chargebee 3.26.0 → 3.28.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.
Files changed (172) hide show
  1. package/CHANGELOG.md +14 -1
  2. package/README.md +131 -0
  3. package/cjs/RequestWrapper.js +130 -12
  4. package/cjs/chargebee.cjs.js +5 -0
  5. package/cjs/chargebee.cjs.worker.js +2 -0
  6. package/cjs/chargebeeZodValidationError.js +18 -0
  7. package/cjs/createChargebee.js +23 -2
  8. package/cjs/environment.js +1 -1
  9. package/cjs/schema/addon.schema.js +269 -0
  10. package/cjs/schema/address.schema.js +35 -0
  11. package/cjs/schema/alert.schema.js +74 -0
  12. package/cjs/schema/alert_status.schema.js +31 -0
  13. package/cjs/schema/attached_item.schema.js +144 -0
  14. package/cjs/schema/business_entity.schema.js +46 -0
  15. package/cjs/schema/card.schema.js +165 -0
  16. package/cjs/schema/comment.schema.js +69 -0
  17. package/cjs/schema/coupon.schema.js +323 -0
  18. package/cjs/schema/coupon_code.schema.js +49 -0
  19. package/cjs/schema/coupon_set.schema.js +88 -0
  20. package/cjs/schema/credit_note.schema.js +502 -0
  21. package/cjs/schema/currency.schema.js +32 -0
  22. package/cjs/schema/customer.schema.js +1201 -0
  23. package/cjs/schema/customer_entitlement.schema.js +14 -0
  24. package/cjs/schema/differential_price.schema.js +106 -0
  25. package/cjs/schema/entitlement.schema.js +54 -0
  26. package/cjs/schema/entitlement_override.schema.js +35 -0
  27. package/cjs/schema/estimate.schema.js +1535 -0
  28. package/cjs/schema/event.schema.js +1060 -0
  29. package/cjs/schema/export.schema.js +3385 -0
  30. package/cjs/schema/feature.schema.js +78 -0
  31. package/cjs/schema/gift.schema.js +293 -0
  32. package/cjs/schema/grant_block.schema.js +47 -0
  33. package/cjs/schema/hosted_page.schema.js +1777 -0
  34. package/cjs/schema/in_app_subscription.schema.js +68 -0
  35. package/cjs/schema/index.js +88 -0
  36. package/cjs/schema/invoice.schema.js +1685 -0
  37. package/cjs/schema/item.schema.js +195 -0
  38. package/cjs/schema/item_entitlement.schema.js +45 -0
  39. package/cjs/schema/item_family.schema.js +57 -0
  40. package/cjs/schema/item_price.schema.js +335 -0
  41. package/cjs/schema/ledger_account_balance.schema.js +21 -0
  42. package/cjs/schema/ledger_operation.schema.js +104 -0
  43. package/cjs/schema/meter.schema.js +13 -0
  44. package/cjs/schema/metered_feature.schema.js +20 -0
  45. package/cjs/schema/non_subscription.schema.js +28 -0
  46. package/cjs/schema/offer_event.schema.js +13 -0
  47. package/cjs/schema/offer_fulfillment.schema.js +20 -0
  48. package/cjs/schema/omnichannel_one_time_order.schema.js +26 -0
  49. package/cjs/schema/omnichannel_subscription.schema.js +122 -0
  50. package/cjs/schema/omnichannel_subscription_item.schema.js +13 -0
  51. package/cjs/schema/order.schema.js +441 -0
  52. package/cjs/schema/payment_intent.schema.js +127 -0
  53. package/cjs/schema/payment_schedule_scheme.schema.js +20 -0
  54. package/cjs/schema/payment_source.schema.js +630 -0
  55. package/cjs/schema/payment_voucher.schema.js +57 -0
  56. package/cjs/schema/personalized_offer.schema.js +28 -0
  57. package/cjs/schema/plan.schema.js +363 -0
  58. package/cjs/schema/portal_session.schema.js +22 -0
  59. package/cjs/schema/price_variant.schema.js +93 -0
  60. package/cjs/schema/pricing_page_session.schema.js +135 -0
  61. package/cjs/schema/promotional_credit.schema.js +78 -0
  62. package/cjs/schema/promotional_grant.schema.js +17 -0
  63. package/cjs/schema/purchase.schema.js +277 -0
  64. package/cjs/schema/quote.schema.js +1667 -0
  65. package/cjs/schema/ramp.schema.js +245 -0
  66. package/cjs/schema/recorded_purchase.schema.js +32 -0
  67. package/cjs/schema/resource_migration.schema.js +14 -0
  68. package/cjs/schema/site_migration_detail.schema.js +81 -0
  69. package/cjs/schema/subscription.schema.js +3344 -0
  70. package/cjs/schema/subscription_entitlement.schema.js +25 -0
  71. package/cjs/schema/time_machine.schema.js +17 -0
  72. package/cjs/schema/transaction.schema.js +744 -0
  73. package/cjs/schema/unbilled_charge.schema.js +139 -0
  74. package/cjs/schema/usage.schema.js +93 -0
  75. package/cjs/schema/usage_charge.schema.js +17 -0
  76. package/cjs/schema/usage_event.schema.js +28 -0
  77. package/cjs/schema/usage_file.schema.js +13 -0
  78. package/cjs/schema/usage_summary.schema.js +17 -0
  79. package/cjs/schema/virtual_bank_account.schema.js +71 -0
  80. package/cjs/schema/webhook_endpoint.schema.js +508 -0
  81. package/cjs/telemetry/TelemetryAdapter.js +145 -0
  82. package/cjs/telemetry/index.js +28 -0
  83. package/cjs/telemetry/otel.js +66 -0
  84. package/cjs/telemetry/types.js +47 -0
  85. package/cjs/validationLoader.js +59 -0
  86. package/esm/RequestWrapper.js +130 -12
  87. package/esm/chargebee.esm.js +3 -0
  88. package/esm/chargebee.esm.worker.js +1 -0
  89. package/esm/chargebeeZodValidationError.js +14 -0
  90. package/esm/createChargebee.js +23 -2
  91. package/esm/environment.js +1 -1
  92. package/esm/schema/addon.schema.js +266 -0
  93. package/esm/schema/address.schema.js +32 -0
  94. package/esm/schema/alert.schema.js +71 -0
  95. package/esm/schema/alert_status.schema.js +28 -0
  96. package/esm/schema/attached_item.schema.js +141 -0
  97. package/esm/schema/business_entity.schema.js +43 -0
  98. package/esm/schema/card.schema.js +162 -0
  99. package/esm/schema/comment.schema.js +66 -0
  100. package/esm/schema/coupon.schema.js +320 -0
  101. package/esm/schema/coupon_code.schema.js +46 -0
  102. package/esm/schema/coupon_set.schema.js +85 -0
  103. package/esm/schema/credit_note.schema.js +499 -0
  104. package/esm/schema/currency.schema.js +29 -0
  105. package/esm/schema/customer.schema.js +1198 -0
  106. package/esm/schema/customer_entitlement.schema.js +11 -0
  107. package/esm/schema/differential_price.schema.js +103 -0
  108. package/esm/schema/entitlement.schema.js +51 -0
  109. package/esm/schema/entitlement_override.schema.js +32 -0
  110. package/esm/schema/estimate.schema.js +1532 -0
  111. package/esm/schema/event.schema.js +1057 -0
  112. package/esm/schema/export.schema.js +3382 -0
  113. package/esm/schema/feature.schema.js +75 -0
  114. package/esm/schema/gift.schema.js +290 -0
  115. package/esm/schema/grant_block.schema.js +44 -0
  116. package/esm/schema/hosted_page.schema.js +1774 -0
  117. package/esm/schema/in_app_subscription.schema.js +65 -0
  118. package/esm/schema/index.js +72 -0
  119. package/esm/schema/invoice.schema.js +1682 -0
  120. package/esm/schema/item.schema.js +192 -0
  121. package/esm/schema/item_entitlement.schema.js +42 -0
  122. package/esm/schema/item_family.schema.js +54 -0
  123. package/esm/schema/item_price.schema.js +332 -0
  124. package/esm/schema/ledger_account_balance.schema.js +18 -0
  125. package/esm/schema/ledger_operation.schema.js +101 -0
  126. package/esm/schema/meter.schema.js +10 -0
  127. package/esm/schema/metered_feature.schema.js +17 -0
  128. package/esm/schema/non_subscription.schema.js +25 -0
  129. package/esm/schema/offer_event.schema.js +10 -0
  130. package/esm/schema/offer_fulfillment.schema.js +17 -0
  131. package/esm/schema/omnichannel_one_time_order.schema.js +23 -0
  132. package/esm/schema/omnichannel_subscription.schema.js +119 -0
  133. package/esm/schema/omnichannel_subscription_item.schema.js +10 -0
  134. package/esm/schema/order.schema.js +438 -0
  135. package/esm/schema/payment_intent.schema.js +124 -0
  136. package/esm/schema/payment_schedule_scheme.schema.js +17 -0
  137. package/esm/schema/payment_source.schema.js +627 -0
  138. package/esm/schema/payment_voucher.schema.js +54 -0
  139. package/esm/schema/personalized_offer.schema.js +25 -0
  140. package/esm/schema/plan.schema.js +360 -0
  141. package/esm/schema/portal_session.schema.js +19 -0
  142. package/esm/schema/price_variant.schema.js +90 -0
  143. package/esm/schema/pricing_page_session.schema.js +132 -0
  144. package/esm/schema/promotional_credit.schema.js +75 -0
  145. package/esm/schema/promotional_grant.schema.js +14 -0
  146. package/esm/schema/purchase.schema.js +274 -0
  147. package/esm/schema/quote.schema.js +1664 -0
  148. package/esm/schema/ramp.schema.js +242 -0
  149. package/esm/schema/recorded_purchase.schema.js +29 -0
  150. package/esm/schema/resource_migration.schema.js +11 -0
  151. package/esm/schema/site_migration_detail.schema.js +78 -0
  152. package/esm/schema/subscription.schema.js +3341 -0
  153. package/esm/schema/subscription_entitlement.schema.js +22 -0
  154. package/esm/schema/time_machine.schema.js +14 -0
  155. package/esm/schema/transaction.schema.js +741 -0
  156. package/esm/schema/unbilled_charge.schema.js +136 -0
  157. package/esm/schema/usage.schema.js +90 -0
  158. package/esm/schema/usage_charge.schema.js +14 -0
  159. package/esm/schema/usage_event.schema.js +25 -0
  160. package/esm/schema/usage_file.schema.js +10 -0
  161. package/esm/schema/usage_summary.schema.js +14 -0
  162. package/esm/schema/virtual_bank_account.schema.js +68 -0
  163. package/esm/schema/webhook_endpoint.schema.js +505 -0
  164. package/esm/telemetry/TelemetryAdapter.js +132 -0
  165. package/esm/telemetry/index.js +8 -0
  166. package/esm/telemetry/otel.js +62 -0
  167. package/esm/telemetry/types.js +44 -0
  168. package/esm/validationLoader.js +56 -0
  169. package/package.json +43 -24
  170. package/types/core.d.ts +2 -0
  171. package/types/index.d.ts +85 -0
  172. package/types/telemetry/otel.d.ts +22 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ### v3.28.0 (2026-06-30)
