vesant-sdk 1.2.0 → 1.3.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.
Files changed (71) hide show
  1. package/dist/{client-BWp5FI3x.d.ts → client-B6fUFAUM.d.mts} +2 -1
  2. package/dist/{client-BIfLMfuC.d.mts → client-DoczGA6L.d.ts} +2 -1
  3. package/dist/client-DzElM7u-.d.mts +238 -0
  4. package/dist/client-DzElM7u-.d.ts +238 -0
  5. package/dist/compliance/index.d.mts +5 -4
  6. package/dist/compliance/index.d.ts +5 -4
  7. package/dist/compliance/index.js +306 -98
  8. package/dist/compliance/index.js.map +1 -1
  9. package/dist/compliance/index.mjs +306 -98
  10. package/dist/compliance/index.mjs.map +1 -1
  11. package/dist/decisions/index.d.mts +100 -0
  12. package/dist/decisions/index.d.ts +100 -0
  13. package/dist/decisions/index.js +607 -0
  14. package/dist/decisions/index.js.map +1 -0
  15. package/dist/decisions/index.mjs +605 -0
  16. package/dist/decisions/index.mjs.map +1 -0
  17. package/dist/geolocation/index.d.mts +4 -3
  18. package/dist/geolocation/index.d.ts +4 -3
  19. package/dist/geolocation/index.js +306 -98
  20. package/dist/geolocation/index.js.map +1 -1
  21. package/dist/geolocation/index.mjs +306 -98
  22. package/dist/geolocation/index.mjs.map +1 -1
  23. package/dist/index.d.mts +15 -7
  24. package/dist/index.d.ts +15 -7
  25. package/dist/index.js +676 -90
  26. package/dist/index.js.map +1 -1
  27. package/dist/index.mjs +667 -91
  28. package/dist/index.mjs.map +1 -1
  29. package/dist/kyc/core.d.mts +4 -3
  30. package/dist/kyc/core.d.ts +4 -3
  31. package/dist/kyc/core.js +284 -29
  32. package/dist/kyc/core.js.map +1 -1
  33. package/dist/kyc/core.mjs +284 -29
  34. package/dist/kyc/core.mjs.map +1 -1
  35. package/dist/kyc/index.d.mts +46 -3
  36. package/dist/kyc/index.d.ts +46 -3
  37. package/dist/kyc/index.js +284 -29
  38. package/dist/kyc/index.js.map +1 -1
  39. package/dist/kyc/index.mjs +284 -29
  40. package/dist/kyc/index.mjs.map +1 -1
  41. package/dist/react.d.mts +9 -5
  42. package/dist/react.d.ts +9 -5
  43. package/dist/react.js +422 -99
  44. package/dist/react.js.map +1 -1
  45. package/dist/react.mjs +322 -4
  46. package/dist/react.mjs.map +1 -1
  47. package/dist/risk-profile/index.d.mts +4 -4
  48. package/dist/risk-profile/index.d.ts +4 -4
  49. package/dist/risk-profile/index.js +249 -29
  50. package/dist/risk-profile/index.js.map +1 -1
  51. package/dist/risk-profile/index.mjs +249 -29
  52. package/dist/risk-profile/index.mjs.map +1 -1
  53. package/dist/scores/index.d.mts +96 -0
  54. package/dist/scores/index.d.ts +96 -0
  55. package/dist/scores/index.js +594 -0
  56. package/dist/scores/index.js.map +1 -0
  57. package/dist/scores/index.mjs +591 -0
  58. package/dist/scores/index.mjs.map +1 -0
  59. package/dist/{types-DfHLp_tz.d.ts → types-DLC7Sfy5.d.ts} +1 -1
  60. package/dist/types-DZHongaK.d.mts +61 -0
  61. package/dist/types-DZHongaK.d.ts +61 -0
  62. package/dist/{types-DKCQN4C5.d.mts → types-jaLuzruy.d.mts} +1 -1
  63. package/dist/webhooks/index.d.mts +176 -0
  64. package/dist/webhooks/index.d.ts +176 -0
  65. package/dist/webhooks/index.js +193 -0
  66. package/dist/webhooks/index.js.map +1 -0
  67. package/dist/webhooks/index.mjs +188 -0
  68. package/dist/webhooks/index.mjs.map +1 -0
  69. package/package.json +25 -2
  70. package/dist/types-BpKxSXGF.d.mts +0 -177
  71. package/dist/types-BpKxSXGF.d.ts +0 -177
