@inkress/admin-sdk 1.1.41 → 1.1.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1917,7 +1917,7 @@ const ORDER_FIELD_TYPES = {
1917
1917
  status_on: 'number',
1918
1918
  uid: 'string',
1919
1919
  cart_id: 'number',
1920
- currency_id: 'number',
1920
+ currency_code: 'string',
1921
1921
  customer_id: 'number',
1922
1922
  payment_link_id: 'number',
1923
1923
  billing_plan_id: 'number',
@@ -1945,7 +1945,7 @@ const PRODUCT_FIELD_TYPES = {
1945
1945
  tag_ids: 'array',
1946
1946
  uid: 'string',
1947
1947
  category_id: 'number',
1948
- currency_id: 'number',
1948
+ currency_code: 'string',
1949
1949
  user_id: 'number',
1950
1950
  inserted_at: 'date',
1951
1951
  updated_at: 'date',
@@ -2037,7 +2037,7 @@ const BILLING_PLAN_FIELD_TYPES = {
2037
2037
  payout_value_limit: 'number',
2038
2038
  payout_percentage_limit: 'number',
2039
2039
  uid: 'string',
2040
- currency_id: 'number',
2040
+ currency_code: 'string',
2041
2041
  payment_provider_id: 'number',
2042
2042
  inserted_at: 'date',
2043
2043
  updated_at: 'date',
@@ -2078,7 +2078,7 @@ const PAYMENT_LINK_FIELD_TYPES = {
2078
2078
  status: 'number',
2079
2079
  kind: 'number',
2080
2080
  customer_id: 'number',
2081
- currency_id: 'number',
2081
+ currency_code: 'string',
2082
2082
  order_id: 'number',
2083
2083
  inserted_at: 'date',
2084
2084
  updated_at: 'date',
@@ -2122,7 +2122,7 @@ const FINANCIAL_REQUEST_FIELD_TYPES = {
2122
2122
  merchant_id: 'number',
2123
2123
  requester_id: 'number',
2124
2124
  reviewer_id: 'number',
2125
- currency_id: 'number',
2125
+ currency_code: 'string',
2126
2126
  evidence_file_id: 'number',
2127
2127
  inserted_at: 'date',
2128
2128
  updated_at: 'date',
@@ -2216,7 +2216,6 @@ const FEE_FIELD_TYPES = {
2216
2216
  currency_code: 'string',
2217
2217
  hash: 'string',
2218
2218
  fee_set_id: 'number',
2219
- currency_id: 'number',
2220
2219
  user_id: 'number',
2221
2220
  inserted_at: 'date',
2222
2221
  updated_at: 'date',
@@ -3842,6 +3841,15 @@ class FinancialRequestsResource {
3842
3841
  }
3843
3842
  }
3844
3843
 
3844
+ let crypto;
3845
+ try {
3846
+ if (typeof require !== 'undefined') {
3847
+ crypto = require('crypto');
3848
+ }
3849
+ }
3850
+ catch (_a) {
3851
+ // Fallback for environments without Node.js crypto
3852
+ }
3845
3853
  class WebhookUrlsResource {
3846
3854
  constructor(client) {
3847
3855
  this.client = client;
@@ -3901,6 +3909,160 @@ class WebhookUrlsResource {
3901
3909
  createQueryBuilder() {
3902
3910
  return new WebhookUrlQueryBuilder(this);
3903
3911
  }
3912
+ // ============================================================================
3913
+ // WEBHOOK VERIFICATION METHODS
3914
+ // ============================================================================
3915
+ /**
3916
+ * Verify webhook signature using HMAC SHA256
3917
+ * Inkress webhooks use the format: crypto.mac(:hmac, :sha256, secret, body) |> Base.encode64()
3918
+ */
3919
+ verifySignature(body, signature, secret) {
3920
+ if (!crypto) {
3921
+ throw new Error('Node.js crypto module not available. Cannot verify webhook signature.');
3922
+ }
3923
+ try {
3924
+ // Generate expected signature using HMAC SHA256
3925
+ const expectedSignature = crypto
3926
+ .createHmac('sha256', secret)
3927
+ .update(body, 'utf8')
3928
+ .digest('base64');
3929
+ // Use constant-time comparison to prevent timing attacks
3930
+ return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature));
3931
+ }
3932
+ catch (error) {
3933
+ return false;
3934
+ }
3935
+ }
3936
+ /**
3937
+ * Parse webhook payload from a string
3938
+ */
3939
+ parsePayload(payload) {
3940
+ try {
3941
+ const parsed = JSON.parse(payload);
3942
+ if (!parsed.id || !parsed.timestamp || !parsed.event) {
3943
+ throw new Error('Invalid webhook payload structure: missing required fields (id, timestamp, or event)');
3944
+ }
3945
+ return parsed;
3946
+ }
3947
+ catch (error) {
3948
+ if (error instanceof Error) {
3949
+ throw new Error(`Failed to parse webhook payload: ${error.message}`);
3950
+ }
3951
+ throw new Error('Failed to parse webhook payload');
3952
+ }
3953
+ }
3954
+ /**
3955
+ * Verify and parse an incoming webhook request
3956
+ * This method clones the request body, validates the signature, and returns the parsed payload
3957
+ *
3958
+ * @param request - The incoming HTTP request object with headers and body
3959
+ * @param secret - Your webhook secret for signature verification
3960
+ * @param options - Optional verification options (e.g., timestamp tolerance)
3961
+ * @returns Promise that resolves to the parsed webhook payload
3962
+ * @throws Error if signature verification fails or payload is invalid
3963
+ *
3964
+ * @example
3965
+ * ```typescript
3966
+ * // Express.js example
3967
+ * app.post('/webhooks', async (req, res) => {
3968
+ * try {
3969
+ * const payload = await sdk.webhookUrls.verifyRequest(
3970
+ * { headers: req.headers, body: req.body },
3971
+ * 'your-webhook-secret'
3972
+ * );
3973
+ *
3974
+ * // Process the webhook
3975
+ * console.log('Received webhook:', payload.event.type);
3976
+ *
3977
+ * res.status(200).json({ received: true });
3978
+ * } catch (error) {
3979
+ * console.error('Webhook verification failed:', error);
3980
+ * res.status(400).json({ error: error.message });
3981
+ * }
3982
+ * });
3983
+ * ```
3984
+ */
3985
+ async verifyRequest(request, secret, options) {
3986
+ // Extract signature from headers (case-insensitive)
3987
+ const signature = request.headers['x-inkress-webhook-signature'] ||
3988
+ request.headers['X-Inkress-Webhook-Signature'];
3989
+ if (!signature || typeof signature !== 'string') {
3990
+ throw new Error('Missing X-Inkress-Webhook-Signature header');
3991
+ }
3992
+ // Clone and ensure body is a string
3993
+ let body;
3994
+ if (typeof request.body === 'string') {
3995
+ body = request.body;
3996
+ }
3997
+ else if (request.body && typeof request.body === 'object') {
3998
+ body = JSON.stringify(request.body);
3999
+ }
4000
+ else {
4001
+ throw new Error('Invalid request body format: body must be a string or object');
4002
+ }
4003
+ // Verify signature
4004
+ const isValid = this.verifySignature(body, signature, secret);
4005
+ if (!isValid) {
4006
+ throw new Error('Webhook signature verification failed: signature does not match');
4007
+ }
4008
+ // Parse the payload
4009
+ const payload = this.parsePayload(body);
4010
+ // Optional: Verify timestamp tolerance
4011
+ if (options === null || options === void 0 ? void 0 : options.tolerance) {
4012
+ const currentTimestamp = Math.floor(Date.now() / 1000);
4013
+ const timeDifference = Math.abs(currentTimestamp - payload.timestamp);
4014
+ if (timeDifference > options.tolerance) {
4015
+ throw new Error(`Webhook timestamp outside tolerance window: ${timeDifference}s (max: ${options.tolerance}s)`);
4016
+ }
4017
+ }
4018
+ return payload;
4019
+ }
4020
+ /**
4021
+ * Verify webhook signature only (without parsing)
4022
+ * Useful for custom verification flows
4023
+ *
4024
+ * @param body - The raw webhook request body as a string
4025
+ * @param signature - The signature from X-Inkress-Webhook-Signature header
4026
+ * @param secret - Your webhook secret
4027
+ * @returns Promise that resolves to true if valid, rejects with error if invalid
4028
+ */
4029
+ async verify(body, signature, secret) {
4030
+ if (!this.verifySignature(body, signature, secret)) {
4031
+ throw new Error('Webhook signature verification failed');
4032
+ }
4033
+ return true;
4034
+ }
4035
+ /**
4036
+ * Generate webhook signature for testing
4037
+ * Matches Inkress signature generation: crypto.mac(:hmac, :sha256, secret, body) |> Base.encode64()
4038
+ *
4039
+ * @example
4040
+ * ```typescript
4041
+ * const testBody = JSON.stringify({ id: '123', timestamp: Date.now(), event: {...} });
4042
+ * const signature = sdk.webhookUrls.generateSignature(testBody, 'your-secret');
4043
+ * ```
4044
+ */
4045
+ generateSignature(body, secret) {
4046
+ if (!crypto) {
4047
+ throw new Error('Node.js crypto module not available. Cannot generate signature.');
4048
+ }
4049
+ return crypto
4050
+ .createHmac('sha256', secret)
4051
+ .update(body, 'utf8')
4052
+ .digest('base64');
4053
+ }
4054
+ /**
4055
+ * Extract event data from webhook payload with type safety
4056
+ *
4057
+ * @example
4058
+ * ```typescript
4059
+ * const payload = await sdk.webhookUrls.verifyRequest(request, secret);
4060
+ * const orderData = sdk.webhookUrls.extractEventData<Order>(payload);
4061
+ * ```
4062
+ */
4063
+ extractEventData(payload) {
4064
+ return payload.event.data;
4065
+ }
3904
4066
  }
3905
4067
 
3906
4068
  /**