2
+ * * *
3
+
4
+ ### New Features
5
+ * Added an optional `telemetryAdapter` config hook for tracing Chargebee API calls via OpenTelemetry (or any APM). When unconfigured, the SDK skips all telemetry work — no behavior change for existing integrations.
6
+ * Each API call emits one CLIENT span (`chargebee.{resource}.{operation}`) with OpenTelemetry HTTP semantic-convention attributes plus `chargebee.*` attributes, and injects W3C trace context (`traceparent`) into outbound requests for distributed tracing.
7
+ * Exposed `TelemetryAdapter`, `RequestTelemetryContext`, `RequestTelemetryResult`, `RequestTelemetryError`, `RequestTelemetryHandle` types and the `TelemetryAttributeKeys` constant from the CJS and ESM entry points.
8
+ * Added a ready-to-use OpenTelemetry adapter via the `chargebee/telemetry/otel` subpath. `@opentelemetry/api` is an optional peer dependency and is not bundled — install it in your app to use this adapter.
9
+
10
+ ### Enhancements:
11
+ - **Zod-backed request validation** — Set `enableValidation: true` in the client configuration to validate outgoing request parameters against each endpoint's generated Zod schema before the API call is sent. Invalid payloads raise `ChargebeeZodValidationError`, which carries the offending `actionName` and the original `ZodError` (including `issues` and `flatten()`) for inspection.
12
+ - **Runtime dependency** — Added [`zod`](https://www.npmjs.com/package/zod) (v4) as a runtime dependency to support request validation.
13
+
14
+
1
15
  ### v3.26.0 (2026-06-12)
2
16
  * * *
3
17
  ### New Resources:
@@ -34,7 +48,6 @@
34
48
  - `updated_at` and `created_at` have been added as new values to enum query parameter `sort_by.desc` in [`list_omnichannel_subscriptions`](https://apidocs.chargebee.com/docs/api/omnichannel_subscriptions/list-omnichannel-subscriptions) of [`OmnichannelSubscription`](https://apidocs.chargebee.com/docs/api/omnichannel_subscriptions).
35
49
 
36
50
 
37
-
38
51
  ### v3.25.0 (2026-06-08)
39
52
  * * *
40
53
  ### New Attributes:
package/README.md CHANGED
@@ -124,6 +124,45 @@ try {
124
124
  }
125
125
  ```
126
126
 
127
+ ### Request parameter validation (Zod)
128
+
129
+ When `enableValidation` is set to `true`, the SDK validates parameters for **every** API request against Zod schemas **before** the HTTP call is made. If you omit the params object on a call, it is validated as `{}`. This is **off by default**. Schemas are included for API actions that support them; actions without a bundled schema behave as usual.
130
+
131
+ ```typescript
132
+ import Chargebee, { ChargebeeZodValidationError } from 'chargebee';
133
+
134
+ const chargebee = new Chargebee({
135
+ site: '{{site}}',
136
+ apiKey: '{{api-key}}',
137
+ enableValidation: true,
138
+ });
139
+
140
+ try {
141
+ await chargebee.customer.create({
142
+ id: 'a'.repeat(100),
143
+ auto_collection: 'invalid',
144
+ });
145
+ } catch (err) {
146
+ if (err instanceof ChargebeeZodValidationError) {
147
+ console.error(err.message);
148
+ console.error(err.actionName);
149
+ console.error(err.zodError.issues);
150
+ } else {
151
+ throw err;
152
+ }
153
+ }
154
+ ```
155
+
156
+ Invalid parameters produce a `ChargebeeZodValidationError`. The error message lists every problem (field path and message). You can also inspect `actionName` (the API action, for example `create`) and `zodError` (Zod’s `ZodError`, including `issues`) for structured handling.
157
+
158
+ **Example message:**
159
+
160
+ ```text
161
+ ChargebeeZodValidationError: [Chargebee] Validation failed for 'create': id: Too big: expected string to have <=50 characters; auto_collection: Invalid option: expected one of "on"|"off"
162
+ ```
163
+
164
+ The same `ChargebeeZodValidationError` shape applies to any action with a schema when parameters are invalid (for example bad filters or limits on `list`).
165
+
127
166
  ### Using filters in the List API
128
167
 
129
168
  For pagination, `offset` is the parameter that is being used. The value used for this parameter must be the value returned for `next_offset` parameter in the previous API call.
@@ -563,6 +602,98 @@ const chargebee = new Chargebee({
563
602
 
564
603
  These examples demonstrate how to implement and inject custom clients using `axios` and `ky`, respectively.
565
604
 
605
+ ### Telemetry (OpenTelemetry)
606
+
607
+ Optional. Pass a `telemetryAdapter` when you want Chargebee API calls traced in your observability stack (Datadog, Splunk, Honeycomb, Jaeger, etc.). The SDK ships a ready-to-use OpenTelemetry adapter, so for most setups you only need to add `@opentelemetry/api` and wire the adapter on the client.
608
+
609
+ `@opentelemetry/api` is an **optional peer dependency** — it is not bundled with `chargebee` and is only loaded when you import the adapter, so a plain `import 'chargebee'` stays dependency-free.
610
+
611
+ The SDK builds standardized span attributes (`ctx.startAttributes`, `result.endAttributes`) following the stable [OpenTelemetry HTTP semantic conventions](https://opentelemetry.io/docs/specs/semconv/http/http-spans/) (`url.full`, `http.request.method`, `http.response.status_code`, `server.address`, `error.type`) plus Chargebee-specific `chargebee.*` attributes — use them as-is so spans render correctly in your APM and stay consistent across SDKs.
612
+
613
+ Spans are named `chargebee.{resource}.{operation}` (e.g. `chargebee.subscription.create`).
614
+
615
+ #### Quick start (built-in adapter)
616
+
617
+ ```bash
618
+ npm install chargebee @opentelemetry/api @opentelemetry/sdk-node @opentelemetry/exporter-trace-otlp-http
619
+ ```
620
+
621
+ Configure OpenTelemetry once at app startup. Exporting (endpoint, service name, credentials) is driven entirely by your OpenTelemetry runtime and the standard `OTEL_*` environment variables — the adapter just uses the globally registered tracer:
622
+
623
+ ```typescript
624
+ // instrumentation.ts — node --require ./instrumentation.js app.js
625
+ import { NodeSDK } from '@opentelemetry/sdk-node';
626
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
627
+
628
+ new NodeSDK({
629
+ serviceName: process.env.OTEL_SERVICE_NAME ?? 'billing-service',
630
+ traceExporter: new OTLPTraceExporter({
631
+ url: process.env.OTEL_EXPORTER_OTLP_TRACES_ENDPOINT ?? 'http://localhost:4318/v1/traces',
632
+ }),
633
+ }).start();
634
+ ```
635
+
636
+ Then import the ready-to-use adapter and pass it on client initialization:
637
+
638
+ ```typescript
639
+ import Chargebee from 'chargebee';
640
+ import otelDefaultAdapter from 'chargebee/telemetry/otel';
641
+
642
+ const chargebee = new Chargebee({
643
+ site: '{{site}}',
644
+ apiKey: '{{api-key}}',
645
+ telemetryAdapter: otelDefaultAdapter,
646
+ });
647
+ ```
648
+
649
+ That's it — every SDK call now emits a `chargebee.<resource>.<operation>` CLIENT span that attaches to the active OpenTelemetry context (or starts a root span), with W3C trace context propagated to Chargebee. Spans are exported by your own OpenTelemetry setup, so they flow to whatever backend you've configured (Datadog, Splunk, Honeycomb, Jaeger, etc.) — refer to your APM vendor's OpenTelemetry/OTLP documentation for exporter endpoints.
650
+
651
+ #### Custom adapter (advanced)
652
+
653
+ To customize behavior (different tracer name, extra attributes, a non-OpenTelemetry backend, etc.), implement `TelemetryAdapter` yourself instead of importing the built-in adapter:
654
+
655
+ ```typescript
656
+ import Chargebee, {
657
+ type TelemetryAdapter,
658
+ type RequestTelemetryContext,
659
+ type RequestTelemetryResult,
660
+ } from 'chargebee';
661
+ import { context, propagation, trace, SpanKind, SpanStatusCode, type Span } from '@opentelemetry/api';
662
+
663
+ class OtelTelemetryAdapter implements TelemetryAdapter<Span> {
664
+ private readonly tracer = trace.getTracer('chargebee-node');
665
+
666
+ onRequestStart(ctx: RequestTelemetryContext, requestHeaders: Record<string, string | number>): Span {
667
+ const span = this.tracer.startSpan(ctx.spanName, {
668
+ kind: SpanKind.CLIENT,
669
+ attributes: ctx.startAttributes,
670
+ });
671
+ propagation.inject(trace.setSpan(context.active(), span), requestHeaders);
672
+ return span;
673
+ }
674
+
675
+ onRequestEnd(span: Span | void, result: RequestTelemetryResult) {
676
+ if (!span) return;
677
+ for (const [key, value] of Object.entries(result.endAttributes)) {
678
+ span.setAttribute(key, value);
679
+ }
680
+ if (result.error) {
681
+ span.recordException(new Error(result.error.message));
682
+ span.setStatus({ code: SpanStatusCode.ERROR, message: result.error.message });
683
+ } else {
684
+ span.setStatus({ code: SpanStatusCode.OK });
685
+ }
686
+ span.end();
687
+ }
688
+ }
689
+
690
+ const chargebee = new Chargebee({
691
+ site: '{{site}}',
692
+ apiKey: '{{api-key}}',
693
+ telemetryAdapter: new OtelTelemetryAdapter(),
694
+ });
695
+ ```
696
+
566
697
  ## Feedback
567
698
 
568
699
  If you find any bugs or have any questions / feedback, open an issue in this repository or reach out to us on dx@chargebee.com
@@ -2,8 +2,11 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RequestWrapper = void 0;
4
4
  const util_js_1 = require("./util.js");
5
+ const index_js_1 = require("./telemetry/index.js");
5
6
  const coreCommon_js_1 = require("./coreCommon.js");
6
7
  const node_buffer_1 = require("node:buffer");
8
+ const chargebeeZodValidationError_js_1 = require("./chargebeeZodValidationError.js");
9
+ const validationLoader_js_1 = require("./validationLoader.js");
7
10
  class RequestWrapper {
8
11
  constructor(args, apiCall, envArg) {
9
12
  this.getRequest = () => {
@@ -23,6 +26,17 @@ class RequestWrapper {
23
26
  }
24
27
  return idParam;
25
28
  }
29
+ /**
30
+ * Validate parameters against the action's Zod schema when enableValidation is true.
31
+ * Query params are validated as `params ?? {}`; body params are validated when `params` is non-null.
32
+ * Throws a descriptive error listing every validation violation.
33
+ */
34
+ static _validateParams(params, schema, actionName) {
35
+ const result = schema.safeParse(params);
36
+ if (!result.success) {
37
+ throw new chargebeeZodValidationError_js_1.ChargebeeZodValidationError(actionName, result.error);
38
+ }
39
+ }
26
40
  static parseRetryAfter(retryAfter) {
27
41
  if (!retryAfter)
28
42
  return null;
@@ -32,9 +46,28 @@ class RequestWrapper {
32
46
  }
33
47
  return null;
34
48
  }
49
+ _buildRequestUrl(env, urlIdParam, params) {
50
+ let path = (0, util_js_1.getApiURL)(env, this.apiCall.urlPrefix, this.apiCall.urlSuffix, urlIdParam);
51
+ if (this.apiCall.httpMethod === 'GET') {
52
+ let requestParams = params;
53
+ if (typeof requestParams === 'undefined' || requestParams === null) {
54
+ requestParams = {};
55
+ }
56
+ const queryParam = this.apiCall.isListReq
57
+ ? (0, util_js_1.encodeListParams)((0, util_js_1.serialize)(requestParams))
58
+ : (0, util_js_1.encodeParams)((0, util_js_1.serialize)(requestParams));
59
+ path += '?' + queryParam;
60
+ }
61
+ return new URL(path, `${env.protocol}://${(0, util_js_1.getHost)(env, this.apiCall.subDomain)}${env.port ? `:${env.port}` : ''}`);
62
+ }
35
63
  async request() {
36
64
  let _env = {};
37
65
  (0, util_js_1.extend)(true, _env, this.envArg);
66
+ // Class-based adapters (e.g. OpenTelemetry) keep methods on the prototype;
67
+ // deep extend only copies own enumerable properties, so preserve by reference.
68
+ if (this.envArg.telemetryAdapter !== undefined) {
69
+ _env.telemetryAdapter = this.envArg.telemetryAdapter;
70
+ }
38
71
  const env = _env;
39
72
  const retryConfig = Object.assign({ enabled: false, maxRetries: 3, delayMs: 200, retryOn: [500, 502, 503, 504] }, env.retryConfig);
40
73
  const urlIdParam = this.apiCall.hasIdInUrl ? this.args[0] : null;
@@ -42,6 +75,20 @@ class RequestWrapper {
42
75
  ? this.args[1]
43
76
  : this.args[0];
44
77
  let headers = this.apiCall.hasIdInUrl ? this.args[2] : this.args[1];
78
+ // Lazy-load Zod schema when enableValidation is true
79
+ if (env.enableValidation &&
80
+ this.apiCall.resourceKey &&
81
+ this.apiCall.actionName) {
82
+ const schema = await (0, validationLoader_js_1.getSchema)(this.apiCall.resourceKey, this.apiCall.actionName);
83
+ if (schema) {
84
+ if (this.apiCall.httpMethod === 'GET') {
85
+ RequestWrapper._validateParams(params !== null && params !== void 0 ? params : {}, schema, this.apiCall.methodName);
86
+ }
87
+ else if (params != null) {
88
+ RequestWrapper._validateParams(params, schema, this.apiCall.methodName);
89
+ }
90
+ }
91
+ }
45
92
  Object.assign(this.httpHeaders, headers);
46
93
  if (this.apiCall.httpMethod === 'POST' &&
47
94
  !this.httpHeaders['chargebee-idempotency-key'] &&
@@ -50,19 +97,43 @@ class RequestWrapper {
50
97
  retryConfig.enabled) {
51
98
  this.httpHeaders['chargebee-idempotency-key'] = (0, util_js_1.generateUUIDv4)();
52
99
  }
100
+ const telemetryAdapter = env.telemetryAdapter;
101
+ const telemetryHeaders = {};
102
+ const requestStartTime = Date.now();
103
+ const requestUrl = this._buildRequestUrl(env, urlIdParam, params);
104
+ // No telemetry adapter configured => skip all telemetry work (zero overhead).
105
+ let telemetryHandle;
106
+ if (telemetryAdapter !== undefined) {
107
+ const telemetryContext = (0, index_js_1.buildRequestTelemetryContext)({
108
+ resource: this.apiCall.resource,
109
+ operation: this.apiCall.methodName,
110
+ httpMethod: this.apiCall.httpMethod,
111
+ httpUrl: `${requestUrl.origin}${requestUrl.pathname}`,
112
+ serverAddress: requestUrl.hostname,
113
+ chargebeeSite: env.site,
114
+ chargebeeApiVersion: (0, index_js_1.resolveChargebeeApiVersion)(env.apiPath),
115
+ sdkVersion: env.clientVersion,
116
+ requestHeaders: this.httpHeaders,
117
+ });
118
+ try {
119
+ telemetryHandle = telemetryAdapter.onRequestStart(telemetryContext, telemetryHeaders);
120
+ }
121
+ catch (err) {
122
+ const message = err instanceof Error
123
+ ? err.message
124
+ : 'Unknown telemetry adapter error';
125
+ (0, util_js_1.log)(env, {
126
+ level: 'ERROR',
127
+ message: `Telemetry adapter onRequestStart failed: ${message}. Continuing without telemetry.`,
128
+ });
129
+ telemetryHandle = undefined;
130
+ }
131
+ }
53
132
  const makeRequest = async (attempt = 0) => {
54
- let path = (0, util_js_1.getApiURL)(env, this.apiCall.urlPrefix, this.apiCall.urlSuffix, urlIdParam);
55
133
  let requestParams = params;
56
134
  if (typeof requestParams === 'undefined' || requestParams === null) {
57
135
  requestParams = {};
58
136
  }
59
- if (this.apiCall.httpMethod === 'GET') {
60
- const queryParam = this.apiCall.isListReq
61
- ? (0, util_js_1.encodeListParams)((0, util_js_1.serialize)(requestParams))
62
- : (0, util_js_1.encodeParams)((0, util_js_1.serialize)(requestParams));
63
- path += '?' + queryParam;
64
- requestParams = {};
65
- }
66
137
  const jsonKeys = this.apiCall.jsonKeys;
67
138
  let data = null;
68
139
  if (this.apiCall.httpMethod !== 'GET') {
@@ -70,7 +141,7 @@ class RequestWrapper {
70
141
  ? JSON.stringify(requestParams)
71
142
  : (0, util_js_1.encodeParams)(requestParams, undefined, undefined, undefined, jsonKeys);
72
143
  }
73
- const requestHeaders = Object.assign({}, this.httpHeaders);
144
+ const requestHeaders = Object.assign(Object.assign({}, this.httpHeaders), telemetryHeaders);
74
145
  if (data && data.length) {
75
146
  (0, util_js_1.extend)(true, requestHeaders, {
76
147
  'Content-Length': node_buffer_1.Buffer.byteLength(data, 'utf8'),
@@ -90,8 +161,7 @@ class RequestWrapper {
90
161
  if (attempt > 0) {
91
162
  requestHeaders['X-CB-Retry-Attempt'] = attempt.toString();
92
163
  }
93
- const url = new URL(path, `${env.protocol}://${(0, util_js_1.getHost)(env, this.apiCall.subDomain)}${env.port ? `:${env.port}` : ''}`);
94
- const request = new Request(url, {
164
+ const request = new Request(requestUrl, {
95
165
  method: this.apiCall.httpMethod,
96
166
  body: data || undefined,
97
167
  headers: this._createHeaders(requestHeaders),
@@ -153,7 +223,55 @@ class RequestWrapper {
153
223
  return await withRetry(retryCount + 1, startTime);
154
224
  }
155
225
  };
156
- const promise = withRetry(0, Date.now());
226
+ const runWithTelemetry = async (adapter) => {
227
+ var _a;
228
+ try {
229
+ const result = await withRetry(0, requestStartTime);
230
+ const httpStatusCode = typeof (result === null || result === void 0 ? void 0 : result.httpStatusCode) === 'number'
231
+ ? result.httpStatusCode
232
+ : 200;
233
+ try {
234
+ adapter.onRequestEnd(telemetryHandle, (0, index_js_1.buildRequestTelemetryResult)({
235
+ httpStatusCode,
236
+ durationMs: Date.now() - requestStartTime,
237
+ }));
238
+ }
239
+ catch (err) {
240
+ const message = err instanceof Error
241
+ ? err.message
242
+ : 'Unknown telemetry adapter error';
243
+ (0, util_js_1.log)(env, {
244
+ level: 'ERROR',
245
+ message: `Telemetry adapter onRequestEnd failed: ${message}.`,
246
+ });
247
+ }
248
+ return result;
249
+ }
250
+ catch (err) {
251
+ const httpStatusCode = (_a = (0, index_js_1.extractHttpStatusCode)(err)) !== null && _a !== void 0 ? _a : 500;
252
+ const telemetryError = (0, index_js_1.extractRequestTelemetryError)(err);
253
+ try {
254
+ adapter.onRequestEnd(telemetryHandle, (0, index_js_1.buildRequestTelemetryResult)({
255
+ httpStatusCode,
256
+ durationMs: Date.now() - requestStartTime,
257
+ error: telemetryError,
258
+ }));
259
+ }
260
+ catch (telemetryErr) {
261
+ const message = telemetryErr instanceof Error
262
+ ? telemetryErr.message
263
+ : 'Unknown telemetry adapter error';
264
+ (0, util_js_1.log)(env, {
265
+ level: 'ERROR',
266
+ message: `Telemetry adapter onRequestEnd failed: ${message}.`,
267
+ });
268
+ }
269
+ throw err;
270
+ }
271
+ };
272
+ const promise = telemetryAdapter !== undefined
273
+ ? runWithTelemetry(telemetryAdapter)
274
+ : withRetry(0, requestStartTime);
157
275
  return (0, util_js_1.callbackifyPromise)(promise);
158
276
  }
159
277
  _createHeaders(httpHeaders) {
@@ -4,6 +4,8 @@ const createChargebee_js_1 = require("./createChargebee.js");
4
4
  const FetchClient_js_1 = require("./net/FetchClient.js");
5
5
  const handler_js_1 = require("./resources/webhook/handler.js");
6
6
  const auth_js_1 = require("./resources/webhook/auth.js");
7
+ const index_js_1 = require("./telemetry/index.js");
8
+ const chargebeeZodValidationError_js_1 = require("./chargebeeZodValidationError.js");
7
9
  const httpClient = new FetchClient_js_1.FetchHttpClient();
8
10
  const Chargebee = (0, createChargebee_js_1.CreateChargebee)(httpClient);
9
11
  module.exports = Chargebee;
@@ -18,3 +20,6 @@ module.exports.WebhookError = handler_js_1.WebhookError;
18
20
  module.exports.WebhookAuthenticationError = handler_js_1.WebhookAuthenticationError;
19
21
  module.exports.WebhookPayloadValidationError = handler_js_1.WebhookPayloadValidationError;
20
22
  module.exports.WebhookPayloadParseError = handler_js_1.WebhookPayloadParseError;
23
+ module.exports.TelemetryAttributeKeys = index_js_1.TelemetryAttributeKeys;
24
+ // Export validation error class
25
+ module.exports.ChargebeeZodValidationError = chargebeeZodValidationError_js_1.ChargebeeZodValidationError;
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.WebhookPayloadParseError = exports.WebhookPayloadValidationError = exports.WebhookAuthenticationError = exports.WebhookError = exports.basicAuthValidator = exports.WebhookContentType = exports.WebhookEventType = void 0;
4
4
  const createChargebee_js_1 = require("./createChargebee.js");
5
5
  const FetchClient_js_1 = require("./net/FetchClient.js");
6
+ const chargebeeZodValidationError_js_1 = require("./chargebeeZodValidationError.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;
@@ -19,3 +20,4 @@ Object.defineProperty(exports, "WebhookError", { enumerable: true, get: function
19
20
  Object.defineProperty(exports, "WebhookAuthenticationError", { enumerable: true, get: function () { return handler_js_2.WebhookAuthenticationError; } });
20
21
  Object.defineProperty(exports, "WebhookPayloadValidationError", { enumerable: true, get: function () { return handler_js_2.WebhookPayloadValidationError; } });
21
22
  Object.defineProperty(exports, "WebhookPayloadParseError", { enumerable: true, get: function () { return handler_js_2.WebhookPayloadParseError; } });
23
+ module.exports.ChargebeeZodValidationError = chargebeeZodValidationError_js_1.ChargebeeZodValidationError;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChargebeeZodValidationError = void 0;
4
+ class ChargebeeZodValidationError extends Error {
5
+ constructor(actionName, zodError) {
6
+ var _a;
7
+ const messages = zodError.issues
8
+ .map((e) => `${e.path.join('.')}: ${e.message}`)
9
+ .join('; ');
10
+ super(`[Chargebee] Validation failed for '${actionName}': ${messages}`);
11
+ Object.setPrototypeOf(this, new.target.prototype);
12
+ this.name = 'ChargebeeZodValidationError';
13
+ this.actionName = actionName;
14
+ this.zodError = zodError;
15
+ (_a = Error.captureStackTrace) === null || _a === void 0 ? void 0 : _a.call(Error, this, this.constructor);
16
+ }
17
+ }
18
+ exports.ChargebeeZodValidationError = ChargebeeZodValidationError;
@@ -1,4 +1,15 @@
1
1
  "use strict";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
2
13
  Object.defineProperty(exports, "__esModule", { value: true });
3
14
  exports.CreateChargebee = void 0;
4
15
  const RequestWrapper_js_1 = require("./RequestWrapper.js");
@@ -10,10 +21,14 @@ const handler_js_1 = require("./resources/webhook/handler.js");
10
21
  const CreateChargebee = (httpClient) => {
11
22
  const Chargebee = function (conf) {
12
23
  this._env = Object.assign({}, environment_js_1.Environment);
13
- (0, util_js_1.extend)(true, this._env, conf);
24
+ const { telemetryAdapter, httpClient: configHttpClient } = conf, confToMerge = __rest(conf, ["telemetryAdapter", "httpClient"]);
25
+ (0, util_js_1.extend)(true, this._env, confToMerge);
14
26
  // @ts-ignore
15
27
  this._env.httpClient =
16
- conf.httpClient != null ? conf.httpClient : httpClient;
28
+ configHttpClient != null ? configHttpClient : httpClient;
29
+ if (telemetryAdapter !== undefined) {
30
+ this._env.telemetryAdapter = telemetryAdapter;
31
+ }
17
32
  this._buildResources();
18
33
  this._endpoints = api_endpoints_js_1.Endpoints;
19
34
  // Initialize webhooks handler with auto-configured Basic Auth (if env vars are set)
@@ -85,6 +100,7 @@ const CreateChargebee = (httpClient) => {
85
100
  for (let apiIdx = 0; apiIdx < apiCalls.length; apiIdx++) {
86
101
  const metaArr = apiCalls[apiIdx];
87
102
  const apiCall = {
103
+ resource: res,
88
104
  methodName: metaArr[0],
89
105
  httpMethod: metaArr[1],
90
106
  urlPrefix: metaArr[2],
@@ -96,6 +112,11 @@ const CreateChargebee = (httpClient) => {
96
112
  jsonKeys: metaArr[7],
97
113
  options: metaArr[8],
98
114
  };
115
+ if (this._env.enableValidation) {
116
+ // Store resource and action for lazy schema loading in RequestWrapper
117
+ apiCall.resourceKey = res;
118
+ apiCall.actionName = metaArr[0];
119
+ }
99
120
  this[res][apiCall.methodName] = this._createApiFunc(apiCall, this._env);
100
121
  }
101
122
  }
@@ -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.26.0',
14
+ clientVersion: 'v3.28.0',
15
15
  port: DEFAULT_PORT,
16
16
  timemachineWaitInMillis: DEFAULT_TIME_MACHINE_WAIT,
17
17
  exportWaitInMillis: DEFAULT_EXPORT_WAIT,