@railhook/node 2.12.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.
@@ -0,0 +1,190 @@
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
+ /**
38
+ * After a rotation Railhook signs each delivery with the new secret and the retired one
39
+ * for the endpoint's grace window, so a receiver that has not deployed the new secret yet
40
+ * keeps working. The parser used to keep only the last v1 and rejected whichever half of
41
+ * the pair the receiver was holding.
42
+ */
43
+ describe('a header carrying two signatures (secret rotation)', () => {
44
+ const newSecret = 'whsec_new';
45
+ const retiredSecret = 'whsec_retired';
46
+ const dualHeader = (body, at = Date.now()) => {
47
+ const retiredV1 = (0, webhooks_1.generateSignature)(body, retiredSecret, at).split('v1=')[1];
48
+ return `${(0, webhooks_1.generateSignature)(body, newSecret, at)},v1=${retiredV1}`;
49
+ };
50
+ it('verifies with the new secret', () => {
51
+ expect((0, webhooks_1.verifySignature)(payload, dualHeader(payload), newSecret)).toBe(true);
52
+ });
53
+ it('verifies with the retired secret', () => {
54
+ expect((0, webhooks_1.verifySignature)(payload, dualHeader(payload), retiredSecret)).toBe(true);
55
+ });
56
+ it('still rejects an unrelated secret', () => {
57
+ expect(() => (0, webhooks_1.verifySignature)(payload, dualHeader(payload), 'whsec_someone_else'))
58
+ .toThrow(errors_1.RailhookError);
59
+ });
60
+ it('still rejects a tampered body', () => {
61
+ expect(() => (0, webhooks_1.verifySignature)(`${payload} `, dualHeader(payload), newSecret))
62
+ .toThrow(errors_1.RailhookError);
63
+ });
64
+ });
65
+ describe('verifySignature', () => {
66
+ it('should verify valid signature', () => {
67
+ const timestamp = Date.now();
68
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
69
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret)).toBe(true);
70
+ });
71
+ it('should throw on missing signature', () => {
72
+ expect(() => (0, webhooks_1.verifySignature)(payload, '', secret)).toThrow(errors_1.RailhookError);
73
+ expect(() => (0, webhooks_1.verifySignature)(payload, '', secret)).toThrow('Missing signature header');
74
+ });
75
+ it('should throw on invalid signature format', () => {
76
+ expect(() => (0, webhooks_1.verifySignature)(payload, 'invalid', secret)).toThrow('Invalid signature format');
77
+ });
78
+ it('should throw on missing timestamp', () => {
79
+ expect(() => (0, webhooks_1.verifySignature)(payload, 'v1=abc123', secret)).toThrow('Invalid signature format');
80
+ });
81
+ it('should throw on missing v1 signature', () => {
82
+ expect(() => (0, webhooks_1.verifySignature)(payload, 't=1700000000000', secret)).toThrow('Invalid signature format');
83
+ });
84
+ it('should throw on expired timestamp', () => {
85
+ const oldTimestamp = Date.now() - 600000; // 10 minutes ago
86
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, oldTimestamp);
87
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('outside tolerance window');
88
+ });
89
+ it('should throw on future timestamp outside tolerance', () => {
90
+ const futureTimestamp = Date.now() + 600000; // 10 minutes in future
91
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, futureTimestamp);
92
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('outside tolerance window');
93
+ });
94
+ it('should accept timestamp within tolerance', () => {
95
+ const recentTimestamp = Date.now() - 60000; // 1 minute ago
96
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, recentTimestamp);
97
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret)).toBe(true);
98
+ });
99
+ it('should throw on invalid signature value', () => {
100
+ const timestamp = Date.now();
101
+ const signature = `t=${timestamp},v1=invalid_signature_that_will_not_match`;
102
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret)).toThrow('Invalid signature');
103
+ });
104
+ it('should throw on tampered payload', () => {
105
+ const timestamp = Date.now();
106
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
107
+ const tamperedPayload = JSON.stringify({ type: 'order.cancelled', data: {} });
108
+ expect(() => (0, webhooks_1.verifySignature)(tamperedPayload, signature, secret)).toThrow('Invalid signature');
109
+ });
110
+ it('should respect custom tolerance', () => {
111
+ const oldTimestamp = Date.now() - 60000; // 1 minute ago
112
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, oldTimestamp);
113
+ // Should fail with 30s tolerance
114
+ expect(() => (0, webhooks_1.verifySignature)(payload, signature, secret, { tolerance: 30000 }))
115
+ .toThrow('outside tolerance window');
116
+ // Should pass with 2min tolerance
117
+ expect((0, webhooks_1.verifySignature)(payload, signature, secret, { tolerance: 120000 })).toBe(true);
118
+ });
119
+ });
120
+ describe('constructEvent', () => {
121
+ it('should construct event from valid request', () => {
122
+ const timestamp = Date.now();
123
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
124
+ const headers = {
125
+ 'x-signature': signature,
126
+ 'x-timestamp': timestamp.toString(),
127
+ 'x-event-id': 'evt_123',
128
+ 'x-delivery-id': 'dlv_456',
129
+ };
130
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
131
+ expect(event.eventId).toBe('evt_123');
132
+ expect(event.deliveryId).toBe('dlv_456');
133
+ expect(event.timestamp).toBe(timestamp);
134
+ expect(event.type).toBe('order.completed');
135
+ expect(event.data).toEqual({ orderId: '12345' });
136
+ });
137
+ it('should handle uppercase headers', () => {
138
+ const timestamp = Date.now();
139
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
140
+ const headers = {
141
+ 'X-Signature': signature,
142
+ 'X-Timestamp': timestamp.toString(),
143
+ 'X-Event-Id': 'evt_123',
144
+ 'X-Delivery-Id': 'dlv_456',
145
+ };
146
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
147
+ expect(event.eventId).toBe('evt_123');
148
+ });
149
+ it('should throw on missing signature header', () => {
150
+ const headers = {
151
+ 'x-timestamp': Date.now().toString(),
152
+ };
153
+ expect(() => (0, webhooks_1.constructEvent)(payload, headers, secret))
154
+ .toThrow('Missing X-Signature header');
155
+ });
156
+ it('should throw on invalid JSON payload', () => {
157
+ const timestamp = Date.now();
158
+ const invalidPayload = 'not valid json';
159
+ const signature = (0, webhooks_1.generateSignature)(invalidPayload, secret, timestamp);
160
+ const headers = {
161
+ 'x-signature': signature,
162
+ 'x-timestamp': timestamp.toString(),
163
+ };
164
+ expect(() => (0, webhooks_1.constructEvent)(invalidPayload, headers, secret))
165
+ .toThrow('Invalid JSON payload');
166
+ });
167
+ it('should handle payload without nested data field', () => {
168
+ const flatPayload = JSON.stringify({ type: 'test.event', value: 123 });
169
+ const timestamp = Date.now();
170
+ const signature = (0, webhooks_1.generateSignature)(flatPayload, secret, timestamp);
171
+ const headers = {
172
+ 'x-signature': signature,
173
+ 'x-timestamp': timestamp.toString(),
174
+ };
175
+ const event = (0, webhooks_1.constructEvent)(flatPayload, headers, secret);
176
+ expect(event.type).toBe('test.event');
177
+ expect(event.data).toEqual({ type: 'test.event', value: 123 });
178
+ });
179
+ it('should use current timestamp if not provided in headers', () => {
180
+ const timestamp = Date.now();
181
+ const signature = (0, webhooks_1.generateSignature)(payload, secret, timestamp);
182
+ const headers = {
183
+ 'x-signature': signature,
184
+ };
185
+ const event = (0, webhooks_1.constructEvent)(payload, headers, secret);
186
+ expect(event.timestamp).toBeGreaterThan(0);
187
+ });
188
+ });
189
+ });
190
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid2ViaG9va3MudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9fX3Rlc3RzX18vd2ViaG9va3MudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLDBDQUFpRjtBQUNqRixzQ0FBMEM7QUFFMUMsUUFBUSxDQUFDLGdDQUFnQyxFQUFFLEdBQUcsRUFBRTtJQUM5QyxNQUFNLE1BQU0sR0FBRywyQkFBMkIsQ0FBQztJQUMzQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLEVBQUUsSUFBSSxFQUFFLGlCQUFpQixFQUFFLElBQUksRUFBRSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFFeEYsUUFBUSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRTtRQUNqQyxFQUFFLENBQUMsd0NBQXdDLEVBQUUsR0FBRyxFQUFFO1lBQ2hELE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3JELE1BQU0sQ0FBQyxTQUFTLENBQUMsQ0FBQyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUN2RCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQywrQkFBK0IsRUFBRSxHQUFHLEVBQUU7WUFDdkMsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sU0FBUyxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUNoRSxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUMsU0FBUyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNoRCxDQUFDLENBQUMsQ0FBQztRQUVILEVBQUUsQ0FBQyx1REFBdUQsRUFBRSxHQUFHLEVBQUU7WUFDL0QsTUFBTSxTQUFTLEdBQUcsYUFBYSxDQUFDO1lBQ2hDLE1BQU0sSUFBSSxHQUFHLElBQUEsNEJBQWlCLEVBQUMsT0FB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bmF0dXJlLCBjb25zdHJ1Y3RFdmVudCwgZ2VuZXJhdGVTaWduYXR1cmUgfSBmcm9tICcuLi93ZWJob29rcyc7XG5pbXBvcnQgeyBSYWlsaG9va0Vycm9yIH0gZnJvbSAnLi4vZXJyb3JzJztcblxuZGVzY3JpYmUoJ1dlYmhvb2sgU2lnbmF0dXJlIFZlcmlmaWNhdGlvbicsICgpID0+IHtcbiAgY29uc3Qgc2VjcmV0ID0gJ3doc2VjX3Rlc3Rfc2VjcmV0X2tleV8xMjMnO1xuICBjb25zdCBwYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkoeyB0eXBlOiAnb3JkZXIuY29tcGxldGVkJywgZGF0YTogeyBvcmRlcklkOiAnMTIzNDUnIH0gfSk7XG5cbiAgZGVzY3JpYmUoJ2dlbmVyYXRlU2lnbmF0dXJlJywgKCkgPT4ge1xuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgdmFsaWQgc2lnbmF0dXJlIGZvcm1hdCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCk7XG4gICAgICBleHBlY3Qoc2lnbmF0dXJlKS50b01hdGNoKC9edD1cXGQrLHYxPVthLWYwLTldezY0fSQvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdXNlIHByb3ZpZGVkIHRpbWVzdGFtcCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IDE3MDAwMDAwMDAwMDA7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBleHBlY3Qoc2lnbmF0dXJlKS50b0NvbnRhaW4oYHQ9JHt0aW1lc3RhbXB9YCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGdlbmVyYXRlIGNvbnNpc3RlbnQgc2lnbmF0dXJlcyBmb3Igc2FtZSBpbnB1dHMnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSAxNzAwMDAwMDAwMDAwO1xuICAgICAgY29uc3Qgc2lnMSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGNvbnN0IHNpZzIgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBleHBlY3Qoc2lnMSkudG9CZShzaWcyKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgZGlmZmVyZW50IHNpZ25hdHVyZXMgZm9yIGRpZmZlcmVudCBwYXlsb2FkcycsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IDE3MDAwMDAwMDAwMDA7XG4gICAgICBjb25zdCBzaWcxID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgY29uc3Qgc2lnMiA9IGdlbmVyYXRlU2lnbmF0dXJlKCdkaWZmZXJlbnQgcGF5bG9hZCcsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdChzaWcxKS5ub3QudG9CZShzaWcyKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZ2VuZXJhdGUgZGlmZmVyZW50IHNpZ25hdHVyZXMgZm9yIGRpZmZlcmVudCBzZWNyZXRzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gMTcwMDAwMDAwMDAwMDtcbiAgICAgIGNvbnN0IHNpZzEgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBjb25zdCBzaWcyID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgJ2RpZmZlcmVudF9zZWNyZXQnLCB0aW1lc3RhbXApO1xuICAgICAgZXhwZWN0KHNpZzEpLm5vdC50b0JlKHNpZzIpO1xuICAgIH0pO1xuICB9KTtcblxuICAvKipcbiAgICogQWZ0ZXIgYSByb3RhdGlvbiBSYWlsaG9vayBzaWducyBlYWNoIGRlbGl2ZXJ5IHdpdGggdGhlIG5ldyBzZWNyZXQgYW5kIHRoZSByZXRpcmVkIG9uZVxuICAgKiBmb3IgdGhlIGVuZHBvaW50J3MgZ3JhY2Ugd2luZG93LCBzbyBhIHJlY2VpdmVyIHRoYXQgaGFzIG5vdCBkZXBsb3llZCB0aGUgbmV3IHNlY3JldCB5ZXRcbiAgICoga2VlcHMgd29ya2luZy4gVGhlIHBhcnNlciB1c2VkIHRvIGtlZXAgb25seSB0aGUgbGFzdCB2MSBhbmQgcmVqZWN0ZWQgd2hpY2hldmVyIGhhbGYgb2ZcbiAgICogdGhlIHBhaXIgdGhlIHJlY2VpdmVyIHdhcyBob2xkaW5nLlxuICAgKi9cbiAgZGVzY3JpYmUoJ2EgaGVhZGVyIGNhcnJ5aW5nIHR3byBzaWduYXR1cmVzIChzZWNyZXQgcm90YXRpb24pJywgKCkgPT4ge1xuICAgIGNvbnN0IG5ld1NlY3JldCA9ICd3aHNlY19uZXcnO1xuICAgIGNvbnN0IHJldGlyZWRTZWNyZXQgPSAnd2hzZWNfcmV0aXJlZCc7XG5cbiAgICBjb25zdCBkdWFsSGVhZGVyID0gKGJvZHk6IHN0cmluZywgYXQgPSBEYXRlLm5vdygpKSA9PiB7XG4gICAgICBjb25zdCByZXRpcmVkVjEgPSBnZW5lcmF0ZVNpZ25hdHVyZShib2R5LCByZXRpcmVkU2VjcmV0LCBhdCkuc3BsaXQoJ3YxPScpWzFdO1xuICAgICAgcmV0dXJuIGAke2dlbmVyYXRlU2lnbmF0dXJlKGJvZHksIG5ld1NlY3JldCwgYXQpfSx2MT0ke3JldGlyZWRWMX1gO1xuICAgIH07XG5cbiAgICBpdCgndmVyaWZpZXMgd2l0aCB0aGUgbmV3IHNlY3JldCcsICgpID0+IHtcbiAgICAgIGV4cGVjdCh2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgZHVhbEhlYWRlcihwYXlsb2FkKSwgbmV3U2VjcmV0KSkudG9CZSh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCd2ZXJpZmllcyB3aXRoIHRoZSByZXRpcmVkIHNlY3JldCcsICgpID0+IHtcbiAgICAgIGV4cGVjdCh2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgZHVhbEhlYWRlcihwYXlsb2FkKSwgcmV0aXJlZFNlY3JldCkpLnRvQmUodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc3RpbGwgcmVqZWN0cyBhbiB1bnJlbGF0ZWQgc2VjcmV0JywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCBkdWFsSGVhZGVyKHBheWxvYWQpLCAnd2hzZWNfc29tZW9uZV9lbHNlJykpXG4gICAgICAgIC50b1Rocm93KFJhaWxob29rRXJyb3IpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3N0aWxsIHJlamVjdHMgYSB0YW1wZXJlZCBib2R5JywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShgJHtwYXlsb2FkfSBgLCBkdWFsSGVhZGVyKHBheWxvYWQpLCBuZXdTZWNyZXQpKVxuICAgICAgICAudG9UaHJvdyhSYWlsaG9va0Vycm9yKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3ZlcmlmeVNpZ25hdHVyZScsICgpID0+IHtcbiAgICBpdCgnc2hvdWxkIHZlcmlmeSB2YWxpZCBzaWduYXR1cmUnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgZXhwZWN0KHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCBzaWduYXR1cmUsIHNlY3JldCkpLnRvQmUodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIG1pc3Npbmcgc2lnbmF0dXJlJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCAnJywgc2VjcmV0KSkudG9UaHJvdyhSYWlsaG9va0Vycm9yKTtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgJycsIHNlY3JldCkpLnRvVGhyb3coJ01pc3Npbmcgc2lnbmF0dXJlIGhlYWRlcicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBpbnZhbGlkIHNpZ25hdHVyZSBmb3JtYXQnLCAoKSA9PiB7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsICdpbnZhbGlkJywgc2VjcmV0KSkudG9UaHJvdygnSW52YWxpZCBzaWduYXR1cmUgZm9ybWF0Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIG1pc3NpbmcgdGltZXN0YW1wJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCAndjE9YWJjMTIzJywgc2VjcmV0KSkudG9UaHJvdygnSW52YWxpZCBzaWduYXR1cmUgZm9ybWF0Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIG1pc3NpbmcgdjEgc2lnbmF0dXJlJywgKCkgPT4ge1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCAndD0xNzAwMDAwMDAwMDAwJywgc2VjcmV0KSkudG9UaHJvdygnSW52YWxpZCBzaWduYXR1cmUgZm9ybWF0Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIGV4cGlyZWQgdGltZXN0YW1wJywgKCkgPT4ge1xuICAgICAgY29uc3Qgb2xkVGltZXN0YW1wID0gRGF0ZS5ub3coKSAtIDYwMDAwMDsgLy8gMTAgbWludXRlcyBhZ29cbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgb2xkVGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQpKS50b1Rocm93KCdvdXRzaWRlIHRvbGVyYW5jZSB3aW5kb3cnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gZnV0dXJlIHRpbWVzdGFtcCBvdXRzaWRlIHRvbGVyYW5jZScsICgpID0+IHtcbiAgICAgIGNvbnN0IGZ1dHVyZVRpbWVzdGFtcCA9IERhdGUubm93KCkgKyA2MDAwMDA7IC8vIDEwIG1pbnV0ZXMgaW4gZnV0dXJlXG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIGZ1dHVyZVRpbWVzdGFtcCk7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsIHNpZ25hdHVyZSwgc2VjcmV0KSkudG9UaHJvdygnb3V0c2lkZSB0b2xlcmFuY2Ugd2luZG93Jyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFjY2VwdCB0aW1lc3RhbXAgd2l0aGluIHRvbGVyYW5jZScsICgpID0+IHtcbiAgICAgIGNvbnN0IHJlY2VudFRpbWVzdGFtcCA9IERhdGUubm93KCkgLSA2MDAwMDsgLy8gMSBtaW51dGUgYWdvXG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHJlY2VudFRpbWVzdGFtcCk7XG4gICAgICBleHBlY3QodmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsIHNpZ25hdHVyZSwgc2VjcmV0KSkudG9CZSh0cnVlKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gaW52YWxpZCBzaWduYXR1cmUgdmFsdWUnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gYHQ9JHt0aW1lc3RhbXB9LHYxPWludmFsaWRfc2lnbmF0dXJlX3RoYXRfd2lsbF9ub3RfbWF0Y2hgO1xuICAgICAgZXhwZWN0KCgpID0+IHZlcmlmeVNpZ25hdHVyZShwYXlsb2FkLCBzaWduYXR1cmUsIHNlY3JldCkpLnRvVGhyb3coJ0ludmFsaWQgc2lnbmF0dXJlJyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHRocm93IG9uIHRhbXBlcmVkIHBheWxvYWQnLCAoKSA9PiB7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgY29uc3QgdGFtcGVyZWRQYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkoeyB0eXBlOiAnb3JkZXIuY2FuY2VsbGVkJywgZGF0YToge30gfSk7XG4gICAgICBleHBlY3QoKCkgPT4gdmVyaWZ5U2lnbmF0dXJlKHRhbXBlcmVkUGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQpKS50b1Rocm93KCdJbnZhbGlkIHNpZ25hdHVyZScpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXNwZWN0IGN1c3RvbSB0b2xlcmFuY2UnLCAoKSA9PiB7XG4gICAgICBjb25zdCBvbGRUaW1lc3RhbXAgPSBEYXRlLm5vdygpIC0gNjAwMDA7IC8vIDEgbWludXRlIGFnb1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUocGF5bG9hZCwgc2VjcmV0LCBvbGRUaW1lc3RhbXApO1xuICAgICAgXG4gICAgICAvLyBTaG91bGQgZmFpbCB3aXRoIDMwcyB0b2xlcmFuY2VcbiAgICAgIGV4cGVjdCgoKSA9PiB2ZXJpZnlTaWduYXR1cmUocGF5bG9hZCwgc2lnbmF0dXJlLCBzZWNyZXQsIHsgdG9sZXJhbmNlOiAzMDAwMCB9KSlcbiAgICAgICAgLnRvVGhyb3coJ291dHNpZGUgdG9sZXJhbmNlIHdpbmRvdycpO1xuICAgICAgXG4gICAgICAvLyBTaG91bGQgcGFzcyB3aXRoIDJtaW4gdG9sZXJhbmNlXG4gICAgICBleHBlY3QodmVyaWZ5U2lnbmF0dXJlKHBheWxvYWQsIHNpZ25hdHVyZSwgc2VjcmV0LCB7IHRvbGVyYW5jZTogMTIwMDAwIH0pKS50b0JlKHRydWUpO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY29uc3RydWN0RXZlbnQnLCAoKSA9PiB7XG4gICAgaXQoJ3Nob3VsZCBjb25zdHJ1Y3QgZXZlbnQgZnJvbSB2YWxpZCByZXF1ZXN0JywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIFxuICAgICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgICAgJ3gtc2lnbmF0dXJlJzogc2lnbmF0dXJlLFxuICAgICAgICAneC10aW1lc3RhbXAnOiB0aW1lc3RhbXAudG9TdHJpbmcoKSxcbiAgICAgICAgJ3gtZXZlbnQtaWQnOiAnZXZ0XzEyMycsXG4gICAgICAgICd4LWRlbGl2ZXJ5LWlkJzogJ2Rsdl80NTYnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZXZlbnQgPSBjb25zdHJ1Y3RFdmVudChwYXlsb2FkLCBoZWFkZXJzLCBzZWNyZXQpO1xuICAgICAgXG4gICAgICBleHBlY3QoZXZlbnQuZXZlbnRJZCkudG9CZSgnZXZ0XzEyMycpO1xuICAgICAgZXhwZWN0KGV2ZW50LmRlbGl2ZXJ5SWQpLnRvQmUoJ2Rsdl80NTYnKTtcbiAgICAgIGV4cGVjdChldmVudC50aW1lc3RhbXApLnRvQmUodGltZXN0YW1wKTtcbiAgICAgIGV4cGVjdChldmVudC50eXBlKS50b0JlKCdvcmRlci5jb21wbGV0ZWQnKTtcbiAgICAgIGV4cGVjdChldmVudC5kYXRhKS50b0VxdWFsKHsgb3JkZXJJZDogJzEyMzQ1JyB9KTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgaGFuZGxlIHVwcGVyY2FzZSBoZWFkZXJzJywgKCkgPT4ge1xuICAgICAgY29uc3QgdGltZXN0YW1wID0gRGF0ZS5ub3coKTtcbiAgICAgIGNvbnN0IHNpZ25hdHVyZSA9IGdlbmVyYXRlU2lnbmF0dXJlKHBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIFxuICAgICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgICAgJ1gtU2lnbmF0dXJlJzogc2lnbmF0dXJlLFxuICAgICAgICAnWC1UaW1lc3RhbXAnOiB0aW1lc3RhbXAudG9TdHJpbmcoKSxcbiAgICAgICAgJ1gtRXZlbnQtSWQnOiAnZXZ0XzEyMycsXG4gICAgICAgICdYLURlbGl2ZXJ5LUlkJzogJ2Rsdl80NTYnLFxuICAgICAgfTtcblxuICAgICAgY29uc3QgZXZlbnQgPSBjb25zdHJ1Y3RFdmVudChwYXlsb2FkLCBoZWFkZXJzLCBzZWNyZXQpO1xuICAgICAgZXhwZWN0KGV2ZW50LmV2ZW50SWQpLnRvQmUoJ2V2dF8xMjMnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgb24gbWlzc2luZyBzaWduYXR1cmUgaGVhZGVyJywgKCkgPT4ge1xuICAgICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgICAgJ3gtdGltZXN0YW1wJzogRGF0ZS5ub3coKS50b1N0cmluZygpLFxuICAgICAgfTtcblxuICAgICAgZXhwZWN0KCgpID0+IGNvbnN0cnVjdEV2ZW50KHBheWxvYWQsIGhlYWRlcnMsIHNlY3JldCkpXG4gICAgICAgIC50b1Rocm93KCdNaXNzaW5nIFgtU2lnbmF0dXJlIGhlYWRlcicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBvbiBpbnZhbGlkIEpTT04gcGF5bG9hZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBpbnZhbGlkUGF5bG9hZCA9ICdub3QgdmFsaWQganNvbic7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShpbnZhbGlkUGF5bG9hZCwgc2VjcmV0LCB0aW1lc3RhbXApO1xuICAgICAgXG4gICAgICBjb25zdCBoZWFkZXJzID0ge1xuICAgICAgICAneC1zaWduYXR1cmUnOiBzaWduYXR1cmUsXG4gICAgICAgICd4LXRpbWVzdGFtcCc6IHRpbWVzdGFtcC50b1N0cmluZygpLFxuICAgICAgfTtcblxuICAgICAgZXhwZWN0KCgpID0+IGNvbnN0cnVjdEV2ZW50KGludmFsaWRQYXlsb2FkLCBoZWFkZXJzLCBzZWNyZXQpKVxuICAgICAgICAudG9UaHJvdygnSW52YWxpZCBKU09OIHBheWxvYWQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgaGFuZGxlIHBheWxvYWQgd2l0aG91dCBuZXN0ZWQgZGF0YSBmaWVsZCcsICgpID0+IHtcbiAgICAgIGNvbnN0IGZsYXRQYXlsb2FkID0gSlNPTi5zdHJpbmdpZnkoeyB0eXBlOiAndGVzdC5ldmVudCcsIHZhbHVlOiAxMjMgfSk7XG4gICAgICBjb25zdCB0aW1lc3RhbXAgPSBEYXRlLm5vdygpO1xuICAgICAgY29uc3Qgc2lnbmF0dXJlID0gZ2VuZXJhdGVTaWduYXR1cmUoZmxhdFBheWxvYWQsIHNlY3JldCwgdGltZXN0YW1wKTtcbiAgICAgIFxuICAgICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgICAgJ3gtc2lnbmF0dXJlJzogc2lnbmF0dXJlLFxuICAgICAgICAneC10aW1lc3RhbXAnOiB0aW1lc3RhbXAudG9TdHJpbmcoKSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGV2ZW50ID0gY29uc3RydWN0RXZlbnQoZmxhdFBheWxvYWQsIGhlYWRlcnMsIHNlY3JldCk7XG4gICAgICBleHBlY3QoZXZlbnQudHlwZSkudG9CZSgndGVzdC5ldmVudCcpO1xuICAgICAgZXhwZWN0KGV2ZW50LmRhdGEpLnRvRXF1YWwoeyB0eXBlOiAndGVzdC5ldmVudCcsIHZhbHVlOiAxMjMgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHVzZSBjdXJyZW50IHRpbWVzdGFtcCBpZiBub3QgcHJvdmlkZWQgaW4gaGVhZGVycycsICgpID0+IHtcbiAgICAgIGNvbnN0IHRpbWVzdGFtcCA9IERhdGUubm93KCk7XG4gICAgICBjb25zdCBzaWduYXR1cmUgPSBnZW5lcmF0ZVNpZ25hdHVyZShwYXlsb2FkLCBzZWNyZXQsIHRpbWVzdGFtcCk7XG4gICAgICBcbiAgICAgIGNvbnN0IGhlYWRlcnMgPSB7XG4gICAgICAgICd4LXNpZ25hdHVyZSc6IHNpZ25hdHVyZSxcbiAgICAgIH07XG5cbiAgICAgIGNvbnN0IGV2ZW50ID0gY29uc3RydWN0RXZlbnQocGF5bG9hZCwgaGVhZGVycywgc2VjcmV0KTtcbiAgICAgIGV4cGVjdChldmVudC50aW1lc3RhbXApLnRvQmVHcmVhdGVyVGhhbigwKTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdfQ==
@@ -0,0 +1,103 @@
1
+ import { RailhookConfig, Event, EventResponse, Endpoint, EndpointCreateParams, EndpointUpdateParams, EndpointListParams, Subscription, SubscriptionCreateParams, Delivery, DeliveryAttempt, DeliveryListParams, PaginatedResponse, EndpointTestResult, IncomingSource, IncomingSourceCreateParams, IncomingSourceUpdateParams, IncomingDestination, IncomingDestinationCreateParams, IncomingDestinationUpdateParams, IncomingEvent, IncomingEventListParams, IncomingForwardAttempt, ReplayEventResponse } from './types';
2
+ export declare class Railhook {
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
+ readonly incomingSources: IncomingSources;
11
+ readonly incomingEvents: IncomingEvents;
12
+ constructor(config: RailhookConfig);
13
+ request<T>(method: string, path: string, body?: unknown, idempotencyKey?: string): Promise<T>;
14
+ /**
15
+ * Generic GET request to any API path.
16
+ * Use this for endpoints not yet covered by the SDK.
17
+ */
18
+ get<T = unknown>(path: string): Promise<T>;
19
+ /**
20
+ * Generic POST request to any API path.
21
+ * Use this for endpoints not yet covered by the SDK.
22
+ */
23
+ post<T = unknown>(path: string, body?: unknown, idempotencyKey?: string): Promise<T>;
24
+ /**
25
+ * Generic PUT request to any API path.
26
+ * Use this for endpoints not yet covered by the SDK.
27
+ */
28
+ put<T = unknown>(path: string, body?: unknown): Promise<T>;
29
+ /**
30
+ * Generic PATCH request to any API path.
31
+ * Use this for endpoints not yet covered by the SDK.
32
+ */
33
+ patch<T = unknown>(path: string, body?: unknown): Promise<T>;
34
+ /**
35
+ * Generic DELETE request to any API path.
36
+ * Use this for endpoints not yet covered by the SDK.
37
+ */
38
+ delete<T = void>(path: string): Promise<T>;
39
+ private extractRateLimitInfo;
40
+ private handleError;
41
+ }
42
+ declare class Events {
43
+ private client;
44
+ constructor(client: Railhook);
45
+ send(event: Event, idempotencyKey?: string): Promise<EventResponse>;
46
+ }
47
+ declare class Endpoints {
48
+ private client;
49
+ constructor(client: Railhook);
50
+ create(projectId: string, params: EndpointCreateParams): Promise<Endpoint>;
51
+ get(projectId: string, endpointId: string): Promise<Endpoint>;
52
+ /**
53
+ * Lists a project's endpoints.
54
+ *
55
+ * The API returns a Spring page envelope here, not a bare array — the
56
+ * endpoints themselves are in `.content`.
57
+ */
58
+ list(projectId: string, params?: EndpointListParams): Promise<PaginatedResponse<Endpoint>>;
59
+ update(projectId: string, endpointId: string, params: EndpointUpdateParams): Promise<Endpoint>;
60
+ delete(projectId: string, endpointId: string): Promise<void>;
61
+ rotateSecret(projectId: string, endpointId: string): Promise<Endpoint>;
62
+ test(projectId: string, endpointId: string): Promise<EndpointTestResult>;
63
+ }
64
+ declare class Subscriptions {
65
+ private client;
66
+ constructor(client: Railhook);
67
+ create(projectId: string, params: SubscriptionCreateParams): Promise<Subscription>;
68
+ get(projectId: string, subscriptionId: string): Promise<Subscription>;
69
+ list(projectId: string): Promise<Subscription[]>;
70
+ update(projectId: string, subscriptionId: string, params: Partial<SubscriptionCreateParams>): Promise<Subscription>;
71
+ delete(projectId: string, subscriptionId: string): Promise<void>;
72
+ }
73
+ declare class Deliveries {
74
+ private client;
75
+ constructor(client: Railhook);
76
+ get(deliveryId: string): Promise<Delivery>;
77
+ list(projectId: string, params?: DeliveryListParams): Promise<PaginatedResponse<Delivery>>;
78
+ getAttempts(deliveryId: string): Promise<DeliveryAttempt[]>;
79
+ replay(deliveryId: string): Promise<void>;
80
+ }
81
+ declare class IncomingSources {
82
+ private client;
83
+ constructor(client: Railhook);
84
+ create(projectId: string, params: IncomingSourceCreateParams): Promise<IncomingSource>;
85
+ get(projectId: string, sourceId: string): Promise<IncomingSource>;
86
+ list(projectId: string): Promise<PaginatedResponse<IncomingSource>>;
87
+ update(projectId: string, sourceId: string, params: IncomingSourceUpdateParams): Promise<IncomingSource>;
88
+ delete(projectId: string, sourceId: string): Promise<void>;
89
+ createDestination(projectId: string, sourceId: string, params: IncomingDestinationCreateParams): Promise<IncomingDestination>;
90
+ getDestination(projectId: string, sourceId: string, destinationId: string): Promise<IncomingDestination>;
91
+ listDestinations(projectId: string, sourceId: string): Promise<PaginatedResponse<IncomingDestination>>;
92
+ updateDestination(projectId: string, sourceId: string, destinationId: string, params: IncomingDestinationUpdateParams): Promise<IncomingDestination>;
93
+ deleteDestination(projectId: string, sourceId: string, destinationId: string): Promise<void>;
94
+ }
95
+ declare class IncomingEvents {
96
+ private client;
97
+ constructor(client: Railhook);
98
+ list(projectId: string, params?: IncomingEventListParams): Promise<PaginatedResponse<IncomingEvent>>;
99
+ get(projectId: string, eventId: string): Promise<IncomingEvent>;
100
+ getAttempts(projectId: string, eventId: string): Promise<PaginatedResponse<IncomingForwardAttempt>>;
101
+ replay(projectId: string, eventId: string): Promise<ReplayEventResponse>;
102
+ }
103
+ export {};