@@ -0,0 +1,193 @@
1
+ 'use strict';
2
+
3
+ // src/core/webhook-utils.ts
4
+ async function verifyWebhookSignature(payload, signature, secret) {
5
+ const hexDigest = await computeHmacSha256(payload, secret);
6
+ const expectedPrefixed = `sha256=${hexDigest}`;
7
+ if (signature.startsWith("sha256=")) {
8
+ return constantTimeEqual(signature, expectedPrefixed);
9
+ }
10
+ return constantTimeEqual(signature, hexDigest);
11
+ }
12
+ async function computeHmacSha256(message, secret) {
13
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
14
+ const encoder = new TextEncoder();
15
+ const key = await globalThis.crypto.subtle.importKey(
16
+ "raw",
17
+ encoder.encode(secret),
18
+ { name: "HMAC", hash: "SHA-256" },
19
+ false,
20
+ ["sign"]
21
+ );
22
+ const sig = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(message));
23
+ return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
24
+ }
25
+ try {
26
+ const { createHmac } = await import('crypto');
27
+ return createHmac("sha256", secret).update(message).digest("hex");
28
+ } catch {
29
+ throw new Error(
30
+ "No crypto implementation available. Requires Web Crypto API or Node.js crypto module."
31
+ );
32
+ }
33
+ }
34
+ function constantTimeEqual(a, b) {
35
+ if (a.length !== b.length) {
36
+ return false;
37
+ }
38
+ let result = 0;
39
+ for (let i = 0; i < a.length; i++) {
40
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
41
+ }
42
+ return result === 0;
43
+ }
44
+
45
+ // src/webhooks/handler.ts
46
+ var WebhookHandler = class {
47
+ constructor(config) {
48
+ this.handlers = /* @__PURE__ */ new Map();
49
+ this.anyHandlers = [];
50
+ this.secret = config.secret;
51
+ this.tolerance = config.tolerance ?? 3e5;
52
+ }
53
+ /**
54
+ * Register a handler for a specific event type.
55
+ */
56
+ on(eventType, handler) {
57
+ const existing = this.handlers.get(eventType) || [];
58
+ existing.push(handler);
59
+ this.handlers.set(eventType, existing);
60
+ return this;
61
+ }
62
+ /**
63
+ * Register a catch-all handler for all event types.
64
+ */
65
+ onAny(handler) {
66
+ this.anyHandlers.push(handler);
67
+ return this;
68
+ }
69
+ /**
70
+ * Verify signature and parse the webhook body.
71
+ */
72
+ async verifyAndParse(body, signature) {
73
+ const isValid = await verifyWebhookSignature(body, signature, this.secret);
74
+ if (!isValid) {
75
+ throw new Error("Invalid webhook signature");
76
+ }
77
+ return this.parseAndValidate(body);
78
+ }
79
+ /**
80
+ * Verify signature, parse, and dispatch to registered handlers.
81
+ */
82
+ async handle(body, signature) {
83
+ const event = await this.verifyAndParse(body, signature);
84
+ await this.dispatch(event);
85
+ }
86
+ /**
87
+ * Parse an event without signature verification (for testing).
88
+ */
89
+ parseEvent(body) {
90
+ return this.parseAndValidate(body);
91
+ }
92
+ parseAndValidate(body) {
93
+ const event = JSON.parse(body);
94
+ if (!event.type || !event.id || !event.timestamp) {
95
+ throw new Error("Invalid webhook event: missing required fields (type, id, timestamp)");
96
+ }
97
+ if (this.tolerance > 0) {
98
+ const eventTime = new Date(event.timestamp).getTime();
99
+ const now = Date.now();
100
+ if (Math.abs(now - eventTime) > this.tolerance) {
101
+ throw new Error(
102
+ `Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`
103
+ );
104
+ }
105
+ }
106
+ return event;
107
+ }
108
+ async dispatch(event) {
109
+ const typeHandlers = this.handlers.get(event.type) || [];
110
+ const allHandlers = [...typeHandlers, ...this.anyHandlers];
111
+ for (const handler of allHandlers) {
112
+ await handler(event);
113
+ }
114
+ }
115
+ };
116
+
117
+ // src/webhooks/middleware.ts
118
+ function createWebhookMiddleware(options) {
119
+ const handler = buildHandler(options);
120
+ const signatureHeader = options.signatureHeader || "x-webhook-signature";
121
+ return async (req, res, next) => {
122
+ try {
123
+ const body = typeof req.body === "string" ? req.body : req.body.toString("utf-8");
124
+ const signature = req.headers[signatureHeader];
125
+ if (!signature || typeof signature !== "string") {
126
+ res.status(401).json({ error: "Missing webhook signature" });
127
+ return;
128
+ }
129
+ await handler.handle(body, signature);
130
+ res.status(200).json({ received: true });
131
+ } catch (error) {
132
+ const message = error instanceof Error ? error.message : "Webhook processing failed";
133
+ if (message.includes("signature")) {
134
+ res.status(401).json({ error: message });
135
+ } else if (message.includes("tolerance") || message.includes("timestamp")) {
136
+ res.status(400).json({ error: message });
137
+ } else if (next) {
138
+ next(error);
139
+ } else {
140
+ res.status(500).json({ error: message });
141
+ }
142
+ }
143
+ };
144
+ }
145
+ function createNextWebhookHandler(options) {
146
+ const handler = buildHandler(options);
147
+ const signatureHeader = options.signatureHeader || "x-webhook-signature";
148
+ return async (request) => {
149
+ try {
150
+ const body = await request.text();
151
+ const signature = request.headers.get(signatureHeader);
152
+ if (!signature) {
153
+ return new Response(JSON.stringify({ error: "Missing webhook signature" }), {
154
+ status: 401,
155
+ headers: { "Content-Type": "application/json" }
156
+ });
157
+ }
158
+ await handler.handle(body, signature);
159
+ return new Response(JSON.stringify({ received: true }), {
160
+ status: 200,
161
+ headers: { "Content-Type": "application/json" }
162
+ });
163
+ } catch (error) {
164
+ const message = error instanceof Error ? error.message : "Webhook processing failed";
165
+ const status = message.includes("signature") ? 401 : message.includes("tolerance") || message.includes("timestamp") ? 400 : 500;
166
+ return new Response(JSON.stringify({ error: message }), {
167
+ status,
168
+ headers: { "Content-Type": "application/json" }
169
+ });
170
+ }
171
+ };
172
+ }
173
+ function buildHandler(options) {
174
+ const handler = new WebhookHandler(options);
175
+ if (options.handlers) {
176
+ for (const [eventType, eventHandler] of Object.entries(options.handlers)) {
177
+ if (eventHandler) {
178
+ handler.on(eventType, eventHandler);
179
+ }
180
+ }
181
+ }
182
+ if (options.onAny) {
183
+ handler.onAny(options.onAny);
184
+ }
185
+ return handler;
186
+ }
187
+
188
+ exports.WebhookHandler = WebhookHandler;
189
+ exports.createNextWebhookHandler = createNextWebhookHandler;
190
+ exports.createWebhookMiddleware = createWebhookMiddleware;
191
+ exports.verifyWebhookSignature = verifyWebhookSignature;
192
+ //# sourceMappingURL=index.js.map
193
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/webhook-utils.ts","../../src/webhooks/handler.ts","../../src/webhooks/middleware.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Webhook signature verification utilities.\n *\n * Supports both Web Crypto API (browsers, Deno, Cloudflare Workers)\n * and Node.js crypto module with automatic runtime detection.\n * Uses constant-time comparison to prevent timing attacks.\n */\n\n/**\n * Verify an HMAC-SHA256 webhook signature.\n *\n * @param payload - The raw request body string\n * @param signature - The signature from the webhook header\n * @param secret - The webhook signing secret\n * @returns true if the signature is valid\n */\nexport async function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): Promise<boolean> {\n const hexDigest = await computeHmacSha256(payload, secret);\n\n // Backend sends \"sha256=<hex>\" format — support both prefixed and raw signatures\n const expectedPrefixed = `sha256=${hexDigest}`;\n\n if (signature.startsWith('sha256=')) {\n return constantTimeEqual(signature, expectedPrefixed);\n }\n\n return constantTimeEqual(signature, hexDigest);\n}\n\n/**\n * Compute HMAC-SHA256 hex digest.\n * Automatically selects Web Crypto API or Node.js crypto.\n */\nasync function computeHmacSha256(message: string, secret: string): Promise<string> {\n // Try Web Crypto API first (browsers, Deno, Cloudflare Workers, Node 18+)\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder();\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n const sig = await globalThis.crypto.subtle.sign('HMAC', key, encoder.encode(message));\n return Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Fallback to Node.js crypto module\n try {\n const { createHmac } = await import('crypto');\n return createHmac('sha256', secret).update(message).digest('hex');\n } catch {\n throw new Error(\n 'No crypto implementation available. Requires Web Crypto API or Node.js crypto module.'\n );\n }\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks.\n */\nfunction constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","/**\n * Webhook event handler with signature verification and typed dispatch.\n */\n\nimport { verifyWebhookSignature } from '../core/webhook-utils';\nimport type {\n WebhookEvent,\n WebhookEventType,\n WebhookEventHandler,\n WebhookAnyHandler,\n WebhookHandlerConfig,\n} from './types';\n\nexport class WebhookHandler {\n private handlers = new Map<WebhookEventType, WebhookEventHandler[]>();\n private anyHandlers: WebhookAnyHandler[] = [];\n private readonly secret: string;\n private readonly tolerance: number;\n\n constructor(config: WebhookHandlerConfig) {\n this.secret = config.secret;\n this.tolerance = config.tolerance ?? 300000; // 5 minutes\n }\n\n /**\n * Register a handler for a specific event type.\n */\n on<T extends WebhookEventType>(\n eventType: T,\n handler: WebhookEventHandler<T>\n ): this {\n const existing = this.handlers.get(eventType) || [];\n existing.push(handler as unknown as WebhookEventHandler);\n this.handlers.set(eventType, existing);\n return this;\n }\n\n /**\n * Register a catch-all handler for all event types.\n */\n onAny(handler: WebhookAnyHandler): this {\n this.anyHandlers.push(handler);\n return this;\n }\n\n /**\n * Verify signature and parse the webhook body.\n */\n async verifyAndParse(body: string, signature: string): Promise<WebhookEvent> {\n const isValid = await verifyWebhookSignature(body, signature, this.secret);\n if (!isValid) {\n throw new Error('Invalid webhook signature');\n }\n\n return this.parseAndValidate(body);\n }\n\n /**\n * Verify signature, parse, and dispatch to registered handlers.\n */\n async handle(body: string, signature: string): Promise<void> {\n const event = await this.verifyAndParse(body, signature);\n await this.dispatch(event);\n }\n\n /**\n * Parse an event without signature verification (for testing).\n */\n parseEvent(body: string): WebhookEvent {\n return this.parseAndValidate(body);\n }\n\n private parseAndValidate(body: string): WebhookEvent {\n const event = JSON.parse(body) as WebhookEvent;\n\n if (!event.type || !event.id || !event.timestamp) {\n throw new Error('Invalid webhook event: missing required fields (type, id, timestamp)');\n }\n\n // Timestamp tolerance check\n if (this.tolerance > 0) {\n const eventTime = new Date(event.timestamp).getTime();\n const now = Date.now();\n if (Math.abs(now - eventTime) > this.tolerance) {\n throw new Error(\n `Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`\n );\n }\n }\n\n return event;\n }\n\n private async dispatch(event: WebhookEvent): Promise<void> {\n const typeHandlers = this.handlers.get(event.type) || [];\n const allHandlers = [...typeHandlers, ...this.anyHandlers];\n\n for (const handler of allHandlers) {\n await (handler as WebhookAnyHandler)(event);\n }\n }\n}\n","/**\n * Framework middleware helpers for webhook handling.\n *\n * Provides pre-built integrations for Express/Connect and Next.js App Router.\n */\n\nimport { WebhookHandler } from './handler';\nimport type { WebhookHandlerConfig, WebhookEventType, WebhookEventHandler, WebhookAnyHandler } from './types';\n\nexport interface WebhookMiddlewareOptions extends WebhookHandlerConfig {\n /** Event handlers to register */\n handlers?: Partial<Record<WebhookEventType, WebhookEventHandler>>;\n /** Catch-all handler */\n onAny?: WebhookAnyHandler;\n}\n\n/**\n * Create an Express/Connect-compatible middleware for webhook handling.\n *\n * Expects the raw body to be available as `req.body` (string).\n * Use `express.raw({ type: 'application/json' })` or similar middleware upstream.\n */\nexport function createWebhookMiddleware(options: WebhookMiddlewareOptions) {\n const handler = buildHandler(options);\n const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n return async (\n req: { body: string | Buffer; headers: Record<string, string | string[] | undefined> },\n res: { status(code: number): { json(body: unknown): void }; json?(body: unknown): void },\n next?: (err?: unknown) => void\n ) => {\n try {\n const body = typeof req.body === 'string' ? req.body : req.body.toString('utf-8');\n const signature = req.headers[signatureHeader];\n\n if (!signature || typeof signature !== 'string') {\n res.status(401).json({ error: 'Missing webhook signature' });\n return;\n }\n\n await handler.handle(body, signature);\n res.status(200).json({ received: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Webhook processing failed';\n\n if (message.includes('signature')) {\n res.status(401).json({ error: message });\n } else if (message.includes('tolerance') || message.includes('timestamp')) {\n res.status(400).json({ error: message });\n } else if (next) {\n next(error);\n } else {\n res.status(500).json({ error: message });\n }\n }\n };\n}\n\n/**\n * Create a Next.js App Router-compatible webhook handler.\n *\n * Returns an async function `(request: Request) => Promise<Response>`.\n */\nexport function createNextWebhookHandler(\n options: WebhookMiddlewareOptions\n): (request: Request) => Promise<Response> {\n const handler = buildHandler(options);\n const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n return async (request: Request): Promise<Response> => {\n try {\n const body = await request.text();\n const signature = request.headers.get(signatureHeader);\n\n if (!signature) {\n return new Response(JSON.stringify({ error: 'Missing webhook signature' }), {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n await handler.handle(body, signature);\n\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Webhook processing failed';\n const status = message.includes('signature')\n ? 401\n : message.includes('tolerance') || message.includes('timestamp')\n ? 400\n : 500;\n\n return new Response(JSON.stringify({ error: message }), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n };\n}\n\nfunction buildHandler(options: WebhookMiddlewareOptions): WebhookHandler {\n const handler = new WebhookHandler(options);\n\n if (options.handlers) {\n for (const [eventType, eventHandler] of Object.entries(options.handlers)) {\n if (eventHandler) {\n handler.on(eventType as WebhookEventType, eventHandler);\n }\n }\n }\n\n if (options.onAny) {\n handler.onAny(options.onAny);\n }\n\n return handler;\n}\n"]}
@@ -0,0 +1,188 @@
1
+ // src/core/webhook-utils.ts
2
+ async function verifyWebhookSignature(payload, signature, secret) {
3
+ const hexDigest = await computeHmacSha256(payload, secret);
4
+ const expectedPrefixed = `sha256=${hexDigest}`;
5
+ if (signature.startsWith("sha256=")) {
6
+ return constantTimeEqual(signature, expectedPrefixed);
7
+ }
8
+ return constantTimeEqual(signature, hexDigest);
9
+ }
10
+ async function computeHmacSha256(message, secret) {
11
+ if (typeof globalThis.crypto !== "undefined" && globalThis.crypto.subtle) {
12
+ const encoder = new TextEncoder();
13
+ const key = await globalThis.crypto.subtle.importKey(
14
+ "raw",
15
+ encoder.encode(secret),
16
+ { name: "HMAC", hash: "SHA-256" },
17
+ false,
18
+ ["sign"]
19
+ );
20
+ const sig = await globalThis.crypto.subtle.sign("HMAC", key, encoder.encode(message));
21
+ return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
22
+ }
23
+ try {
24
+ const { createHmac } = await import('crypto');
25
+ return createHmac("sha256", secret).update(message).digest("hex");
26
+ } catch {
27
+ throw new Error(
28
+ "No crypto implementation available. Requires Web Crypto API or Node.js crypto module."
29
+ );
30
+ }
31
+ }
32
+ function constantTimeEqual(a, b) {
33
+ if (a.length !== b.length) {
34
+ return false;
35
+ }
36
+ let result = 0;
37
+ for (let i = 0; i < a.length; i++) {
38
+ result |= a.charCodeAt(i) ^ b.charCodeAt(i);
39
+ }
40
+ return result === 0;
41
+ }
42
+
43
+ // src/webhooks/handler.ts
44
+ var WebhookHandler = class {
45
+ constructor(config) {
46
+ this.handlers = /* @__PURE__ */ new Map();
47
+ this.anyHandlers = [];
48
+ this.secret = config.secret;
49
+ this.tolerance = config.tolerance ?? 3e5;
50
+ }
51
+ /**
52
+ * Register a handler for a specific event type.
53
+ */
54
+ on(eventType, handler) {
55
+ const existing = this.handlers.get(eventType) || [];
56
+ existing.push(handler);
57
+ this.handlers.set(eventType, existing);
58
+ return this;
59
+ }
60
+ /**
61
+ * Register a catch-all handler for all event types.
62
+ */
63
+ onAny(handler) {
64
+ this.anyHandlers.push(handler);
65
+ return this;
66
+ }
67
+ /**
68
+ * Verify signature and parse the webhook body.
69
+ */
70
+ async verifyAndParse(body, signature) {
71
+ const isValid = await verifyWebhookSignature(body, signature, this.secret);
72
+ if (!isValid) {
73
+ throw new Error("Invalid webhook signature");
74
+ }
75
+ return this.parseAndValidate(body);
76
+ }
77
+ /**
78
+ * Verify signature, parse, and dispatch to registered handlers.
79
+ */
80
+ async handle(body, signature) {
81
+ const event = await this.verifyAndParse(body, signature);
82
+ await this.dispatch(event);
83
+ }
84
+ /**
85
+ * Parse an event without signature verification (for testing).
86
+ */
87
+ parseEvent(body) {
88
+ return this.parseAndValidate(body);
89
+ }
90
+ parseAndValidate(body) {
91
+ const event = JSON.parse(body);
92
+ if (!event.type || !event.id || !event.timestamp) {
93
+ throw new Error("Invalid webhook event: missing required fields (type, id, timestamp)");
94
+ }
95
+ if (this.tolerance > 0) {
96
+ const eventTime = new Date(event.timestamp).getTime();
97
+ const now = Date.now();
98
+ if (Math.abs(now - eventTime) > this.tolerance) {
99
+ throw new Error(
100
+ `Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`
101
+ );
102
+ }
103
+ }
104
+ return event;
105
+ }
106
+ async dispatch(event) {
107
+ const typeHandlers = this.handlers.get(event.type) || [];
108
+ const allHandlers = [...typeHandlers, ...this.anyHandlers];
109
+ for (const handler of allHandlers) {
110
+ await handler(event);
111
+ }
112
+ }
113
+ };
114
+
115
+ // src/webhooks/middleware.ts
116
+ function createWebhookMiddleware(options) {
117
+ const handler = buildHandler(options);
118
+ const signatureHeader = options.signatureHeader || "x-webhook-signature";
119
+ return async (req, res, next) => {
120
+ try {
121
+ const body = typeof req.body === "string" ? req.body : req.body.toString("utf-8");
122
+ const signature = req.headers[signatureHeader];
123
+ if (!signature || typeof signature !== "string") {
124
+ res.status(401).json({ error: "Missing webhook signature" });
125
+ return;
126
+ }
127
+ await handler.handle(body, signature);
128
+ res.status(200).json({ received: true });
129
+ } catch (error) {
130
+ const message = error instanceof Error ? error.message : "Webhook processing failed";
131
+ if (message.includes("signature")) {
132
+ res.status(401).json({ error: message });
133
+ } else if (message.includes("tolerance") || message.includes("timestamp")) {
134
+ res.status(400).json({ error: message });
135
+ } else if (next) {
136
+ next(error);
137
+ } else {
138
+ res.status(500).json({ error: message });
139
+ }
140
+ }
141
+ };
142
+ }
143
+ function createNextWebhookHandler(options) {
144
+ const handler = buildHandler(options);
145
+ const signatureHeader = options.signatureHeader || "x-webhook-signature";
146
+ return async (request) => {
147
+ try {
148
+ const body = await request.text();
149
+ const signature = request.headers.get(signatureHeader);
150
+ if (!signature) {
151
+ return new Response(JSON.stringify({ error: "Missing webhook signature" }), {
152
+ status: 401,
153
+ headers: { "Content-Type": "application/json" }
154
+ });
155
+ }
156
+ await handler.handle(body, signature);
157
+ return new Response(JSON.stringify({ received: true }), {
158
+ status: 200,
159
+ headers: { "Content-Type": "application/json" }
160
+ });
161
+ } catch (error) {
162
+ const message = error instanceof Error ? error.message : "Webhook processing failed";
163
+ const status = message.includes("signature") ? 401 : message.includes("tolerance") || message.includes("timestamp") ? 400 : 500;
164
+ return new Response(JSON.stringify({ error: message }), {
165
+ status,
166
+ headers: { "Content-Type": "application/json" }
167
+ });
168
+ }
169
+ };
170
+ }
171
+ function buildHandler(options) {
172
+ const handler = new WebhookHandler(options);
173
+ if (options.handlers) {
174
+ for (const [eventType, eventHandler] of Object.entries(options.handlers)) {
175
+ if (eventHandler) {
176
+ handler.on(eventType, eventHandler);
177
+ }
178
+ }
179
+ }
180
+ if (options.onAny) {
181
+ handler.onAny(options.onAny);
182
+ }
183
+ return handler;
184
+ }
185
+
186
+ export { WebhookHandler, createNextWebhookHandler, createWebhookMiddleware, verifyWebhookSignature };
187
+ //# sourceMappingURL=index.mjs.map
188
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/webhook-utils.ts","../../src/webhooks/handler.ts","../../src/webhooks/middleware.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Webhook signature verification utilities.\n *\n * Supports both Web Crypto API (browsers, Deno, Cloudflare Workers)\n * and Node.js crypto module with automatic runtime detection.\n * Uses constant-time comparison to prevent timing attacks.\n */\n\n/**\n * Verify an HMAC-SHA256 webhook signature.\n *\n * @param payload - The raw request body string\n * @param signature - The signature from the webhook header\n * @param secret - The webhook signing secret\n * @returns true if the signature is valid\n */\nexport async function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string\n): Promise<boolean> {\n const hexDigest = await computeHmacSha256(payload, secret);\n\n // Backend sends \"sha256=<hex>\" format — support both prefixed and raw signatures\n const expectedPrefixed = `sha256=${hexDigest}`;\n\n if (signature.startsWith('sha256=')) {\n return constantTimeEqual(signature, expectedPrefixed);\n }\n\n return constantTimeEqual(signature, hexDigest);\n}\n\n/**\n * Compute HMAC-SHA256 hex digest.\n * Automatically selects Web Crypto API or Node.js crypto.\n */\nasync function computeHmacSha256(message: string, secret: string): Promise<string> {\n // Try Web Crypto API first (browsers, Deno, Cloudflare Workers, Node 18+)\n if (typeof globalThis.crypto !== 'undefined' && globalThis.crypto.subtle) {\n const encoder = new TextEncoder();\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign']\n );\n const sig = await globalThis.crypto.subtle.sign('HMAC', key, encoder.encode(message));\n return Array.from(new Uint8Array(sig))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n }\n\n // Fallback to Node.js crypto module\n try {\n const { createHmac } = await import('crypto');\n return createHmac('sha256', secret).update(message).digest('hex');\n } catch {\n throw new Error(\n 'No crypto implementation available. Requires Web Crypto API or Node.js crypto module.'\n );\n }\n}\n\n/**\n * Constant-time string comparison to prevent timing attacks.\n */\nfunction constantTimeEqual(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n}\n","/**\n * Webhook event handler with signature verification and typed dispatch.\n */\n\nimport { verifyWebhookSignature } from '../core/webhook-utils';\nimport type {\n WebhookEvent,\n WebhookEventType,\n WebhookEventHandler,\n WebhookAnyHandler,\n WebhookHandlerConfig,\n} from './types';\n\nexport class WebhookHandler {\n private handlers = new Map<WebhookEventType, WebhookEventHandler[]>();\n private anyHandlers: WebhookAnyHandler[] = [];\n private readonly secret: string;\n private readonly tolerance: number;\n\n constructor(config: WebhookHandlerConfig) {\n this.secret = config.secret;\n this.tolerance = config.tolerance ?? 300000; // 5 minutes\n }\n\n /**\n * Register a handler for a specific event type.\n */\n on<T extends WebhookEventType>(\n eventType: T,\n handler: WebhookEventHandler<T>\n ): this {\n const existing = this.handlers.get(eventType) || [];\n existing.push(handler as unknown as WebhookEventHandler);\n this.handlers.set(eventType, existing);\n return this;\n }\n\n /**\n * Register a catch-all handler for all event types.\n */\n onAny(handler: WebhookAnyHandler): this {\n this.anyHandlers.push(handler);\n return this;\n }\n\n /**\n * Verify signature and parse the webhook body.\n */\n async verifyAndParse(body: string, signature: string): Promise<WebhookEvent> {\n const isValid = await verifyWebhookSignature(body, signature, this.secret);\n if (!isValid) {\n throw new Error('Invalid webhook signature');\n }\n\n return this.parseAndValidate(body);\n }\n\n /**\n * Verify signature, parse, and dispatch to registered handlers.\n */\n async handle(body: string, signature: string): Promise<void> {\n const event = await this.verifyAndParse(body, signature);\n await this.dispatch(event);\n }\n\n /**\n * Parse an event without signature verification (for testing).\n */\n parseEvent(body: string): WebhookEvent {\n return this.parseAndValidate(body);\n }\n\n private parseAndValidate(body: string): WebhookEvent {\n const event = JSON.parse(body) as WebhookEvent;\n\n if (!event.type || !event.id || !event.timestamp) {\n throw new Error('Invalid webhook event: missing required fields (type, id, timestamp)');\n }\n\n // Timestamp tolerance check\n if (this.tolerance > 0) {\n const eventTime = new Date(event.timestamp).getTime();\n const now = Date.now();\n if (Math.abs(now - eventTime) > this.tolerance) {\n throw new Error(\n `Webhook event timestamp is outside tolerance window (${this.tolerance}ms)`\n );\n }\n }\n\n return event;\n }\n\n private async dispatch(event: WebhookEvent): Promise<void> {\n const typeHandlers = this.handlers.get(event.type) || [];\n const allHandlers = [...typeHandlers, ...this.anyHandlers];\n\n for (const handler of allHandlers) {\n await (handler as WebhookAnyHandler)(event);\n }\n }\n}\n","/**\n * Framework middleware helpers for webhook handling.\n *\n * Provides pre-built integrations for Express/Connect and Next.js App Router.\n */\n\nimport { WebhookHandler } from './handler';\nimport type { WebhookHandlerConfig, WebhookEventType, WebhookEventHandler, WebhookAnyHandler } from './types';\n\nexport interface WebhookMiddlewareOptions extends WebhookHandlerConfig {\n /** Event handlers to register */\n handlers?: Partial<Record<WebhookEventType, WebhookEventHandler>>;\n /** Catch-all handler */\n onAny?: WebhookAnyHandler;\n}\n\n/**\n * Create an Express/Connect-compatible middleware for webhook handling.\n *\n * Expects the raw body to be available as `req.body` (string).\n * Use `express.raw({ type: 'application/json' })` or similar middleware upstream.\n */\nexport function createWebhookMiddleware(options: WebhookMiddlewareOptions) {\n const handler = buildHandler(options);\n const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n return async (\n req: { body: string | Buffer; headers: Record<string, string | string[] | undefined> },\n res: { status(code: number): { json(body: unknown): void }; json?(body: unknown): void },\n next?: (err?: unknown) => void\n ) => {\n try {\n const body = typeof req.body === 'string' ? req.body : req.body.toString('utf-8');\n const signature = req.headers[signatureHeader];\n\n if (!signature || typeof signature !== 'string') {\n res.status(401).json({ error: 'Missing webhook signature' });\n return;\n }\n\n await handler.handle(body, signature);\n res.status(200).json({ received: true });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Webhook processing failed';\n\n if (message.includes('signature')) {\n res.status(401).json({ error: message });\n } else if (message.includes('tolerance') || message.includes('timestamp')) {\n res.status(400).json({ error: message });\n } else if (next) {\n next(error);\n } else {\n res.status(500).json({ error: message });\n }\n }\n };\n}\n\n/**\n * Create a Next.js App Router-compatible webhook handler.\n *\n * Returns an async function `(request: Request) => Promise<Response>`.\n */\nexport function createNextWebhookHandler(\n options: WebhookMiddlewareOptions\n): (request: Request) => Promise<Response> {\n const handler = buildHandler(options);\n const signatureHeader = options.signatureHeader || 'x-webhook-signature';\n\n return async (request: Request): Promise<Response> => {\n try {\n const body = await request.text();\n const signature = request.headers.get(signatureHeader);\n\n if (!signature) {\n return new Response(JSON.stringify({ error: 'Missing webhook signature' }), {\n status: 401,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n\n await handler.handle(body, signature);\n\n return new Response(JSON.stringify({ received: true }), {\n status: 200,\n headers: { 'Content-Type': 'application/json' },\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : 'Webhook processing failed';\n const status = message.includes('signature')\n ? 401\n : message.includes('tolerance') || message.includes('timestamp')\n ? 400\n : 500;\n\n return new Response(JSON.stringify({ error: message }), {\n status,\n headers: { 'Content-Type': 'application/json' },\n });\n }\n };\n}\n\nfunction buildHandler(options: WebhookMiddlewareOptions): WebhookHandler {\n const handler = new WebhookHandler(options);\n\n if (options.handlers) {\n for (const [eventType, eventHandler] of Object.entries(options.handlers)) {\n if (eventHandler) {\n handler.on(eventType as WebhookEventType, eventHandler);\n }\n }\n }\n\n if (options.onAny) {\n handler.onAny(options.onAny);\n }\n\n return handler;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vesant-sdk",
3
- "version": "1.2.0",
3
+ "version": "1.3.1",
4
4
  "description": "TypeScript SDK for Vesant Compliance Platform - Geolocation, KYC, Risk Profiling, CipherText, and Compliance Orchestration",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -40,6 +40,21 @@
40
40
  "types": "./dist/kyc/core.d.ts",
41
41
  "import": "./dist/kyc/core.mjs",
42
42
  "require": "./dist/kyc/core.js"
43
+ },
44
+ "./decisions": {
45
+ "types": "./dist/decisions/index.d.ts",
46
+ "import": "./dist/decisions/index.mjs",
47
+ "require": "./dist/decisions/index.js"
48
+ },
49
+ "./webhooks": {
50
+ "types": "./dist/webhooks/index.d.ts",
51
+ "import": "./dist/webhooks/index.mjs",
52
+ "require": "./dist/webhooks/index.js"
53
+ },
54
+ "./scores": {
55
+ "types": "./dist/scores/index.d.ts",
56
+ "import": "./dist/scores/index.mjs",
57
+ "require": "./dist/scores/index.js"
43
58
  }
44
59
  },
45
60
  "files": [
@@ -67,16 +82,21 @@
67
82
  "author": "Vesant Compliance",
68
83
  "license": "MIT",
69
84
  "peerDependencies": {
70
- "react": "^18.0.0"
85
+ "react": "^18.0.0",
86
+ "react-dom": "^18.0.0"
71
87
  },
72
88
  "peerDependenciesMeta": {
73
89
  "react": {
74
90
  "optional": true
91
+ },
92
+ "react-dom": {
93
+ "optional": true
75
94
  }
76
95
  },
77
96
  "devDependencies": {
78
97
  "@types/node": "^20.0.0",
79
98
  "@types/react": "^18.2.0",
99
+ "@types/react-dom": "^19",
80
100
  "@typescript-eslint/eslint-plugin": "^6.0.0",
81
101
  "@typescript-eslint/parser": "^6.0.0",
82
102
  "@vitest/coverage-v8": "^2.0.0",
@@ -94,5 +114,8 @@
94
114
  "type": "git",
95
115
  "url": "https://github.com/botcalm-compliance/cgs-server.git",
96
116
  "directory": "sdk/typescript"
117
+ },
118
+ "dependencies": {
119
+ "react-dom": "^19.2.4"
97
120
  }
98
121
  }