chargebee 3.20.0 → 3.21.1
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/CHANGELOG.md +14 -0
- package/README.md +304 -23
- package/cjs/chargebee.cjs.js +11 -4
- package/cjs/createChargebee.js +12 -0
- package/cjs/environment.js +1 -1
- package/cjs/resources/webhook/auth.js +53 -0
- package/cjs/resources/webhook/content.js +4 -0
- package/cjs/resources/webhook/errors.js +94 -0
- package/cjs/resources/webhook/eventType.js +11 -1
- package/cjs/resources/webhook/handler.js +483 -0
- package/esm/chargebee.esm.js +4 -2
- package/esm/createChargebee.js +12 -0
- package/esm/environment.js +1 -1
- package/esm/resources/webhook/auth.js +49 -0
- package/esm/resources/webhook/content.js +2 -0
- package/esm/resources/webhook/errors.js +87 -0
- package/esm/resources/webhook/eventType.js +11 -1
- package/esm/resources/webhook/handler.js +472 -0
- package/package.json +11 -6
- package/types/index.d.ts +190 -0
- package/types/resources/WebhookEvent.d.ts +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
### v3.21.1 (2026-02-20)
|
|
2
|
+
* * *
|
|
3
|
+
|
|
4
|
+
### Core Changes:
|
|
5
|
+
|
|
6
|
+
- Added new core utility method.
|
|
7
|
+
|
|
8
|
+
### v3.21.0 (2026-02-11)
|
|
9
|
+
* * *
|
|
10
|
+
|
|
11
|
+
### 🚀 New Feature
|
|
12
|
+
|
|
13
|
+
* Added webhook handler support. Refer to the [README.md](https://github.com/chargebee/chargebee-node/blob/master/README.md#handle-webhooks) for more details.
|
|
14
|
+
|
|
1
15
|
### v3.20.0 (2026-02-06)
|
|
2
16
|
* * *
|
|
3
17
|
### New Attributes:
|
package/README.md
CHANGED
|
@@ -20,6 +20,16 @@ If you're upgrading from an older version of [`chargebee-typescript`](https://ww
|
|
|
20
20
|
|
|
21
21
|
Node.js 18 or higher.
|
|
22
22
|
|
|
23
|
+
## Runtime Support
|
|
24
|
+
|
|
25
|
+
This SDK supports multiple JavaScript runtimes:
|
|
26
|
+
|
|
27
|
+
- **Node.js** 18+
|
|
28
|
+
- **Deno**
|
|
29
|
+
- **Bun**
|
|
30
|
+
- **Cloudflare Workers**
|
|
31
|
+
- **Edge Runtimes** (e.g., Vercel Edge, Netlify Edge Functions)
|
|
32
|
+
|
|
23
33
|
## Installation
|
|
24
34
|
|
|
25
35
|
Install the library with npm:
|
|
@@ -37,6 +47,16 @@ With yarn:
|
|
|
37
47
|
yarn add chargebee
|
|
38
48
|
```
|
|
39
49
|
|
|
50
|
+
With bun:
|
|
51
|
+
```sh
|
|
52
|
+
bun add chargebee
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
With deno:
|
|
56
|
+
```sh
|
|
57
|
+
deno add npm:chargebee
|
|
58
|
+
```
|
|
59
|
+
|
|
40
60
|
## Usage
|
|
41
61
|
|
|
42
62
|
The package needs to be configured with your site's API key, which is available under Configure Chargebee Section. Refer [here](https://www.chargebee.com/docs/2.0/api_keys.html) for more details.
|
|
@@ -63,6 +83,34 @@ const chargebee = new Chargebee({
|
|
|
63
83
|
});
|
|
64
84
|
```
|
|
65
85
|
|
|
86
|
+
### Using Deno:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import Chargebee from "npm:chargebee";
|
|
90
|
+
|
|
91
|
+
const chargebee = new Chargebee({
|
|
92
|
+
site: "{{site}}",
|
|
93
|
+
apiKey: "{{api-key}}",
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
const response = await chargebee.customer.list();
|
|
97
|
+
console.log(response);
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Using Bun:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
import Chargebee from "chargebee";
|
|
104
|
+
|
|
105
|
+
const chargebee = new Chargebee({
|
|
106
|
+
site: "{{site}}",
|
|
107
|
+
apiKey: "{{api-key}}",
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const response = await chargebee.customer.list();
|
|
111
|
+
console.log(response);
|
|
112
|
+
```
|
|
113
|
+
|
|
66
114
|
### Using Async / Await
|
|
67
115
|
|
|
68
116
|
```typescript
|
|
@@ -148,6 +196,259 @@ const chargebeeSiteEU = new Chargebee({
|
|
|
148
196
|
});
|
|
149
197
|
```
|
|
150
198
|
|
|
199
|
+
### Handle webhooks
|
|
200
|
+
|
|
201
|
+
Use the webhook handlers to parse and route webhook payloads from Chargebee with full TypeScript support.
|
|
202
|
+
|
|
203
|
+
#### Quick Start: Using the instance `webhooks` handler
|
|
204
|
+
|
|
205
|
+
The simplest way to handle webhooks is using the `webhooks` property on your initialized Chargebee client:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import express from 'express';
|
|
209
|
+
import Chargebee, {
|
|
210
|
+
WebhookEventType,
|
|
211
|
+
AuthenticationError,
|
|
212
|
+
PayloadValidationError,
|
|
213
|
+
PayloadParseError,
|
|
214
|
+
} from 'chargebee';
|
|
215
|
+
|
|
216
|
+
const chargebee = new Chargebee({
|
|
217
|
+
site: '{{site}}',
|
|
218
|
+
apiKey: '{{api-key}}',
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const app = express();
|
|
222
|
+
app.use(express.json());
|
|
223
|
+
|
|
224
|
+
// ⚠️ Register listeners once at startup, not inside request handlers
|
|
225
|
+
chargebee.webhooks.on(WebhookEventType.SubscriptionCreated, async ({ event, response }) => {
|
|
226
|
+
console.log(`Subscription created: ${event.id}`);
|
|
227
|
+
const subscription = event.content.subscription;
|
|
228
|
+
console.log(`Customer: ${subscription.customer_id}`);
|
|
229
|
+
response?.status(200).send('OK');
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
chargebee.webhooks.on('error', (error, { response }) => {
|
|
233
|
+
if (error instanceof AuthenticationError) {
|
|
234
|
+
response?.status(401).send('Unauthorized');
|
|
235
|
+
} else if (error instanceof PayloadValidationError || error instanceof PayloadParseError) {
|
|
236
|
+
response?.status(400).send('Bad Request');
|
|
237
|
+
} else {
|
|
238
|
+
console.error('Webhook error:', error.message);
|
|
239
|
+
response?.status(500).send('Internal Server Error');
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
app.post('/chargebee/webhooks', async (req, res) => {
|
|
244
|
+
await chargebee.webhooks.handle({
|
|
245
|
+
body: req.body,
|
|
246
|
+
headers: req.headers,
|
|
247
|
+
request: req,
|
|
248
|
+
response: res,
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
app.listen(8080);
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
**Auto-configured Basic Auth:** The `webhooks` handler automatically configures Basic Auth validation if the following environment variables are set:
|
|
256
|
+
|
|
257
|
+
- `CHARGEBEE_WEBHOOK_USERNAME` - The expected username
|
|
258
|
+
- `CHARGEBEE_WEBHOOK_PASSWORD` - The expected password
|
|
259
|
+
|
|
260
|
+
When both are present, incoming webhook requests will be validated against these credentials.
|
|
261
|
+
|
|
262
|
+
#### Creating typed webhook handlers
|
|
263
|
+
|
|
264
|
+
For more control or multiple webhook endpoints, use `chargebee.webhooks.createHandler()`:
|
|
265
|
+
|
|
266
|
+
```typescript
|
|
267
|
+
import express, { Request, Response } from 'express';
|
|
268
|
+
import Chargebee, {
|
|
269
|
+
WebhookEventType,
|
|
270
|
+
basicAuthValidator,
|
|
271
|
+
AuthenticationError,
|
|
272
|
+
PayloadValidationError,
|
|
273
|
+
PayloadParseError,
|
|
274
|
+
} from 'chargebee';
|
|
275
|
+
|
|
276
|
+
const chargebee = new Chargebee({
|
|
277
|
+
site: '{{site}}',
|
|
278
|
+
apiKey: '{{api-key}}',
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
const app = express();
|
|
282
|
+
app.use(express.json());
|
|
283
|
+
|
|
284
|
+
// Create a typed handler for Express
|
|
285
|
+
const handler = chargebee.webhooks.createHandler<Request, Response>();
|
|
286
|
+
|
|
287
|
+
// Optional: Add request validator (e.g., Basic Auth)
|
|
288
|
+
handler.requestValidator = basicAuthValidator((username, password) => {
|
|
289
|
+
return username === 'admin' && password === 'secret';
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
// ⚠️ Register event listeners once at startup, not inside request handlers
|
|
293
|
+
handler.on(WebhookEventType.SubscriptionCreated, async ({ event, response }) => {
|
|
294
|
+
console.log(`Subscription created: ${event.id}`);
|
|
295
|
+
const subscription = event.content.subscription;
|
|
296
|
+
console.log(`Customer: ${subscription.customer_id}`);
|
|
297
|
+
console.log(`Plan: ${subscription.plan_id}`);
|
|
298
|
+
response?.status(200).send('OK');
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
handler.on(WebhookEventType.PaymentSucceeded, async ({ event, response }) => {
|
|
302
|
+
console.log(`Payment succeeded: ${event.id}`);
|
|
303
|
+
const transaction = event.content.transaction;
|
|
304
|
+
const customer = event.content.customer;
|
|
305
|
+
console.log(`Amount: ${transaction.amount}, Customer: ${customer.email}`);
|
|
306
|
+
response?.status(200).send('OK');
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
handler.on('error', (error, { response }) => {
|
|
310
|
+
if (error instanceof AuthenticationError) {
|
|
311
|
+
response?.status(401).send('Unauthorized');
|
|
312
|
+
} else if (error instanceof PayloadValidationError || error instanceof PayloadParseError) {
|
|
313
|
+
response?.status(400).send('Bad Request');
|
|
314
|
+
} else {
|
|
315
|
+
console.error('Webhook error:', error.message);
|
|
316
|
+
response?.status(500).send('Internal Server Error');
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
app.post('/chargebee/webhooks', async (req, res) => {
|
|
321
|
+
await handler.handle({
|
|
322
|
+
body: req.body,
|
|
323
|
+
headers: req.headers,
|
|
324
|
+
request: req,
|
|
325
|
+
response: res,
|
|
326
|
+
});
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
app.listen(8080);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
#### Low-level: Parse and handle events manually
|
|
333
|
+
|
|
334
|
+
For more control, you can parse webhook events manually:
|
|
335
|
+
|
|
336
|
+
```typescript
|
|
337
|
+
import express from 'express';
|
|
338
|
+
import Chargebee, { type WebhookEvent, WebhookEventType } from 'chargebee';
|
|
339
|
+
|
|
340
|
+
const app = express();
|
|
341
|
+
app.use(express.json());
|
|
342
|
+
|
|
343
|
+
app.post('/chargebee/webhooks', async (req, res) => {
|
|
344
|
+
try {
|
|
345
|
+
const event = req.body as WebhookEvent;
|
|
346
|
+
|
|
347
|
+
switch (event.event_type) {
|
|
348
|
+
case WebhookEventType.SubscriptionCreated: {
|
|
349
|
+
// Cast to specific event type for proper content typing
|
|
350
|
+
const typedEvent = event as WebhookEvent<WebhookEventType.SubscriptionCreated>;
|
|
351
|
+
const subscription = typedEvent.content.subscription;
|
|
352
|
+
console.log('Subscription created:', subscription.id);
|
|
353
|
+
break;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
case WebhookEventType.PaymentSucceeded: {
|
|
357
|
+
const typedEvent = event as WebhookEvent<WebhookEventType.PaymentSucceeded>;
|
|
358
|
+
const transaction = typedEvent.content.transaction;
|
|
359
|
+
console.log('Payment succeeded:', transaction.amount);
|
|
360
|
+
break;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
default:
|
|
364
|
+
console.log('Unhandled event type:', event.event_type);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
res.status(200).send('OK');
|
|
368
|
+
} catch (err) {
|
|
369
|
+
console.error('Error processing webhook:', err);
|
|
370
|
+
res.status(500).send('Error processing webhook');
|
|
371
|
+
}
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
app.listen(8080);
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
#### Responding to Webhooks
|
|
378
|
+
|
|
379
|
+
> ⚠️ **Important:** Always send an HTTP response from your webhook handlers. If you don't respond with a 2xx status, Chargebee will retry the webhook, potentially causing duplicate processing.
|
|
380
|
+
|
|
381
|
+
**Respond with 200** to acknowledge receipt:
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
handler.on(WebhookEventType.SubscriptionCreated, async ({ event, response }) => {
|
|
385
|
+
await provisionAccess(event.content.subscription);
|
|
386
|
+
response?.status(200).json({ received: true });
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Respond with 5xx** so Chargebee retries on failure:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
handler.on(WebhookEventType.PaymentSucceeded, async ({ event, response }) => {
|
|
394
|
+
try {
|
|
395
|
+
await recordPayment(event.content.transaction);
|
|
396
|
+
response?.status(200).send('OK');
|
|
397
|
+
} catch (err) {
|
|
398
|
+
response?.status(500).json({ error: 'Processing failed' });
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
**Access request context** (headers, middleware data):
|
|
404
|
+
|
|
405
|
+
```typescript
|
|
406
|
+
handler.on(WebhookEventType.CustomerCreated, async ({ event, request, response }) => {
|
|
407
|
+
const tenantId = (request as any)?.tenant?.id;
|
|
408
|
+
await createCustomerForTenant(tenantId, event.content.customer);
|
|
409
|
+
response?.status(200).send('OK');
|
|
410
|
+
});
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
#### Handling Unhandled Events and Errors
|
|
414
|
+
|
|
415
|
+
The webhook handler provides specific error classes for different failure scenarios:
|
|
416
|
+
|
|
417
|
+
- **`AuthenticationError`** - Authentication failed (missing/invalid credentials)
|
|
418
|
+
- **`PayloadValidationError`** - Invalid webhook payload structure (missing required fields)
|
|
419
|
+
- **`PayloadParseError`** - Failed to parse JSON body
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
import {
|
|
423
|
+
AuthenticationError,
|
|
424
|
+
PayloadValidationError,
|
|
425
|
+
PayloadParseError,
|
|
426
|
+
} from 'chargebee';
|
|
427
|
+
|
|
428
|
+
// Handle events without registered listeners
|
|
429
|
+
handler.on('unhandled_event', async ({ event, response }) => {
|
|
430
|
+
console.log(`Unhandled: ${event.event_type}`);
|
|
431
|
+
response?.status(200).send('OK');
|
|
432
|
+
});
|
|
433
|
+
|
|
434
|
+
// Handle errors with appropriate HTTP status codes
|
|
435
|
+
handler.on('error', (error, { response }) => {
|
|
436
|
+
if (error instanceof AuthenticationError) {
|
|
437
|
+
console.error('Authentication failed:', error.message);
|
|
438
|
+
response?.status(401).send('Unauthorized');
|
|
439
|
+
} else if (error instanceof PayloadValidationError) {
|
|
440
|
+
console.error('Invalid payload:', error.message);
|
|
441
|
+
response?.status(400).send('Bad Request');
|
|
442
|
+
} else if (error instanceof PayloadParseError) {
|
|
443
|
+
console.error('Failed to parse JSON:', error.message);
|
|
444
|
+
response?.status(400).send('Bad Request');
|
|
445
|
+
} else {
|
|
446
|
+
console.error('Unknown error:', error.message);
|
|
447
|
+
response?.status(500).send('Internal Server Error');
|
|
448
|
+
}
|
|
449
|
+
});
|
|
450
|
+
```
|
|
451
|
+
|
|
151
452
|
### Processing Webhooks - API Version Check
|
|
152
453
|
|
|
153
454
|
An attribute `api_version` is added to the [Event](https://apidocs.chargebee.com/docs/api/events) resource, which indicates the API version based on which the event content is structured. In your webhook servers, ensure this `api_version` is the same as the [API version](https://apidocs.chargebee.com/docs/api#versions) used by your webhook server's client library.
|
|
@@ -227,35 +528,15 @@ To improve type safety and gain better autocompletion when working with webhooks
|
|
|
227
528
|
import Chargebee, { WebhookEventType, WebhookEvent } from "chargebee";
|
|
228
529
|
|
|
229
530
|
const result = await chargebeeInstance.event.retrieve("{event-id}");
|
|
230
|
-
const subscriptionActivatedEvent: WebhookEvent<
|
|
531
|
+
const subscriptionActivatedEvent: WebhookEvent<WebhookEventType.SubscriptionActivated> = result.event;
|
|
231
532
|
const subscription = subscriptionActivatedEvent.content.subscription;
|
|
232
533
|
```
|
|
233
534
|
|
|
234
|
-
You can also use `WebhookEventType` in switch statements for runtime event handling:
|
|
235
|
-
|
|
236
|
-
```ts
|
|
237
|
-
import { WebhookEventType, WebhookEvent } from "chargebee";
|
|
238
|
-
|
|
239
|
-
function handleWebhook(event: WebhookEvent) {
|
|
240
|
-
switch (event.event_type) {
|
|
241
|
-
case WebhookEventType.SubscriptionCreated:
|
|
242
|
-
console.log("Subscription created:", event.content.subscription?.id);
|
|
243
|
-
break;
|
|
244
|
-
case WebhookEventType.PaymentSucceeded:
|
|
245
|
-
console.log("Payment succeeded:", event.content.transaction?.id);
|
|
246
|
-
break;
|
|
247
|
-
default:
|
|
248
|
-
console.log("Unhandled event:", event.event_type);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
535
|
#### Notes
|
|
254
536
|
|
|
255
537
|
* `WebhookEvent<T>` provides type hinting for the event payload, making it easier to work with specific event structures.
|
|
256
|
-
* Use `WebhookEventType` to specify the exact event type (e.g., `SubscriptionCreated`, `InvoiceGenerated`, etc.).
|
|
257
|
-
*
|
|
258
|
-
* `WebhookContentType` is deprecated but still available for backward compatibility.
|
|
538
|
+
* Use the `WebhookEventType` to specify the exact event type (e.g., `SubscriptionCreated`, `InvoiceGenerated`, etc.).
|
|
539
|
+
* This approach ensures you get proper IntelliSense and compile-time checks when accessing event fields.
|
|
259
540
|
|
|
260
541
|
### Custom HTTP Client
|
|
261
542
|
|
package/cjs/chargebee.cjs.js
CHANGED
|
@@ -2,12 +2,19 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const createChargebee_js_1 = require("./createChargebee.js");
|
|
4
4
|
const FetchClient_js_1 = require("./net/FetchClient.js");
|
|
5
|
-
const
|
|
5
|
+
const handler_js_1 = require("./resources/webhook/handler.js");
|
|
6
|
+
const auth_js_1 = require("./resources/webhook/auth.js");
|
|
6
7
|
const httpClient = new FetchClient_js_1.FetchHttpClient();
|
|
7
8
|
const Chargebee = (0, createChargebee_js_1.CreateChargebee)(httpClient);
|
|
8
9
|
module.exports = Chargebee;
|
|
9
10
|
module.exports.Chargebee = Chargebee;
|
|
10
11
|
module.exports.default = Chargebee;
|
|
11
|
-
// Export webhook
|
|
12
|
-
module.exports.WebhookEventType =
|
|
13
|
-
module.exports.WebhookContentType =
|
|
12
|
+
// Export webhook utilities
|
|
13
|
+
module.exports.WebhookEventType = handler_js_1.WebhookEventType;
|
|
14
|
+
module.exports.WebhookContentType = handler_js_1.WebhookContentType;
|
|
15
|
+
module.exports.basicAuthValidator = auth_js_1.basicAuthValidator;
|
|
16
|
+
// Export webhook error classes
|
|
17
|
+
module.exports.WebhookError = handler_js_1.WebhookError;
|
|
18
|
+
module.exports.WebhookAuthenticationError = handler_js_1.WebhookAuthenticationError;
|
|
19
|
+
module.exports.WebhookPayloadValidationError = handler_js_1.WebhookPayloadValidationError;
|
|
20
|
+
module.exports.WebhookPayloadParseError = handler_js_1.WebhookPayloadParseError;
|
package/cjs/createChargebee.js
CHANGED
|
@@ -6,6 +6,7 @@ const environment_js_1 = require("./environment.js");
|
|
|
6
6
|
const api_endpoints_js_1 = require("./resources/api_endpoints.js");
|
|
7
7
|
const util_js_1 = require("./util.js");
|
|
8
8
|
const asyncApiSupport_js_1 = require("./asyncApiSupport.js");
|
|
9
|
+
const handler_js_1 = require("./resources/webhook/handler.js");
|
|
9
10
|
const CreateChargebee = (httpClient) => {
|
|
10
11
|
const Chargebee = function (conf) {
|
|
11
12
|
this._env = Object.assign({}, environment_js_1.Environment);
|
|
@@ -15,6 +16,17 @@ const CreateChargebee = (httpClient) => {
|
|
|
15
16
|
conf.httpClient != null ? conf.httpClient : httpClient;
|
|
16
17
|
this._buildResources();
|
|
17
18
|
this._endpoints = api_endpoints_js_1.Endpoints;
|
|
19
|
+
// Initialize webhooks handler with auto-configured Basic Auth (if env vars are set)
|
|
20
|
+
const handler = (0, handler_js_1.createDefaultHandler)();
|
|
21
|
+
this.__clientIdentifier = (serviceName) => {
|
|
22
|
+
(0, util_js_1.extend)(true, this._env, { userAgentSuffix: serviceName });
|
|
23
|
+
};
|
|
24
|
+
// Create webhooks namespace with handler methods + createHandler factory
|
|
25
|
+
this.webhooks = Object.assign(handler, {
|
|
26
|
+
createHandler(options) {
|
|
27
|
+
return new handler_js_1.WebhookHandler(options);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
18
30
|
};
|
|
19
31
|
Chargebee.prototype = {
|
|
20
32
|
_createApiFunc(apiCall, env) {
|
package/cjs/environment.js
CHANGED
|
@@ -11,7 +11,7 @@ exports.Environment = {
|
|
|
11
11
|
hostSuffix: '.chargebee.com',
|
|
12
12
|
apiPath: '/api/v2',
|
|
13
13
|
timeout: DEFAULT_TIME_OUT,
|
|
14
|
-
clientVersion: 'v3.
|
|
14
|
+
clientVersion: 'v3.21.1',
|
|
15
15
|
port: DEFAULT_PORT,
|
|
16
16
|
timemachineWaitInMillis: DEFAULT_TIME_MACHINE_WAIT,
|
|
17
17
|
exportWaitInMillis: DEFAULT_EXPORT_WAIT,
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.basicAuthValidator = void 0;
|
|
4
|
+
const errors_js_1 = require("./errors.js");
|
|
5
|
+
/**
|
|
6
|
+
* Creates a Basic Auth validator for webhook requests.
|
|
7
|
+
* Parses the Authorization header and validates credentials.
|
|
8
|
+
*
|
|
9
|
+
* @param validateCredentials - Function to validate username/password.
|
|
10
|
+
* Can be sync or async (e.g., for database lookups).
|
|
11
|
+
* @returns A request validator function for use with WebhookHandler
|
|
12
|
+
*
|
|
13
|
+
* @throws {WebhookAuthenticationError} When authentication fails
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Simple sync validation
|
|
17
|
+
* const validator = basicAuthValidator((u, p) => u === 'admin' && p === 'secret');
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Async validation (e.g., database lookup)
|
|
21
|
+
* const validator = basicAuthValidator(async (u, p) => {
|
|
22
|
+
* const user = await db.findUser(u);
|
|
23
|
+
* return user && await bcrypt.compare(p, user.passwordHash);
|
|
24
|
+
* });
|
|
25
|
+
*/
|
|
26
|
+
const basicAuthValidator = (validateCredentials) => {
|
|
27
|
+
return async (headers) => {
|
|
28
|
+
const authHeader = headers['authorization'] || headers['Authorization'];
|
|
29
|
+
if (!authHeader) {
|
|
30
|
+
throw new errors_js_1.WebhookAuthenticationError('Missing authorization header');
|
|
31
|
+
}
|
|
32
|
+
const authStr = Array.isArray(authHeader) ? authHeader[0] : authHeader;
|
|
33
|
+
if (!authStr) {
|
|
34
|
+
throw new errors_js_1.WebhookAuthenticationError('Invalid authorization header');
|
|
35
|
+
}
|
|
36
|
+
const parts = authStr.split(' ');
|
|
37
|
+
if (parts.length !== 2 || parts[0] !== 'Basic') {
|
|
38
|
+
throw new errors_js_1.WebhookAuthenticationError('Invalid authorization header format');
|
|
39
|
+
}
|
|
40
|
+
const decoded = Buffer.from(parts[1], 'base64').toString();
|
|
41
|
+
const separatorIndex = decoded.indexOf(':');
|
|
42
|
+
if (separatorIndex === -1) {
|
|
43
|
+
throw new errors_js_1.WebhookAuthenticationError('Invalid credentials format');
|
|
44
|
+
}
|
|
45
|
+
const username = decoded.substring(0, separatorIndex);
|
|
46
|
+
const password = decoded.substring(separatorIndex + 1);
|
|
47
|
+
const isValid = await validateCredentials(username, password);
|
|
48
|
+
if (!isValid) {
|
|
49
|
+
throw new errors_js_1.WebhookAuthenticationError('Invalid credentials');
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
};
|
|
53
|
+
exports.basicAuthValidator = basicAuthValidator;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.WebhookPayloadParseError = exports.WebhookPayloadValidationError = exports.WebhookAuthenticationError = exports.WebhookError = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Base class for all webhook-related errors.
|
|
6
|
+
* Extends the standard Error class with proper stack trace support.
|
|
7
|
+
*/
|
|
8
|
+
class WebhookError extends Error {
|
|
9
|
+
constructor(message) {
|
|
10
|
+
var _a;
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = 'WebhookError';
|
|
13
|
+
// Maintains proper stack trace for where error was thrown (V8 only)
|
|
14
|
+
(_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
exports.WebhookError = WebhookError;
|
|
18
|
+
/**
|
|
19
|
+
* Authentication error thrown when webhook request authentication fails.
|
|
20
|
+
*
|
|
21
|
+
* Common scenarios:
|
|
22
|
+
* - Missing authorization header
|
|
23
|
+
* - Invalid authorization header format
|
|
24
|
+
* - Invalid credentials
|
|
25
|
+
*
|
|
26
|
+
* Typically maps to HTTP 401 Unauthorized.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* handler.on('error', (error, { response }) => {
|
|
31
|
+
* if (error instanceof WebhookAuthenticationError) {
|
|
32
|
+
* response?.status(401).json({ error: 'Unauthorized' });
|
|
33
|
+
* }
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
class WebhookAuthenticationError extends WebhookError {
|
|
38
|
+
constructor(message) {
|
|
39
|
+
super(message);
|
|
40
|
+
this.name = 'WebhookAuthenticationError';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.WebhookAuthenticationError = WebhookAuthenticationError;
|
|
44
|
+
/**
|
|
45
|
+
* Payload validation error thrown when the webhook payload structure is invalid.
|
|
46
|
+
*
|
|
47
|
+
* Common scenarios:
|
|
48
|
+
* - Missing required fields (event_type, id)
|
|
49
|
+
* - Invalid field types
|
|
50
|
+
* - Malformed payload structure
|
|
51
|
+
*
|
|
52
|
+
* Typically maps to HTTP 400 Bad Request.
|
|
53
|
+
*
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* handler.on('error', (error, { response }) => {
|
|
57
|
+
* if (error instanceof WebhookPayloadValidationError) {
|
|
58
|
+
* response?.status(400).json({ error: 'Bad Request', message: error.message });
|
|
59
|
+
* }
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
class WebhookPayloadValidationError extends WebhookError {
|
|
64
|
+
constructor(message) {
|
|
65
|
+
super(message);
|
|
66
|
+
this.name = 'WebhookPayloadValidationError';
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.WebhookPayloadValidationError = WebhookPayloadValidationError;
|
|
70
|
+
/**
|
|
71
|
+
* JSON parsing error thrown when the webhook body cannot be parsed as JSON.
|
|
72
|
+
*
|
|
73
|
+
* Includes the raw body that failed to parse (if available) for debugging.
|
|
74
|
+
*
|
|
75
|
+
* Typically maps to HTTP 400 Bad Request.
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```typescript
|
|
79
|
+
* handler.on('error', (error, { response }) => {
|
|
80
|
+
* if (error instanceof WebhookPayloadParseError) {
|
|
81
|
+
* console.error('Failed to parse:', error.rawBody);
|
|
82
|
+
* response?.status(400).json({ error: 'Invalid JSON' });
|
|
83
|
+
* }
|
|
84
|
+
* });
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
class WebhookPayloadParseError extends WebhookError {
|
|
88
|
+
constructor(message, rawBody) {
|
|
89
|
+
super(message);
|
|
90
|
+
this.rawBody = rawBody;
|
|
91
|
+
this.name = 'WebhookPayloadParseError';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
exports.WebhookPayloadParseError = WebhookPayloadParseError;
|
|
@@ -234,6 +234,16 @@ var WebhookEventType;
|
|
|
234
234
|
WebhookEventType["VoucherExpired"] = "voucher_expired";
|
|
235
235
|
})(WebhookEventType || (exports.WebhookEventType = WebhookEventType = {}));
|
|
236
236
|
/**
|
|
237
|
-
* @deprecated Use WebhookEventType instead.
|
|
237
|
+
* @deprecated Renamed to `WebhookEventType` for clarity. Use `WebhookEventType` instead.
|
|
238
|
+
* This alias will be removed in the next major version.
|
|
239
|
+
*
|
|
240
|
+
* @example
|
|
241
|
+
* // Before (deprecated)
|
|
242
|
+
* import { WebhookContentType } from 'chargebee';
|
|
243
|
+
* if (event.event_type === WebhookContentType.SubscriptionCreated) { ... }
|
|
244
|
+
*
|
|
245
|
+
* // After (recommended)
|
|
246
|
+
* import { WebhookEventType } from 'chargebee';
|
|
247
|
+
* if (event.event_type === WebhookEventType.SubscriptionCreated) { ... }
|
|
238
248
|
*/
|
|
239
249
|
exports.WebhookContentType = WebhookEventType;
|