@webhook-platform/node 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,252 @@
1
+ # @webhook-platform/node
2
+
3
+ Official Node.js SDK for [Webhook Platform](https://github.com/vadymkykalo/webhook-platform).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @webhook-platform/node
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { WebhookPlatform } from '@webhook-platform/node';
15
+
16
+ const client = new WebhookPlatform({
17
+ apiKey: 'wh_live_your_api_key',
18
+ baseUrl: 'http://localhost:8080', // optional, defaults to localhost
19
+ });
20
+
21
+ // Send an event
22
+ const event = await client.events.send({
23
+ type: 'order.completed',
24
+ data: {
25
+ orderId: 'ord_12345',
26
+ amount: 99.99,
27
+ currency: 'USD',
28
+ },
29
+ });
30
+
31
+ console.log(`Event created: ${event.eventId}`);
32
+ console.log(`Deliveries created: ${event.deliveriesCreated}`);
33
+ ```
34
+
35
+ ## API Reference
36
+
37
+ ### Events
38
+
39
+ ```typescript
40
+ // Send event with idempotency key
41
+ const event = await client.events.send(
42
+ { type: 'order.completed', data: { orderId: '123' } },
43
+ 'unique-idempotency-key'
44
+ );
45
+ ```
46
+
47
+ ### Endpoints
48
+
49
+ ```typescript
50
+ // Create endpoint
51
+ const endpoint = await client.endpoints.create(projectId, {
52
+ url: 'https://api.example.com/webhooks',
53
+ description: 'Production webhooks',
54
+ enabled: true,
55
+ });
56
+
57
+ // List endpoints
58
+ const endpoints = await client.endpoints.list(projectId);
59
+
60
+ // Update endpoint
61
+ await client.endpoints.update(projectId, endpointId, {
62
+ enabled: false,
63
+ });
64
+
65
+ // Delete endpoint
66
+ await client.endpoints.delete(projectId, endpointId);
67
+
68
+ // Rotate secret
69
+ const updated = await client.endpoints.rotateSecret(projectId, endpointId);
70
+ console.log(`New secret: ${updated.secret}`);
71
+
72
+ // Test endpoint connectivity
73
+ const result = await client.endpoints.test(projectId, endpointId);
74
+ console.log(`Test ${result.success ? 'passed' : 'failed'}: ${result.latencyMs}ms`);
75
+ ```
76
+
77
+ ### Subscriptions
78
+
79
+ ```typescript
80
+ // Subscribe endpoint to event types
81
+ const subscription = await client.subscriptions.create(projectId, {
82
+ endpointId: endpoint.id,
83
+ eventTypes: ['order.completed', 'order.cancelled'],
84
+ enabled: true,
85
+ });
86
+
87
+ // List subscriptions
88
+ const subscriptions = await client.subscriptions.list(projectId);
89
+
90
+ // Update subscription
91
+ await client.subscriptions.update(projectId, subscriptionId, {
92
+ eventTypes: ['order.*'],
93
+ });
94
+
95
+ // Delete subscription
96
+ await client.subscriptions.delete(projectId, subscriptionId);
97
+ ```
98
+
99
+ ### Deliveries
100
+
101
+ ```typescript
102
+ // List deliveries with filters
103
+ const deliveries = await client.deliveries.list(projectId, {
104
+ status: 'FAILED',
105
+ page: 0,
106
+ size: 20,
107
+ });
108
+
109
+ console.log(`Total failed: ${deliveries.totalElements}`);
110
+
111
+ // Get delivery attempts
112
+ const attempts = await client.deliveries.getAttempts(deliveryId);
113
+ for (const attempt of attempts) {
114
+ console.log(`Attempt ${attempt.attemptNumber}: ${attempt.httpStatus} (${attempt.latencyMs}ms)`);
115
+ }
116
+
117
+ // Replay failed delivery
118
+ await client.deliveries.replay(deliveryId);
119
+ ```
120
+
121
+ ## Webhook Signature Verification
122
+
123
+ Verify incoming webhooks in your endpoint:
124
+
125
+ ```typescript
126
+ import { verifySignature, constructEvent } from '@webhook-platform/node';
127
+
128
+ app.post('/webhooks', (req, res) => {
129
+ const payload = req.body; // raw body string
130
+ const signature = req.headers['x-signature'];
131
+ const secret = process.env.WEBHOOK_SECRET;
132
+
133
+ try {
134
+ // Option 1: Just verify
135
+ verifySignature(payload, signature, secret);
136
+
137
+ // Option 2: Verify and parse
138
+ const event = constructEvent(payload, req.headers, secret);
139
+
140
+ console.log(`Received ${event.type}:`, event.data);
141
+
142
+ // Handle the event
143
+ switch (event.type) {
144
+ case 'order.completed':
145
+ handleOrderCompleted(event.data);
146
+ break;
147
+ }
148
+
149
+ res.status(200).send('OK');
150
+ } catch (err) {
151
+ console.error('Webhook verification failed:', err.message);
152
+ res.status(400).send('Invalid signature');
153
+ }
154
+ });
155
+ ```
156
+
157
+ ### Express.js Example
158
+
159
+ ```typescript
160
+ import express from 'express';
161
+ import { constructEvent } from '@webhook-platform/node';
162
+
163
+ const app = express();
164
+
165
+ // Important: Use raw body for signature verification
166
+ app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
167
+ const event = constructEvent(
168
+ req.body.toString(),
169
+ req.headers,
170
+ process.env.WEBHOOK_SECRET
171
+ );
172
+
173
+ // Process event...
174
+ res.sendStatus(200);
175
+ });
176
+ ```
177
+
178
+ ## Error Handling
179
+
180
+ ```typescript
181
+ import {
182
+ WebhookPlatformError,
183
+ RateLimitError,
184
+ AuthenticationError,
185
+ ValidationError
186
+ } from '@webhook-platform/node';
187
+
188
+ try {
189
+ await client.events.send({ type: 'test', data: {} });
190
+ } catch (err) {
191
+ if (err instanceof RateLimitError) {
192
+ // Wait and retry
193
+ console.log(`Rate limited. Retry after ${err.retryAfter}ms`);
194
+ await sleep(err.retryAfter);
195
+ } else if (err instanceof AuthenticationError) {
196
+ console.error('Invalid API key');
197
+ } else if (err instanceof ValidationError) {
198
+ console.error('Validation failed:', err.fieldErrors);
199
+ } else if (err instanceof WebhookPlatformError) {
200
+ console.error(`Error ${err.status}: ${err.message}`);
201
+ }
202
+ }
203
+ ```
204
+
205
+ ## Configuration
206
+
207
+ ```typescript
208
+ const client = new WebhookPlatform({
209
+ apiKey: 'wh_live_xxx', // Required: Your API key
210
+ baseUrl: 'https://api.example.com', // Optional: API base URL
211
+ timeout: 30000, // Optional: Request timeout in ms (default: 30000)
212
+ });
213
+ ```
214
+
215
+ ## TypeScript Support
216
+
217
+ This SDK is written in TypeScript and includes full type definitions:
218
+
219
+ ```typescript
220
+ import type {
221
+ Event,
222
+ EventResponse,
223
+ Endpoint,
224
+ Delivery,
225
+ DeliveryStatus
226
+ } from '@webhook-platform/node';
227
+ ```
228
+
229
+ ## Development
230
+
231
+ ### Running Tests
232
+
233
+ **Local (requires Node.js 16+):**
234
+ ```bash
235
+ npm install
236
+ npm test
237
+ ```
238
+
239
+ **Docker:**
240
+ ```bash
241
+ docker run --rm -v $(pwd):/app -w /app node:20-alpine sh -c "npm install && npm test"
242
+ ```
243
+
244
+ ### Building
245
+
246
+ ```bash
247
+ npm run build
248
+ ```
249
+
250
+ ## License
251
+
252
+ MIT
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const client_1 = require("../client");
4
+ const errors_1 = require("../errors");
5
+ describe('WebhookPlatform Client', () => {
6
+ describe('constructor', () => {
7
+ it('should create client with API key', () => {
8
+ const client = new client_1.WebhookPlatform({ apiKey: 'test_api_key' });
9
+ expect(client).toBeInstanceOf(client_1.WebhookPlatform);
10
+ });
11
+ it('should throw error without API key', () => {
12
+ expect(() => new client_1.WebhookPlatform({ apiKey: '' })).toThrow('API key is required');
13
+ });
14
+ it('should use default base URL', () => {
15
+ const client = new client_1.WebhookPlatform({ apiKey: 'test_api_key' });
16
+ expect(client).toBeDefined();
17
+ });
18
+ it('should accept custom base URL', () => {
19
+ const client = new client_1.WebhookPlatform({
20
+ apiKey: 'test_api_key',
21
+ baseUrl: 'https://api.example.com',
22
+ });
23
+ expect(client).toBeDefined();
24
+ });
25
+ it('should accept custom timeout', () => {
26
+ const client = new client_1.WebhookPlatform({
27
+ apiKey: 'test_api_key',
28
+ timeout: 60000,
29
+ });
30
+ expect(client).toBeDefined();
31
+ });
32
+ it('should initialize all API modules', () => {
33
+ const client = new client_1.WebhookPlatform({ apiKey: 'test_api_key' });
34
+ expect(client.events).toBeDefined();
35
+ expect(client.endpoints).toBeDefined();
36
+ expect(client.subscriptions).toBeDefined();
37
+ expect(client.deliveries).toBeDefined();
38
+ });
39
+ });
40
+ });
41
+ describe('Error Classes', () => {
42
+ describe('WebhookPlatformError', () => {
43
+ it('should have correct properties', () => {
44
+ const error = new errors_1.WebhookPlatformError('Test error', 500, 'test_code');
45
+ expect(error.message).toBe('Test error');
46
+ expect(error.status).toBe(500);
47
+ expect(error.code).toBe('test_code');
48
+ expect(error.name).toBe('WebhookPlatformError');
49
+ });
50
+ });
51
+ describe('AuthenticationError', () => {
52
+ it('should have correct defaults', () => {
53
+ const error = new errors_1.AuthenticationError();
54
+ expect(error.message).toBe('Invalid API key');
55
+ expect(error.status).toBe(401);
56
+ expect(error.code).toBe('authentication_error');
57
+ expect(error.name).toBe('AuthenticationError');
58
+ });
59
+ it('should accept custom message', () => {
60
+ const error = new errors_1.AuthenticationError('Custom auth error');
61
+ expect(error.message).toBe('Custom auth error');
62
+ });
63
+ });
64
+ describe('ValidationError', () => {
65
+ it('should have field errors', () => {
66
+ const fieldErrors = { email: 'Invalid email', url: 'Invalid URL' };
67
+ const error = new errors_1.ValidationError('Validation failed', fieldErrors);
68
+ expect(error.message).toBe('Validation failed');
69
+ expect(error.status).toBe(400);
70
+ expect(error.code).toBe('validation_error');
71
+ expect(error.fieldErrors).toEqual(fieldErrors);
72
+ });
73
+ it('should default to empty field errors', () => {
74
+ const error = new errors_1.ValidationError('Validation failed');
75
+ expect(error.fieldErrors).toEqual({});
76
+ });
77
+ });
78
+ });
79
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvX190ZXN0c19fL2NsaWVudC50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsc0NBQTRDO0FBQzVDLHNDQUF1RjtBQUV2RixRQUFRLENBQUMsd0JBQXdCLEVBQUUsR0FBRyxFQUFFO0lBQ3RDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsR0FBRyxFQUFFO1FBQzNCLEVBQUUsQ0FBQyxtQ0FBbUMsRUFBRSxHQUFHLEVBQUU7WUFDM0MsTUFBTSxNQUFNLEdBQUcsSUFBSSx3QkFBZSxDQUFDLEVBQUUsTUFBTSxFQUFFLGNBQWMsRUFBRSxDQUFDLENBQUM7WUFDL0QsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLGNBQWMsQ0FBQyx3QkFBZSxDQUFDLENBQUM7UUFDakQsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsb0NBQW9DLEVBQUUsR0FBRyxFQUFFO1lBQzVDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLHdCQUFlLENBQUMsRUFBRSxNQUFNLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDO1FBQ25GLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDZCQUE2QixFQUFFLEdBQUcsRUFBRTtZQUNyQyxNQUFNLE1BQU0sR0FBRyxJQUFJLHdCQUFlLENBQUMsRUFBRSxNQUFNLEVBQUUsY0FBYyxFQUFFLENBQUMsQ0FBQztZQUMvRCxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDL0IsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsK0JBQStCLEVBQUUsR0FBRyxFQUFFO1lBQ3ZDLE1BQU0sTUFBTSxHQUFHLElBQUksd0JBQWUsQ0FBQztnQkFDakMsTUFBTSxFQUFFLGNBQWM7Z0JBQ3RCLE9BQU8sRUFBRSx5QkFBeUI7YUFDbkMsQ0FBQyxDQUFDO1lB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LEVBQUUsQ0FBQywwQkFBMEIsRUFBRSxHQUFHLEVBQUU7WUFDbEMsTUFBTSxXQUFXLEdBQUcsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFFLEdBQUcsRUFBRSxhQUFhLEVBQUUsQ0FBQztZQUNuRSxNQUFNLEtBQUssR0FBRyxJQUFJLHdCQUFlLENBQUMsbUJBQW1CLEVBQUUsV0FBVyxDQUFDLENBQUM7WUFDcEUsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUNoRCxNQUFNLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMvQixNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDO1lBQzVDLE1BQU0sQ0FBQyxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1FBQ2pELENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLHNDQUFzQyxFQUFFLEdBQUcsRUFBRTtZQUM5QyxNQUFNLEtBQUssR0FBRyxJQUFJLHdCQUFlLENBQUMsbUJBQW1CLENBQUMsQ0FBQztZQUN2RCxNQUFNLENBQUMsS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUN4QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBXZWJob29rUGxhdGZvcm0gfSBmcm9tICcuLi9jbGllbnQnO1xuaW1wb3J0IHsgV2ViaG9va1BsYXRmb3JtRXJyb3IsIEF1dGhlbnRpY2F0aW9uRXJyb3IsIFZhbGlkYXRpb25FcnJvciB9IGZyb20gJy4uL2Vycm9ycyc7XG5cbmRlc2NyaWJlKCdXZWJob29rUGxhdGZvcm0gQ2xpZW50JywgKCkgPT4ge1xuICBkZXNjcmliZSgnY29uc3RydWN0b3InLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBjcmVhdGUgY2xpZW50IHdpdGggQVBJIGtleScsICgpID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IG5ldyBXZWJob29rUGxhdGZvcm0oeyBhcGlLZXk6ICd0ZXN0X2FwaV9rZXknIH0pO1xuICAgICAgZXhwZWN0KGNsaWVudCkudG9CZUluc3RhbmNlT2YoV2ViaG9va1BsYXRmb3JtKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgZXJyb3Igd2l0aG91dCBBUEkga2V5JywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IG5ldyBXZWJob29rUGxhdGZvcm0oeyBhcGlLZXk6ICcnIH0pKS50b1Rocm93KCdBUEkga2V5IGlzIHJlcXVpcmVkJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHVzZSBkZWZhdWx0IGJhc2UgVVJMJywgKCkgPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gbmV3IFdlYmhvb2tQbGF0Zm9ybSh7IGFwaUtleTogJ3Rlc3RfYXBpX2tleScgfSk7XG4gICAgICBleHBlY3QoY2xpZW50KS50b0JlRGVmaW5lZCgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhY2NlcHQgY3VzdG9tIGJhc2UgVVJMJywgKCkgPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gbmV3IFdlYmhvb2tQbGF0Zm9ybSh7XG4gICAgICAgIGFwaUtleTogJ3Rlc3RfYXBpX2tleScsXG4gICAgICAgIGJhc2VVcmw6ICdodHRwczovL2FwaS5leGFtcGxlLmNvbScsXG4gICAgICB9KTtcbiAgICAgIGV4cGVjdChjbGllbnQpLnRvQmVEZWZpbmVkKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFjY2VwdCBjdXN0b20gdGltZW91dCcsICgpID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IG5ldyBXZWJob29rUGxhdGZvcm0oe1xuICAgICAgICBhcGlLZXk6ICd0ZXN0X2FwaV9rZXknLFxuICAgICAgICB0aW1lb3V0OiA2MDAwMCxcbiAgICAgIH0pO1xuICAgICAgZXhwZWN0KGNsaWVudCkudG9CZURlZmluZWQoKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgaW5pdGlhbGl6ZSBhbGwgQVBJIG1vZHVsZXMnLCAoKSA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBuZXcgV2ViaG9va1BsYXRmb3JtKHsgYXBpS2V5OiAndGVzdF9hcGlfa2V5JyB9KTtcbiAgICAgIGV4cGVjdChjbGllbnQuZXZlbnRzKS50b0JlRGVmaW5lZCgpO1xuICAgICAgZXhwZWN0KGNsaWVudC5lbmRwb2ludHMpLnRvQmVEZWZpbmVkKCk7XG4gICAgICBleHBlY3QoY2xpZW50LnN1YnNjcmlwdGlvbnMpLnRvQmVEZWZpbmVkKCk7XG4gICAgICBleHBlY3QoY2xpZW50LmRlbGl2ZXJpZXMpLnRvQmVEZWZpbmVkKCk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG5cbmRlc2NyaWJlKCdFcnJvciBDbGFzc2VzJywgKCkgPT4ge1xuICBkZXNjcmliZSgnV2ViaG9va1BsYXRmb3JtRXJyb3InLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBoYXZlIGNvcnJlY3QgcHJvcGVydGllcycsICgpID0+IHtcbiAgICAgIGNvbnN0IGVycm9yID0gbmV3IFdlYmhvb2tQbGF0Zm9ybUVycm9yKCdUZXN0IGVycm9yJywgNTAwLCAndGVzdF9jb2RlJyk7XG4gICAgICBleHBlY3QoZXJyb3IubWVzc2FnZSkudG9CZSgnVGVzdCBlcnJvcicpO1xuICAgICAgZXhwZWN0KGVycm9yLnN0YXR1cykudG9CZSg1MDApO1xuICAgICAgZXhwZWN0KGVycm9yLmNvZGUpLnRvQmUoJ3Rlc3RfY29kZScpO1xuICAgICAgZXhwZWN0KGVycm9yLm5hbWUpLnRvQmUoJ1dlYmhvb2tQbGF0Zm9ybUVycm9yJyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdBdXRoZW50aWNhdGlvbkVycm9yJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgaGF2ZSBjb3JyZWN0IGRlZmF1bHRzJywgKCkgPT4ge1xuICAgICAgY29uc3QgZXJyb3IgPSBuZXcgQXV0aGVudGljYXRpb25FcnJvcigpO1xuICAgICAgZXhwZWN0KGVycm9yLm1lc3NhZ2UpLnRvQmUoJ0ludmFsaWQgQVBJIGtleScpO1xuICAgICAgZXhwZWN0KGVycm9yLnN0YXR1cykudG9CZSg0MDEpO1xuICAgICAgZXhwZWN0KGVycm9yLmNvZGUpLnRvQmUoJ2F1dGhlbnRpY2F0aW9uX2Vycm9yJyk7XG4gICAgICBleHBlY3QoZXJyb3IubmFtZSkudG9CZSgnQXV0aGVudGljYXRpb25FcnJvcicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhY2NlcHQgY3VzdG9tIG1lc3NhZ2UnLCAoKSA9PiB7XG4gICAgICBjb25zdCBlcnJvciA9IG5ldyBBdXRoZW50aWNhdGlvbkVycm9yKCdDdXN0b20gYXV0aCBlcnJvcicpO1xuICAgICAgZXhwZWN0KGVycm9yLm1lc3NhZ2UpLnRvQmUoJ0N1c3RvbSBhdXRoIGVycm9yJyk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdWYWxpZGF0aW9uRXJyb3InLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBoYXZlIGZpZWxkIGVycm9ycycsICgpID0+IHtcbiAgICAgIGNvbnN0IGZpZWxkRXJyb3JzID0geyBlbWFpbDogJ0ludmFsaWQgZW1haWwnLCB1cmw6ICdJbnZhbGlkIFVSTCcgfTtcbiAgICAgIGNvbnN0IGVycm9yID0gbmV3IFZhbGlkYXRpb25FcnJvcignVmFsaWRhdGlvbiBmYWlsZWQnLCBmaWVsZEVycm9ycyk7XG4gICAgICBleHBlY3QoZXJyb3IubWVzc2FnZSkudG9CZSgnVmFsaWRhdGlvbiBmYWlsZWQnKTtcbiAgICAgIGV4cGVjdChlcnJvci5zdGF0dXMpLnRvQmUoNDAwKTtcbiAgICAgIGV4cGVjdChlcnJvci5jb2RlKS50b0JlKCd2YWxpZGF0aW9uX2Vycm9yJyk7XG4gICAgICBleHBlY3QoZXJyb3IuZmllbGRFcnJvcnMpLnRvRXF1YWwoZmllbGRFcnJvcnMpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBkZWZhdWx0IHRvIGVtcHR5IGZpZWxkIGVycm9ycycsICgpID0+IHtcbiAgICAgIGNvbnN0IGVycm9yID0gbmV3IFZhbGlkYXRpb25FcnJvcignVmFsaWRhdGlvbiBmYWlsZWQnKTtcbiAgICAgIGV4cGVjdChlcnJvci5maWVsZEVycm9ycykudG9FcXVhbCh7fSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXX0=
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,162 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const webhooks_1 = require("../webhooks");
4
+ const errors_1 = require("../errors");
5
+ describe('Webhook Signature Verification', () => {
6
+ const secret = 'whsec_test_secret_key_123';
7
+ const payload = JSON.stringify({ type: 'order.completed', data: { orderId: '12345' } });
8
+ describe('generateSignature', () => {
9
+ it('should generate valid signature format', () => {
10
+ const signature = (0, webhooks_1.generateSignature)(payload, secret);
11
+ expect(signature).toMatch(/^t=\d+,v1=[a-f0-9]{64}$/);
12
+ });
13
+ it('should use provided timestamp', () => {
14
+ const timestamp = 1700000000000;
15
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
16
+ expect(signature).toContain(`t=${timestamp}`);
17
+ });
18
+ it('should generate consistent signatures for same inputs', () => {
19
+ const timestamp = 1700000000000;
20
+ const sig1 = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
21
+ const sig2 = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
22
+ expect(sig1).toBe(sig2);
23
+ });
24
+ it('should generate different signatures for different payloads', () => {
25
+ const timestamp = 1700000000000;
26
+ const sig1 = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
27
+ const sig2 = (0, webhooks_1.generateSignature)('different payload', secret, timestamp);
28
+ expect(sig1).not.toBe(sig2);
29
+ });
30
+ it('should generate different signatures for different secrets', () => {
31
+ const timestamp = 1700000000000;
32
+ const sig1 = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
33
+ const sig2 = (0, webhooks_1.generateSignature)(payload, 'different_secret', timestamp);
34
+ expect(sig1).not.toBe(sig2);
35
+ });
36
+ });
37
+ describe('verifySignature', () => {
38
+ it('should verify valid signature', () => {
39
+ const timestamp = Date.now();
40
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
41
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret)).toBe(true);
42
+ });
43
+ it('should throw on missing signature', () => {
44
+ expect(() => (0, webhooks_1.verifySignature)(payload, '', secret)).toThrow(errors_1.WebhookPlatformError);
45
+ expect(() => (0, webhooks_1.verifySignature)(payload, '', secret)).toThrow('Missing signature header');
46
+ });
47
+ it('should throw on invalid signature format', () => {
48
+ expect(() => (0, webhooks_1.verifySignature)(payload, 'invalid', secret)).toThrow('Invalid signature format');
49
+ });
50
+ it('should throw on missing timestamp', () => {
51
+ expect(() => (0, webhooks_1.verifySignature)(payload, 'v1=abc123', secret)).toThrow('Invalid signature format');
52
+ });
53
+ it('should throw on missing v1 signature', () => {
54
+ expect(() => (0, webhooks_1.verifySignature)(payload, 't=1700000000000', secret)).toThrow('Invalid signature format');
55
+ });
56
+ it('should throw on expired timestamp', () => {
57
+ const oldTimestamp = Date.now() - 600000; // 10 minutes ago
58
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, oldTimestamp);
59
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('outside tolerance window');
60
+ });
61
+ it('should throw on future timestamp outside tolerance', () => {
62
+ const futureTimestamp = Date.now() + 600000; // 10 minutes in future
63
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, futureTimestamp);
64
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('outside tolerance window');
65
+ });
66
+ it('should accept timestamp within tolerance', () => {
67
+ const recentTimestamp = Date.now() - 60000; // 1 minute ago
68
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, recentTimestamp);
69
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret)).toBe(true);
70
+ });
71
+ it('should throw on invalid signature value', () => {
72
+ const timestamp = Date.now();
73
+ const signature = `t=${timestamp},v1=invalid_signature_that_will_not_match`;
74
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('Invalid signature');
75
+ });
76
+ it('should throw on tampered payload', () => {
77
+ const timestamp = Date.now();
78
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
79
+ const tamperedPayload = JSON.stringify({ type: 'order.cancelled', data: {} });
80
+ expect(() => (0, webhooks_1.verifySignature)(tamperedPayload, signature, secret)).toThrow('Invalid signature');
81
+ });
82
+ it('should respect custom tolerance', () => {
83
+ const oldTimestamp = Date.now() - 60000; // 1 minute ago
84
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, oldTimestamp);
85
+ // Should fail with 30s tolerance
86
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret, { tolerance: 30000 }))
87
+ .toThrow('outside tolerance window');
88
+ // Should pass with 2min tolerance
89
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret, { tolerance: 120000 })).toBe(true);
90
+ });
91
+ });
92
+ describe('constructEvent', () => {
93
+ it('should construct event from valid request', () => {
94
+ const timestamp = Date.now();
95
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
96
+ const headers = {
97
+ 'x-signature': signature,
98
+ 'x-timestamp': timestamp.toString(),
99
+ 'x-event-id': 'evt_123',
100
+ 'x-delivery-id': 'dlv_456',
101
+ };
102
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
103
+ expect(event.eventId).toBe('evt_123');
104
+ expect(event.deliveryId).toBe('dlv_456');
105
+ expect(event.timestamp).toBe(timestamp);
106
+ expect(event.type).toBe('order.completed');
107
+ expect(event.data).toEqual({ orderId: '12345' });
108
+ });
109
+ it('should handle uppercase headers', () => {
110
+ const timestamp = Date.now();
111
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
112
+ const headers = {
113
+ 'X-Signature': signature,
114
+ 'X-Timestamp': timestamp.toString(),
115
+ 'X-Event-Id': 'evt_123',
116
+ 'X-Delivery-Id': 'dlv_456',
117
+ };
118
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
119
+ expect(event.eventId).toBe('evt_123');
120
+ });
121
+ it('should throw on missing signature header', () => {
122
+ const headers = {
123
+ 'x-timestamp': Date.now().toString(),
124
+ };
125
+ expect(() => (0, webhooks_1.constructEvent)(payload, headers, secret))
126
+ .toThrow('Missing X-Signature header');
127
+ });
128
+ it('should throw on invalid JSON payload', () => {
129
+ const timestamp = Date.now();
130
+ const invalidPayload = 'not valid json';
131
+ const signature = (0, webhooks_1.generateSignature)(invalidPayload, secret, timestamp);
132
+ const headers = {
133
+ 'x-signature': signature,
134
+ 'x-timestamp': timestamp.toString(),
135
+ };
136
+ expect(() => (0, webhooks_1.constructEvent)(invalidPayload, headers, secret))
137
+ .toThrow('Invalid JSON payload');
138
+ });
139
+ it('should handle payload without nested data field', () => {
140
+ const flatPayload = JSON.stringify({ type: 'test.event', value: 123 });
141
+ const timestamp = Date.now();
142
+ const signature = (0, webhooks_1.generateSignature)(flatPayload, secret, timestamp);
143
+ const headers = {
144
+ 'x-signature': signature,
145
+ 'x-timestamp': timestamp.toString(),
146
+ };
147
+ const event = (0, webhooks_1.constructEvent)(flatPayload, headers, secret);
148
+ expect(event.type).toBe('test.event');
149
+ expect(event.data).toEqual({ type: 'test.event', value: 123 });
150
+ });
151
+ it('should use current timestamp if not provided in headers', () => {
152
+ const timestamp = Date.now();
153
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
154
+ const headers = {
155
+ 'x-signature': signature,
156
+ };
157
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
158
+ expect(event.timestamp).toBeGreaterThan(0);
159
+ });
160
+ });
161
+ });
162
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9va3MudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9fX3Rlc3RzX18vd2ViaG9va3MudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDBDQUFpRjtBQUNqRixzQ0FBaUQ7QUFFakQsUUFBUSxDQUFDLGdDQUFnQyxFQUFFLEdBQUcsRUFBRTtJQUM5QyxNQUFNLE1BQU0sR0FBRywyQkFBMkIsQ0FBQztJQUMzQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFeEYsUUFBUSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRTtRQUNqQyxFQUFFLENBQUMsd0NBQXdDLEVBQUUsR0FBRyxFQUFFO1lBQ2hELE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3JELE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN2RCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQywrQkFBK0IsRUFBRSxHQUFHLEVBQUU7WUFDdkMsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUNoRSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNoRCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyx1REFBdUQsRUFBRSxHQUFHLEVBQUU7WUFDL0QsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMzRCxNQUFNLElBQUksR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDM0QsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUMxQixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyw2REFBNkQsRUFBRSxHQUFHLEVBQUU7WUFDckUsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMzRCxNQUFNLElBQUksR0FBRyxJQUFBLDRCQUFpQixFQUFDLG1CQUFtQixFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN2RSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5QixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyw0REFBNEQsRUFBRSxHQUFHLEVBQUU7WUFDcEUsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUMzRCxNQUFNLElBQUksR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUN2RSxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUSxDQUFDLGlCQUFpQixFQUFFLEdBQUcsRUFBRTtRQUMvQixFQUFFLENBQUMsK0JBQStCLEVBQUUsR0FBRyxFQUFFO1lBQ3ZDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDaEUsTUFBTSxDQUFDLElBQUEsMEJBQWUsRUFBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ2pFLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLG1DQUFtQyxFQUFFLEdBQUcsRUFBRTtZQUMzQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsNkJBQW9CLENBQUMsQ0FBQztZQUNqRixNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUN6RixDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQywwQ0FBMEMsRUFBRSxHQUFHLEVBQUU7WUFDbEQsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUEsMEJBQWUsRUFBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDaEcsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsbUNBQW1DLEVBQUUsR0FBRyxFQUFFO1lBQzNDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFBLDBCQUFlLEVBQUMsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1FBQ2xHLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLHNDQUFzQyxFQUFFLEdBQUcsRUFBRTtZQUM5QyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1FBQ3hHLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLG1DQUFtQyxFQUFFLEdBQUcsRUFBRTtZQUMzQyxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLEdBQUcsTUFBTSxDQUFDLENBQUMsaUJBQWlCO1lBQzNELE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxZQUFZLENBQUMsQ0FBQztZQUNuRSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsMEJBQTBCLENBQUMsQ0FBQztRQUNoRyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxvREFBb0QsRUFBRSxHQUFHLEVBQUU7WUFDNUQsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLE1BQU0sQ0FBQyxDQUFDLHVCQUF1QjtZQUNwRSxNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDdEUsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUEsMEJBQWUsRUFBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLDBCQUEwQixDQUFDLENBQUM7UUFDaEcsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsMENBQTBDLEVBQUUsR0FBRyxFQUFFO1lBQ2xELE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxLQUFLLENBQUMsQ0FBQyxlQUFlO1lBQzNELE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxlQUFlLENBQUMsQ0FBQztZQUN0RSxNQUFNLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDakUsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMseUNBQXlDLEVBQUUsR0FBRyxFQUFFO1lBQ2pELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxLQUFLLFNBQVMsMkNBQTJDLENBQUM7WUFDNUUsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUEsMEJBQWUsRUFBQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDekYsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsa0NBQWtDLEVBQUUsR0FBRyxFQUFFO1lBQzFDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFDaEUsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxFQUFFLElBQUksRUFBRSxpQkFBaUIsRUFBRSxJQUFJLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQztZQUM5RSxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLGVBQWUsRUFBRSxTQUFTLEVBQUUsTUFBTSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsbUJBQW1CLENBQUMsQ0FBQztRQUNqRyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxpQ0FBaUMsRUFBRSxHQUFHLEVBQUU7WUFDekMsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDLGVBQWU7WUFDeEQsTUFBTSxTQUFTLEdBQUcsSUFBQSw0QkFBaUIsRUFBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBRW5FLGlDQUFpQztZQUNqQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7aUJBQzVFLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO1lBRXZDLGtDQUFrQztZQUNsQyxNQUFNLENBQUMsSUFBQSwwQkFBZSxFQUFDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDeEYsQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztJQUVILFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRSxHQUFHLEVBQUU7UUFDOUIsRUFBRSxDQUFDLDJDQUEyQyxFQUFFLEdBQUcsRUFBRTtZQUNuRCxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUM7WUFDN0IsTUFBTSxTQUFTLEdBQUcsSUFBQSw0QkFBaUIsRUFBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBRWhFLE1BQU0sT0FBTyxHQUFHO2dCQUNkLGFBQWEsRUFBRSxTQUFTO2dCQUN4QixhQUFhLEVBQUUsU0FBUyxDQUFDLFFBQVEsRUFBRTtnQkFDbkMsWUFBWSxFQUFFLFNBQVM7Z0JBQ3ZCLGVBQWUsRUFBRSxTQUFTO2FBQzNCLENBQUM7WUFFRixNQUFNLEtBQUssR0FBRyxJQUFBLHlCQUFjLEVBQUMsT0FBTyxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUV2RCxNQUFNLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN6QyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztZQUN4QyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1lBQzNDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFDLENBQUM7UUFDbkQsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsaUNBQWlDLEVBQUUsR0FBRyxFQUFFO1lBQ3pDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFaEUsTUFBTSxPQUFPLEdBQUc7Z0JBQ2QsYUFBYSxFQUFFLFNBQVM7Z0JBQ3hCLGFBQWEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFO2dCQUNuQyxZQUFZLEVBQUUsU0FBUztnQkFDdkIsZUFBZSxFQUFFLFNBQVM7YUFDM0IsQ0FBQztZQUVGLE1BQU0sS0FBSyxHQUFHLElBQUEseUJBQWMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3hDLENBQUMsQ0FBQyxDQUFDO1FBRUgsRUFBRSxDQUFDLDBDQUEwQyxFQUFFLEdBQUcsRUFBRTtZQUNsRCxNQUFNLE9BQU8sR0FBRztnQkFDZCxhQUFhLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLFFBQVEsRUFBRTthQUNyQyxDQUFDO1lBRUYsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUEseUJBQWMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO2lCQUNuRCxPQUFPLENBQUMsNEJBQTRCLENBQUMsQ0FBQztRQUMzQyxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyxzQ0FBc0MsRUFBRSxHQUFHLEVBQUU7WUFDOUMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDO1lBQzdCLE1BQU0sY0FBYyxHQUFHLGdCQUFnQixDQUFDO1lBQ3hDLE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsY0FBYyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUV2RSxNQUFNLE9BQU8sR0FBRztnQkFDZCxhQUFhLEVBQUUsU0FBUztnQkFDeEIsYUFBYSxFQUFFLFNBQVMsQ0FBQyxRQUFRLEVBQUU7YUFDcEMsQ0FBQztZQUVGLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFBLHlCQUFjLEVBQUMsY0FBYyxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztpQkFDMUQsT0FBTyxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDckMsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMsaURBQWlELEVBQUUsR0FBRyxFQUFFO1lBQ3pELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxJQUFJLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxHQUFHLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZFLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFcEUsTUFBTSxPQUFPLEdBQUc7Z0JBQ2QsYUFBYSxFQUFFLFNBQVM7Z0JBQ3hCLGFBQWEsRUFBRSxTQUFTLENBQUMsUUFBUSxFQUFFO2FBQ3BDLENBQUM7WUFFRixNQUFNLEtBQUssR0FBRyxJQUFBLHlCQUFjLEVBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQztZQUMzRCxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztZQUN0QyxNQUFNLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUFFLElBQUksRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDakUsQ0FBQyxDQUFDLENBQUM7UUFFSCxFQUFFLENBQUMseURBQXlELEVBQUUsR0FBRyxFQUFFO1lBQ2pFLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUM3QixNQUFNLFNBQVMsR0FBRyxJQUFBLDRCQUFpQixFQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7WUFFaEUsTUFBTSxPQUFPLEdBQUc7Z0JBQ2QsYUFBYSxFQUFFLFNBQVM7YUFDekIsQ0FBQztZQUVGLE1BQU0sS0FBSyxHQUFHLElBQUEseUJBQWMsRUFBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3ZELE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQzdDLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHZlcmlmeVNpZ25hdHVyZSwgY29uc3RydWN0RXZlbnQsIGdlbmVyYXRlU2lnbmF0dXJlIH0gZnJvbSAnLi4vd2ViaG9va3MnO1xuaW1wb3J0IHsgV2ViaG9va1BsYXRmb3JtRXJyb3IgfSBmcm9tICcuLi9lcnJvcnMnO1xuXG5kZXNjcmliZSgnV2ViaG9vayBTaWduYXR1cmUgVmVyaWZpY2F0aW9uJywgKCkgPT4ge1xuICBjb25zdCBzZWNyZXQgPSAnd2hzZWNfdGVzdF9zZWNyZXRfa2V5XzEyMyc7XG4gIGNvbnN0IHBheWxvYWQgPSBKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdvcmRlci5jb21wbGV0ZWQnLCBkYXRhOiB7IG9yZGVySWQ6ICcxMjM0NScgfSB9KTtcblxuICBkZXNjcmliZSgnZ2VuZXJhdGVTaWduYXR1cmUnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSB2YWxpZCBzaWduYXR1cmUgZm9ybWF0JywgKCkgPT4ge1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0KTtcbiAgICAgIGV4cGVjdChzaWduYXR1cmUpLnRvTWF0Y2goL150PVxcZCssdjE9W2EtZjAtOV17NjR9JC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB1c2UgcHJvdmlkZWQgdGltZXN0YW1wJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gMTcwMDAwMDAwMDAwMDtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdChzaWduYXR1cmUpLnRvQ29udGFpbihgdD0ke3RpbWVzdGFtcH1gKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgY29uc2lzdGVudCBzaWduYXR1cmVzIGZvciBzYW1lIGlucHV0cycsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IDE3MDAwMDAwMDAwMDA7XG4gICAgICBjb25zdCBzaWcxID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgY29uc3Qgc2lnMiA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdChzaWcxKS50b0JlKHNpZzIpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBkaWZmZXJlbnQgc2lnbmF0dXJlcyBmb3IgZGlmZmVyZW50IHBheWxvYWRzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gMTcwMDAwMDAwMDAwMDtcbiAgICAgIGNvbnN0IHNpZzEgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBjb25zdCBzaWcyID0gZ2VuZXJhdGVTaWduYXR1cmUoJ2RpZmZlcmVudCBwYXlsb2FkJywgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgZXhwZWN0KHNpZzEpLm5vdC50b0JlKHNpZzIpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZW5lcmF0ZSBkaWZmZXJlbnQgc2lnbmF0dXJlcyBmb3IgZGlmZmVyZW50IHNlY3JldHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSAxNzAwMDAwMDAwMDAwO1xuICAgICAgY29uc3Qgc2lnMSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGNvbnN0IHNpZzIgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCAnZGlmZmVyZW50X3NlY3JldCcsIHRpbWVzdGFtcCk7XG4gICAgICBleHBlY3Qoc2lnMSkubm90LnRvQmUoc2lnMik7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd2ZXJpZnlTaWduYXR1cmUnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCB2ZXJpZnkgdmFsaWQgc2lnbmF0dXJlJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdCh2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQpKS50b0JlKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBtaXNzaW5nIHNpZ25hdHVyZScsICgpID0+IHtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgJycsIHNlY3JldCkpLnRvVGhyb3coV2ViaG9va1BsYXRmb3JtRXJyb3IpO1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCAnJywgc2VjcmV0KSkudG9UaHJvdygnTWlzc2luZyBzaWduYXR1cmUgaGVhZGVyJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIGludmFsaWQgc2lnbmF0dXJlIGZvcm1hdCcsICgpID0+IHtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgJ2ludmFsaWQnLCBzZWNyZXQpKS50b1Rocm93KCdJbnZhbGlkIHNpZ25hdHVyZSBmb3JtYXQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gbWlzc2luZyB0aW1lc3RhbXAnLCAoKSA9PiB7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsICd2MT1hYmMxMjMnLCBzZWNyZXQpKS50b1Rocm93KCdJbnZhbGlkIHNpZ25hdHVyZSBmb3JtYXQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gbWlzc2luZyB2MSBzaWduYXR1cmUnLCAoKSA9PiB7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsICd0PTE3MDAwMDAwMDAwMDAnLCBzZWNyZXQpKS50b1Rocm93KCdJbnZhbGlkIHNpZ25hdHVyZSBmb3JtYXQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gZXhwaXJlZCB0aW1lc3RhbXAnLCAoKSA9PiB7XG4gICAgICBjb25zdCBvbGRUaW1lc3RhbXAgPSBEYXRlLm5vdygpIC0gNjAwMDAwOyAvLyAxMCBtaW51dGVzIGFnb1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCBvbGRUaW1lc3RhbXApO1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCBzaWduYXR1cmUsIHNlY3JldCkpLnRvVGhyb3coJ291dHNpZGUgdG9sZXJhbmNlIHdpbmRvdycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBmdXR1cmUgdGltZXN0YW1wIG91dHNpZGUgdG9sZXJhbmNlJywgKCkgPT4ge1xuICAgICAgY29uc3QgZnV0dXJlVGltZXN0YW1wID0gRGF0ZS5ub3coKSArIDYwMDAwMDsgLy8gMTAgbWludXRlcyBpbiBmdXR1cmVcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgZnV0dXJlVGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQpKS50b1Rocm93KCdvdXRzaWRlIHRvbGVyYW5jZSB3aW5kb3cnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYWNjZXB0IHRpbWVzdGFtcCB3aXRoaW4gdG9sZXJhbmNlJywgKCkgPT4ge1xuICAgICAgY29uc3QgcmVjZW50VGltZXN0YW1wID0gRGF0ZS5ub3coKSAtIDYwMDAwOyAvLyAxIG1pbnV0ZSBhZ29cbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgcmVjZW50VGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdCh2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQpKS50b0JlKHRydWUpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBpbnZhbGlkIHNpZ25hdHVyZSB2YWx1ZScsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBgdD0ke3RpbWVzdGFtcH0sdjE9aW52YWxpZF9zaWduYXR1cmVfdGhhdF93aWxsX25vdF9tYXRjaGA7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsIHNpZ25hdHVyZSwgc2VjcmV0KSkudG9UaHJvdygnSW52YWxpZCBzaWduYXR1cmUnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gdGFtcGVyZWQgcGF5bG9hZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBjb25zdCB0YW1wZXJlZFBheWxvYWQgPSBKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICdvcmRlci5jYW5jZWxsZWQnLCBkYXRhOiB7fSB9KTtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUodGFtcGVyZWRQYXlsb2FkLCBzaWduYXR1cmUsIHNlY3JldCkpLnRvVGhyb3coJ0ludmFsaWQgc2lnbmF0dXJlJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlc3BlY3QgY3VzdG9tIHRvbGVyYW5jZScsICgpID0+IHtcbiAgICAgIGNvbnN0IG9sZFRpbWVzdGFtcCA9IERhdGUubm93KCkgLSA2MDAwMDsgLy8gMSBtaW51dGUgYWdvXG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIG9sZFRpbWVzdGFtcCk7XG4gICAgICBcbiAgICAgIC8vIFNob3VsZCBmYWlsIHdpdGggMzBzIHRvbGVyYW5jZVxuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCBzaWduYXR1cmUsIHNlY3JldCwgeyB0b2xlcmFuY2U6IDMwMDAwIH0pKVxuICAgICAgICAudG9UaHJvdygnb3V0c2lkZSB0b2xlcmFuY2Ugd2luZG93Jyk7XG4gICAgICBcbiAgICAgIC8vIFNob3VsZCBwYXNzIHdpdGggMm1pbiB0b2xlcmFuY2VcbiAgICAgIGV4cGVjdCh2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQsIHsgdG9sZXJhbmNlOiAxMjAwMDAgfSkpLnRvQmUodHJ1ZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdjb25zdHJ1Y3RFdmVudCcsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIGNvbnN0cnVjdCBldmVudCBmcm9tIHZhbGlkIHJlcXVlc3QnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgXG4gICAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgICAneC1zaWduYXR1cmUnOiBzaWduYXR1cmUsXG4gICAgICAgICd4LXRpbWVzdGFtcCc6IHRpbWVzdGFtcC50b1N0cmluZygpLFxuICAgICAgICAneC1ldmVudC1pZCc6ICdldnRfMTIzJyxcbiAgICAgICAgJ3gtZGVsaXZlcnktaWQnOiAnZGx2XzQ1NicsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBldmVudCA9IGNvbnN0cnVjdEV2ZW50KHBheWxvYWQsIGhlYWRlcnMsIHNlY3JldCk7XG4gICAgICBcbiAgICAgIGV4cGVjdChldmVudC5ldmVudElkKS50b0JlKCdldnRfMTIzJyk7XG4gICAgICBleHBlY3QoZXZlbnQuZGVsaXZlcnlJZCkudG9CZSgnZGx2XzQ1NicpO1xuICAgICAgZXhwZWN0KGV2ZW50LnRpbWVzdGFtcCkudG9CZSh0aW1lc3RhbXApO1xuICAgICAgZXhwZWN0KGV2ZW50LnR5cGUpLnRvQmUoJ29yZGVyLmNvbXBsZXRlZCcpO1xuICAgICAgZXhwZWN0KGV2ZW50LmRhdGEpLnRvRXF1YWwoeyBvcmRlcklkOiAnMTIzNDUnIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBoYW5kbGUgdXBwZXJjYXNlIGhlYWRlcnMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgXG4gICAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgICAnWC1TaWduYXR1cmUnOiBzaWduYXR1cmUsXG4gICAgICAgICdYLVRpbWVzdGFtcCc6IHRpbWVzdGFtcC50b1N0cmluZygpLFxuICAgICAgICAnWC1FdmVudC1JZCc6ICdldnRfMTIzJyxcbiAgICAgICAgJ1gtRGVsaXZlcnktSWQnOiAnZGx2XzQ1NicsXG4gICAgICB9O1xuXG4gICAgICBjb25zdCBldmVudCA9IGNvbnN0cnVjdEV2ZW50KHBheWxvYWQsIGhlYWRlcnMsIHNlY3JldCk7XG4gICAgICBleHBlY3QoZXZlbnQuZXZlbnRJZCkudG9CZSgnZXZ0XzEyMycpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBtaXNzaW5nIHNpZ25hdHVyZSBoZWFkZXInLCAoKSA9PiB7XG4gICAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgICAneC10aW1lc3RhbXAnOiBEYXRlLm5vdygpLnRvU3RyaW5nKCksXG4gICAgICB9O1xuXG4gICAgICBleHBlY3QoKCkgPT4gY29uc3RydWN0RXZlbnQocGF5bG9hZCwgaGVhZGVycywgc2VjcmV0KSlcbiAgICAgICAgLnRvVGhyb3coJ01pc3NpbmcgWC1TaWduYXR1cmUgaGVhZGVyJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIGludmFsaWQgSlNPTiBwYXlsb2FkJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IGludmFsaWRQYXlsb2FkID0gJ25vdCB2YWxpZCBqc29uJztcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKGludmFsaWRQYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSB7XG4gICAgICAgICd4LXNpZ25hdHVyZSc6IHNpZ25hdHVyZSxcbiAgICAgICAgJ3gtdGltZXN0YW1wJzogdGltZXN0YW1wLnRvU3RyaW5nKCksXG4gICAgICB9O1xuXG4gICAgICBleHBlY3QoKCkgPT4gY29uc3RydWN0RXZlbnQoaW52YWxpZFBheWxvYWQsIGhlYWRlcnMsIHNlY3JldCkpXG4gICAgICAgIC50b1Rocm93KCdJbnZhbGlkIEpTT04gcGF5bG9hZCcpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBoYW5kbGUgcGF5bG9hZCB3aXRob3V0IG5lc3RlZCBkYXRhIGZpZWxkJywgKCkgPT4ge1xuICAgICAgY29uc3QgZmxhdFBheWxvYWQgPSBKU09OLnN0cmluZ2lmeSh7IHR5cGU6ICd0ZXN0LmV2ZW50JywgdmFsdWU6IDEyMyB9KTtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShmbGF0UGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgXG4gICAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgICAneC1zaWduYXR1cmUnOiBzaWduYXR1cmUsXG4gICAgICAgICd4LXRpbWVzdGFtcCc6IHRpbWVzdGFtcC50b1N0cmluZygpLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZXZlbnQgPSBjb25zdHJ1Y3RFdmVudChmbGF0UGF5bG9hZCwgaGVhZGVycywgc2VjcmV0KTtcbiAgICAgIGV4cGVjdChldmVudC50eXBlKS50b0JlKCd0ZXN0LmV2ZW50Jyk7XG4gICAgICBleHBlY3QoZXZlbnQuZGF0YSkudG9FcXVhbCh7IHR5cGU6ICd0ZXN0LmV2ZW50JywgdmFsdWU6IDEyMyB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdXNlIGN1cnJlbnQgdGltZXN0YW1wIGlmIG5vdCBwcm92aWRlZCBpbiBoZWFkZXJzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIFxuICAgICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgICAgJ3gtc2lnbmF0dXJlJzogc2lnbmF0dXJlLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZXZlbnQgPSBjb25zdHJ1Y3RFdmVudChwYXlsb2FkLCBoZWFkZXJzLCBzZWNyZXQpO1xuICAgICAgZXhwZWN0KGV2ZW50LnRpbWVzdGFtcCkudG9CZUdyZWF0ZXJUaGFuKDApO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl19
@@ -0,0 +1,48 @@
1
+ import { WebhookPlatformConfig, Event, EventResponse, Endpoint, EndpointCreateParams, EndpointUpdateParams, Subscription, SubscriptionCreateParams, Delivery, DeliveryAttempt, DeliveryListParams, PaginatedResponse, EndpointTestResult } from './types';
2
+ export declare class WebhookPlatform {
3
+ private readonly apiKey;
4
+ private readonly baseUrl;
5
+ private readonly timeout;
6
+ readonly events: Events;
7
+ readonly endpoints: Endpoints;
8
+ readonly subscriptions: Subscriptions;
9
+ readonly deliveries: Deliveries;
10
+ constructor(config: WebhookPlatformConfig);
11
+ request<T>(method: string, path: string, body?: unknown, idempotencyKey?: string): Promise<T>;
12
+ private extractRateLimitInfo;
13
+ private handleError;
14
+ }
15
+ declare class Events {
16
+ private client;
17
+ constructor(client: WebhookPlatform);
18
+ send(event: Event, idempotencyKey?: string): Promise<EventResponse>;
19
+ }
20
+ declare class Endpoints {
21
+ private client;
22
+ constructor(client: WebhookPlatform);
23
+ create(projectId: string, params: EndpointCreateParams): Promise<Endpoint>;
24
+ get(projectId: string, endpointId: string): Promise<Endpoint>;
25
+ list(projectId: string): Promise<Endpoint[]>;
26
+ update(projectId: string, endpointId: string, params: EndpointUpdateParams): Promise<Endpoint>;
27
+ delete(projectId: string, endpointId: string): Promise<void>;
28
+ rotateSecret(projectId: string, endpointId: string): Promise<Endpoint>;
29
+ test(projectId: string, endpointId: string): Promise<EndpointTestResult>;
30
+ }
31
+ declare class Subscriptions {
32
+ private client;
33
+ constructor(client: WebhookPlatform);
34
+ create(projectId: string, params: SubscriptionCreateParams): Promise<Subscription>;
35
+ get(projectId: string, subscriptionId: string): Promise<Subscription>;
36
+ list(projectId: string): Promise<Subscription[]>;
37
+ update(projectId: string, subscriptionId: string, params: Partial<SubscriptionCreateParams>): Promise<Subscription>;
38
+ delete(projectId: string, subscriptionId: string): Promise<void>;
39
+ }
40
+ declare class Deliveries {
41
+ private client;
42
+ constructor(client: WebhookPlatform);
43
+ get(deliveryId: string): Promise<Delivery>;
44
+ list(projectId: string, params?: DeliveryListParams): Promise<PaginatedResponse<Delivery>>;
45
+ getAttempts(deliveryId: string): Promise<DeliveryAttempt[]>;
46
+ replay(deliveryId: string): Promise<void>;
47
+ }
48
+ export {};