@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.
- package/README.md +476 -0
- package/dist/__tests__/client.test.d.ts +1 -0
- package/dist/__tests__/client.test.js +105 -0
- package/dist/__tests__/incoming.test.d.ts +1 -0
- package/dist/__tests__/incoming.test.js +316 -0
- package/dist/__tests__/package-identity.test.d.ts +1 -0
- package/dist/__tests__/package-identity.test.js +19 -0
- package/dist/__tests__/standardWebhooks.test.d.ts +1 -0
- package/dist/__tests__/standardWebhooks.test.js +102 -0
- package/dist/__tests__/webhooks.test.d.ts +1 -0
- package/dist/__tests__/webhooks.test.js +190 -0
- package/dist/client.d.ts +103 -0
- package/dist/client.js +344 -0
- package/dist/errors.d.ts +28 -0
- package/dist/errors.js +53 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +37 -0
- package/dist/types.d.ts +293 -0
- package/dist/types.js +3 -0
- package/dist/webhooks.d.ts +83 -0
- package/dist/webhooks.js +241 -0
- package/package.json +47 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
export interface RailhookConfig {
|
|
2
|
+
apiKey: string;
|
|
3
|
+
baseUrl?: string;
|
|
4
|
+
timeout?: number;
|
|
5
|
+
}
|
|
6
|
+
export interface Event {
|
|
7
|
+
type: string;
|
|
8
|
+
data: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface EventResponse {
|
|
11
|
+
eventId: string;
|
|
12
|
+
type: string;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
deliveriesCreated: number;
|
|
15
|
+
/**
|
|
16
|
+
* Schema-validation errors this event was accepted despite, when the project has schema
|
|
17
|
+
* validation on with the WARN policy. Absent when the payload matched or validation is off.
|
|
18
|
+
*/
|
|
19
|
+
schemaWarnings?: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface Endpoint {
|
|
22
|
+
id: string;
|
|
23
|
+
projectId: string;
|
|
24
|
+
url: string;
|
|
25
|
+
description?: string;
|
|
26
|
+
secret?: string;
|
|
27
|
+
enabled: boolean;
|
|
28
|
+
rateLimitPerSecond?: number;
|
|
29
|
+
allowedSourceIps?: string;
|
|
30
|
+
mtlsEnabled?: boolean;
|
|
31
|
+
verificationStatus?: string;
|
|
32
|
+
verificationAttemptedAt?: string;
|
|
33
|
+
verificationCompletedAt?: string;
|
|
34
|
+
verificationSkipReason?: string;
|
|
35
|
+
createdAt: string;
|
|
36
|
+
updatedAt?: string;
|
|
37
|
+
}
|
|
38
|
+
export interface EndpointCreateParams {
|
|
39
|
+
url: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
/** Supply your own signing secret. Omit to have the API generate one. */
|
|
42
|
+
secret?: string;
|
|
43
|
+
enabled?: boolean;
|
|
44
|
+
rateLimitPerSecond?: number;
|
|
45
|
+
/** Comma-separated CIDRs the endpoint is allowed to be reached from. */
|
|
46
|
+
allowedSourceIps?: string;
|
|
47
|
+
}
|
|
48
|
+
export interface EndpointUpdateParams {
|
|
49
|
+
url?: string;
|
|
50
|
+
description?: string;
|
|
51
|
+
secret?: string;
|
|
52
|
+
enabled?: boolean;
|
|
53
|
+
rateLimitPerSecond?: number;
|
|
54
|
+
allowedSourceIps?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface Subscription {
|
|
57
|
+
id: string;
|
|
58
|
+
projectId: string;
|
|
59
|
+
endpointId: string;
|
|
60
|
+
eventType: string;
|
|
61
|
+
enabled: boolean;
|
|
62
|
+
orderingEnabled: boolean;
|
|
63
|
+
maxAttempts: number;
|
|
64
|
+
timeoutSeconds: number;
|
|
65
|
+
retryDelays?: string;
|
|
66
|
+
payloadTemplate?: string;
|
|
67
|
+
customHeaders?: string;
|
|
68
|
+
transformationId?: string;
|
|
69
|
+
transformationName?: string;
|
|
70
|
+
createdAt: string;
|
|
71
|
+
updatedAt?: string;
|
|
72
|
+
}
|
|
73
|
+
export interface SubscriptionCreateParams {
|
|
74
|
+
endpointId: string;
|
|
75
|
+
eventType: string;
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
orderingEnabled?: boolean;
|
|
78
|
+
maxAttempts?: number;
|
|
79
|
+
timeoutSeconds?: number;
|
|
80
|
+
retryDelays?: string;
|
|
81
|
+
payloadTemplate?: string;
|
|
82
|
+
customHeaders?: string;
|
|
83
|
+
transformationId?: string;
|
|
84
|
+
}
|
|
85
|
+
export interface Delivery {
|
|
86
|
+
id: string;
|
|
87
|
+
eventId: string;
|
|
88
|
+
endpointId: string;
|
|
89
|
+
subscriptionId: string;
|
|
90
|
+
status: DeliveryStatus;
|
|
91
|
+
attemptCount: number;
|
|
92
|
+
maxAttempts: number;
|
|
93
|
+
nextRetryAt?: string;
|
|
94
|
+
lastAttemptAt?: string;
|
|
95
|
+
succeededAt?: string;
|
|
96
|
+
failedAt?: string;
|
|
97
|
+
createdAt: string;
|
|
98
|
+
}
|
|
99
|
+
export type DeliveryStatus = 'PENDING' | 'PROCESSING' | 'SUCCESS' | 'FAILED' | 'DLQ';
|
|
100
|
+
export interface DeliveryAttempt {
|
|
101
|
+
id: string;
|
|
102
|
+
deliveryId: string;
|
|
103
|
+
attemptNumber: number;
|
|
104
|
+
/** JSON object, serialized as a string, of the headers that were sent. */
|
|
105
|
+
requestHeaders?: string;
|
|
106
|
+
requestBody?: string;
|
|
107
|
+
httpStatusCode?: number;
|
|
108
|
+
/** JSON object, serialized as a string, of the headers that came back. */
|
|
109
|
+
responseHeaders?: string;
|
|
110
|
+
responseBody?: string;
|
|
111
|
+
errorMessage?: string;
|
|
112
|
+
/** Wall-clock duration of the HTTP request, in milliseconds. */
|
|
113
|
+
durationMs?: number;
|
|
114
|
+
/** When the attempt was recorded. */
|
|
115
|
+
createdAt: string;
|
|
116
|
+
}
|
|
117
|
+
export interface PaginatedResponse<T> {
|
|
118
|
+
content: T[];
|
|
119
|
+
totalElements: number;
|
|
120
|
+
totalPages: number;
|
|
121
|
+
/** Page size requested. */
|
|
122
|
+
size: number;
|
|
123
|
+
/** Zero-based index of this page. */
|
|
124
|
+
number: number;
|
|
125
|
+
numberOfElements?: number;
|
|
126
|
+
first?: boolean;
|
|
127
|
+
last?: boolean;
|
|
128
|
+
empty?: boolean;
|
|
129
|
+
}
|
|
130
|
+
export interface EndpointListParams {
|
|
131
|
+
page?: number;
|
|
132
|
+
size?: number;
|
|
133
|
+
}
|
|
134
|
+
export interface DeliveryListParams {
|
|
135
|
+
status?: DeliveryStatus;
|
|
136
|
+
endpointId?: string;
|
|
137
|
+
fromDate?: string;
|
|
138
|
+
toDate?: string;
|
|
139
|
+
page?: number;
|
|
140
|
+
size?: number;
|
|
141
|
+
}
|
|
142
|
+
export interface EndpointTestResult {
|
|
143
|
+
success: boolean;
|
|
144
|
+
httpStatusCode?: number;
|
|
145
|
+
responseBody?: string;
|
|
146
|
+
errorMessage?: string;
|
|
147
|
+
latencyMs: number;
|
|
148
|
+
/** Human-readable summary, e.g. "Endpoint returned non-2xx status". */
|
|
149
|
+
message?: string;
|
|
150
|
+
}
|
|
151
|
+
export interface RateLimitInfo {
|
|
152
|
+
limit: number;
|
|
153
|
+
remaining: number;
|
|
154
|
+
/**
|
|
155
|
+
* Unix timestamp in **seconds** at which the window resets — the raw value
|
|
156
|
+
* of the `X-RateLimit-Reset` header, which the API sends in seconds, not
|
|
157
|
+
* milliseconds.
|
|
158
|
+
*/
|
|
159
|
+
reset: number;
|
|
160
|
+
}
|
|
161
|
+
export interface WebhookEvent {
|
|
162
|
+
eventId: string;
|
|
163
|
+
deliveryId: string;
|
|
164
|
+
timestamp: number;
|
|
165
|
+
type: string;
|
|
166
|
+
data: Record<string, unknown>;
|
|
167
|
+
}
|
|
168
|
+
export type ProviderType = 'GENERIC' | 'GITHUB' | 'GITLAB' | 'STRIPE' | 'SHOPIFY' | 'SLACK' | 'TWILIO';
|
|
169
|
+
export type VerificationMode = 'NONE' | 'HMAC_GENERIC';
|
|
170
|
+
export type IncomingSourceStatus = 'ACTIVE' | 'DISABLED';
|
|
171
|
+
export type IncomingAuthType = 'NONE' | 'BEARER' | 'BASIC' | 'CUSTOM_HEADER';
|
|
172
|
+
export interface IncomingSource {
|
|
173
|
+
id: string;
|
|
174
|
+
projectId: string;
|
|
175
|
+
name: string;
|
|
176
|
+
slug: string;
|
|
177
|
+
providerType: ProviderType;
|
|
178
|
+
status: IncomingSourceStatus;
|
|
179
|
+
ingressPathToken: string;
|
|
180
|
+
ingressUrl: string;
|
|
181
|
+
verificationMode: VerificationMode;
|
|
182
|
+
hmacHeaderName?: string;
|
|
183
|
+
hmacSignaturePrefix?: string;
|
|
184
|
+
hmacSecretConfigured: boolean;
|
|
185
|
+
rateLimitPerSecond?: number;
|
|
186
|
+
createdAt: string;
|
|
187
|
+
updatedAt?: string;
|
|
188
|
+
}
|
|
189
|
+
export interface IncomingSourceCreateParams {
|
|
190
|
+
name: string;
|
|
191
|
+
slug?: string;
|
|
192
|
+
providerType?: ProviderType;
|
|
193
|
+
verificationMode?: VerificationMode;
|
|
194
|
+
hmacSecret?: string;
|
|
195
|
+
hmacHeaderName?: string;
|
|
196
|
+
hmacSignaturePrefix?: string;
|
|
197
|
+
rateLimitPerSecond?: number;
|
|
198
|
+
}
|
|
199
|
+
export interface IncomingSourceUpdateParams {
|
|
200
|
+
name?: string;
|
|
201
|
+
slug?: string;
|
|
202
|
+
providerType?: ProviderType;
|
|
203
|
+
status?: IncomingSourceStatus;
|
|
204
|
+
verificationMode?: VerificationMode;
|
|
205
|
+
hmacSecret?: string;
|
|
206
|
+
hmacHeaderName?: string;
|
|
207
|
+
hmacSignaturePrefix?: string;
|
|
208
|
+
rateLimitPerSecond?: number;
|
|
209
|
+
}
|
|
210
|
+
export interface IncomingDestination {
|
|
211
|
+
id: string;
|
|
212
|
+
incomingSourceId: string;
|
|
213
|
+
url: string;
|
|
214
|
+
authType: IncomingAuthType;
|
|
215
|
+
authConfigured: boolean;
|
|
216
|
+
customHeadersJson?: string;
|
|
217
|
+
enabled: boolean;
|
|
218
|
+
maxAttempts: number;
|
|
219
|
+
timeoutSeconds: number;
|
|
220
|
+
retryDelays?: string;
|
|
221
|
+
payloadTransform?: string;
|
|
222
|
+
transformationId?: string;
|
|
223
|
+
transformationName?: string;
|
|
224
|
+
createdAt: string;
|
|
225
|
+
updatedAt?: string;
|
|
226
|
+
}
|
|
227
|
+
export interface IncomingDestinationCreateParams {
|
|
228
|
+
url: string;
|
|
229
|
+
authType?: IncomingAuthType;
|
|
230
|
+
authConfig?: string;
|
|
231
|
+
customHeadersJson?: string;
|
|
232
|
+
enabled?: boolean;
|
|
233
|
+
maxAttempts?: number;
|
|
234
|
+
timeoutSeconds?: number;
|
|
235
|
+
retryDelays?: string;
|
|
236
|
+
payloadTransform?: string;
|
|
237
|
+
}
|
|
238
|
+
export interface IncomingDestinationUpdateParams {
|
|
239
|
+
url?: string;
|
|
240
|
+
authType?: IncomingAuthType;
|
|
241
|
+
authConfig?: string;
|
|
242
|
+
customHeadersJson?: string;
|
|
243
|
+
enabled?: boolean;
|
|
244
|
+
maxAttempts?: number;
|
|
245
|
+
timeoutSeconds?: number;
|
|
246
|
+
retryDelays?: string;
|
|
247
|
+
payloadTransform?: string;
|
|
248
|
+
}
|
|
249
|
+
export interface IncomingEvent {
|
|
250
|
+
id: string;
|
|
251
|
+
incomingSourceId: string;
|
|
252
|
+
sourceName: string;
|
|
253
|
+
requestId: string;
|
|
254
|
+
method: string;
|
|
255
|
+
path: string;
|
|
256
|
+
queryParams?: string;
|
|
257
|
+
headersJson?: string;
|
|
258
|
+
bodyRaw?: string;
|
|
259
|
+
bodySha256?: string;
|
|
260
|
+
contentType?: string;
|
|
261
|
+
clientIp?: string;
|
|
262
|
+
userAgent?: string;
|
|
263
|
+
verified?: boolean;
|
|
264
|
+
verificationError?: string;
|
|
265
|
+
receivedAt: string;
|
|
266
|
+
}
|
|
267
|
+
export interface IncomingEventListParams {
|
|
268
|
+
sourceId?: string;
|
|
269
|
+
page?: number;
|
|
270
|
+
size?: number;
|
|
271
|
+
}
|
|
272
|
+
export type ForwardAttemptStatus = 'PENDING' | 'PROCESSING' | 'SUCCESS' | 'FAILED' | 'DLQ';
|
|
273
|
+
export interface IncomingForwardAttempt {
|
|
274
|
+
id: string;
|
|
275
|
+
incomingEventId: string;
|
|
276
|
+
destinationId: string;
|
|
277
|
+
destinationUrl: string;
|
|
278
|
+
attemptNumber: number;
|
|
279
|
+
status: ForwardAttemptStatus;
|
|
280
|
+
startedAt?: string;
|
|
281
|
+
finishedAt?: string;
|
|
282
|
+
responseCode?: number;
|
|
283
|
+
responseHeadersJson?: string;
|
|
284
|
+
responseBodySnippet?: string;
|
|
285
|
+
errorMessage?: string;
|
|
286
|
+
nextRetryAt?: string;
|
|
287
|
+
createdAt: string;
|
|
288
|
+
}
|
|
289
|
+
export interface ReplayEventResponse {
|
|
290
|
+
status: string;
|
|
291
|
+
eventId: string;
|
|
292
|
+
destinationsCount: number;
|
|
293
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IiIsInNvdXJjZXNDb250ZW50IjpbImV4cG9ydCBpbnRlcmZhY2UgUmFpbGhvb2tDb25maWcge1xuICBhcGlLZXk6IHN0cmluZztcbiAgYmFzZVVybD86IHN0cmluZztcbiAgdGltZW91dD86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmVudCB7XG4gIHR5cGU6IHN0cmluZztcbiAgZGF0YTogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZlbnRSZXNwb25zZSB7XG4gIGV2ZW50SWQ6IHN0cmluZztcbiAgdHlwZTogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbiAgZGVsaXZlcmllc0NyZWF0ZWQ6IG51bWJlcjtcbiAgLyoqXG4gICAqIFNjaGVtYS12YWxpZGF0aW9uIGVycm9ycyB0aGlzIGV2ZW50IHdhcyBhY2NlcHRlZCBkZXNwaXRlLCB3aGVuIHRoZSBwcm9qZWN0IGhhcyBzY2hlbWFcbiAgICogdmFsaWRhdGlvbiBvbiB3aXRoIHRoZSBXQVJOIHBvbGljeS4gQWJzZW50IHdoZW4gdGhlIHBheWxvYWQgbWF0Y2hlZCBvciB2YWxpZGF0aW9uIGlzIG9mZi5cbiAgICovXG4gIHNjaGVtYVdhcm5pbmdzPzogc3RyaW5nW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW5kcG9pbnQge1xuICBpZDogc3RyaW5nO1xuICBwcm9qZWN0SWQ6IHN0cmluZztcbiAgdXJsOiBzdHJpbmc7XG4gIGRlc2NyaXB0aW9uPzogc3RyaW5nO1xuICBzZWNyZXQ/OiBzdHJpbmc7XG4gIGVuYWJsZWQ6IGJvb2xlYW47XG4gIHJhdGVMaW1pdFBlclNlY29uZD86IG51bWJlcjtcbiAgYWxsb3dlZFNvdXJjZUlwcz86IHN0cmluZztcbiAgbXRsc0VuYWJsZWQ/OiBib29sZWFuO1xuICB2ZXJpZmljYXRpb25TdGF0dXM/OiBzdHJpbmc7XG4gIHZlcmlmaWNhdGlvbkF0dGVtcHRlZEF0Pzogc3RyaW5nO1xuICB2ZXJpZmljYXRpb25Db21wbGV0ZWRBdD86IHN0cmluZztcbiAgdmVyaWZpY2F0aW9uU2tpcFJlYXNvbj86IHN0cmluZztcbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG4gIHVwZGF0ZWRBdD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFbmRwb2ludENyZWF0ZVBhcmFtcyB7XG4gIHVybDogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgLyoqIFN1cHBseSB5b3VyIG93biBzaWduaW5nIHNlY3JldC4gT21pdCB0byBoYXZlIHRoZSBBUEkgZ2VuZXJhdGUgb25lLiAqL1xuICBzZWNyZXQ/OiBzdHJpbmc7XG4gIGVuYWJsZWQ/OiBib29sZWFuO1xuICByYXRlTGltaXRQZXJTZWNvbmQ/OiBudW1iZXI7XG4gIC8qKiBDb21tYS1zZXBhcmF0ZWQgQ0lEUnMgdGhlIGVuZHBvaW50IGlzIGFsbG93ZWQgdG8gYmUgcmVhY2hlZCBmcm9tLiAqL1xuICBhbGxvd2VkU291cmNlSXBzPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEVuZHBvaW50VXBkYXRlUGFyYW1zIHtcbiAgdXJsPzogc3RyaW5nO1xuICBkZXNjcmlwdGlvbj86IHN0cmluZztcbiAgc2VjcmV0Pzogc3RyaW5nO1xuICBlbmFibGVkPzogYm9vbGVhbjtcbiAgcmF0ZUxpbWl0UGVyU2Vjb25kPzogbnVtYmVyO1xuICBhbGxvd2VkU291cmNlSXBzPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN1YnNjcmlwdGlvbiB7XG4gIGlkOiBzdHJpbmc7XG4gIHByb2plY3RJZDogc3RyaW5nO1xuICBlbmRwb2ludElkOiBzdHJpbmc7XG4gIGV2ZW50VHlwZTogc3RyaW5nO1xuICBlbmFibGVkOiBib29sZWFuO1xuICBvcmRlcmluZ0VuYWJsZWQ6IGJvb2xlYW47XG4gIG1heEF0dGVtcHRzOiBudW1iZXI7XG4gIHRpbWVvdXRTZWNvbmRzOiBudW1iZXI7XG4gIHJldHJ5RGVsYXlzPzogc3RyaW5nO1xuICBwYXlsb2FkVGVtcGxhdGU/OiBzdHJpbmc7XG4gIGN1c3RvbUhlYWRlcnM/OiBzdHJpbmc7XG4gIHRyYW5zZm9ybWF0aW9uSWQ/OiBzdHJpbmc7XG4gIHRyYW5zZm9ybWF0aW9uTmFtZT86IHN0cmluZztcbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG4gIHVwZGF0ZWRBdD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdWJzY3JpcHRpb25DcmVhdGVQYXJhbXMge1xuICBlbmRwb2ludElkOiBzdHJpbmc7XG4gIGV2ZW50VHlwZTogc3RyaW5nO1xuICBlbmFibGVkPzogYm9vbGVhbjtcbiAgb3JkZXJpbmdFbmFibGVkPzogYm9vbGVhbjtcbiAgbWF4QXR0ZW1wdHM/OiBudW1iZXI7XG4gIHRpbWVvdXRTZWNvbmRzPzogbnVtYmVyO1xuICByZXRyeURlbGF5cz86IHN0cmluZztcbiAgcGF5bG9hZFRlbXBsYXRlPzogc3RyaW5nO1xuICBjdXN0b21IZWFkZXJzPzogc3RyaW5nO1xuICB0cmFuc2Zvcm1hdGlvbklkPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIERlbGl2ZXJ5IHtcbiAgaWQ6IHN0cmluZztcbiAgZXZlbnRJZDogc3RyaW5nO1xuICBlbmRwb2ludElkOiBzdHJpbmc7XG4gIHN1YnNjcmlwdGlvbklkOiBzdHJpbmc7XG4gIHN0YXR1czogRGVsaXZlcnlTdGF0dXM7XG4gIGF0dGVtcHRDb3VudDogbnVtYmVyO1xuICBtYXhBdHRlbXB0czogbnVtYmVyO1xuICBuZXh0UmV0cnlBdD86IHN0cmluZztcbiAgbGFzdEF0dGVtcHRBdD86IHN0cmluZztcbiAgc3VjY2VlZGVkQXQ/OiBzdHJpbmc7XG4gIGZhaWxlZEF0Pzogc3RyaW5nO1xuICBjcmVhdGVkQXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IHR5cGUgRGVsaXZlcnlTdGF0dXMgPSAnUEVORElORycgfCAnUFJPQ0VTU0lORycgfCAnU1VDQ0VTUycgfCAnRkFJTEVEJyB8ICdETFEnO1xuXG5leHBvcnQgaW50ZXJmYWNlIERlbGl2ZXJ5QXR0ZW1wdCB7XG4gIGlkOiBzdHJpbmc7XG4gIGRlbGl2ZXJ5SWQ6IHN0cmluZztcbiAgYXR0ZW1wdE51bWJlcjogbnVtYmVyO1xuICAvKiogSlNPTiBvYmplY3QsIHNlcmlhbGl6ZWQgYXMgYSBzdHJpbmcsIG9mIHRoZSBoZWFkZXJzIHRoYXQgd2VyZSBzZW50LiAqL1xuICByZXF1ZXN0SGVhZGVycz86IHN0cmluZztcbiAgcmVxdWVzdEJvZHk/OiBzdHJpbmc7XG4gIGh0dHBTdGF0dXNDb2RlPzogbnVtYmVyO1xuICAvKiogSlNPTiBvYmplY3QsIHNlcmlhbGl6ZWQgYXMgYSBzdHJpbmcsIG9mIHRoZSBoZWFkZXJzIHRoYXQgY2FtZSBiYWNrLiAqL1xuICByZXNwb25zZUhlYWRlcnM/OiBzdHJpbmc7XG4gIHJlc3BvbnNlQm9keT86IHN0cmluZztcbiAgZXJyb3JNZXNzYWdlPzogc3RyaW5nO1xuICAvKiogV2FsbC1jbG9jayBkdXJhdGlvbiBvZiB0aGUgSFRUUCByZXF1ZXN0LCBpbiBtaWxsaXNlY29uZHMuICovXG4gIGR1cmF0aW9uTXM/OiBudW1iZXI7XG4gIC8qKiBXaGVuIHRoZSBhdHRlbXB0IHdhcyByZWNvcmRlZC4gKi9cbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUGFnaW5hdGVkUmVzcG9uc2U8VD4ge1xuICBjb250ZW50OiBUW107XG4gIHRvdGFsRWxlbWVudHM6IG51bWJlcjtcbiAgdG90YWxQYWdlczogbnVtYmVyO1xuICAvKiogUGFnZSBzaXplIHJlcXVlc3RlZC4gKi9cbiAgc2l6ZTogbnVtYmVyO1xuICAvKiogWmVyby1iYXNlZCBpbmRleCBvZiB0aGlzIHBhZ2UuICovXG4gIG51bWJlcjogbnVtYmVyO1xuICBudW1iZXJPZkVsZW1lbnRzPzogbnVtYmVyO1xuICBmaXJzdD86IGJvb2xlYW47XG4gIGxhc3Q/OiBib29sZWFuO1xuICBlbXB0eT86IGJvb2xlYW47XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRW5kcG9pbnRMaXN0UGFyYW1zIHtcbiAgcGFnZT86IG51bWJlcjtcbiAgc2l6ZT86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBEZWxpdmVyeUxpc3RQYXJhbXMge1xuICBzdGF0dXM/OiBEZWxpdmVyeVN0YXR1cztcbiAgZW5kcG9pbnRJZD86IHN0cmluZztcbiAgZnJvbURhdGU/OiBzdHJpbmc7XG4gIHRvRGF0ZT86IHN0cmluZztcbiAgcGFnZT86IG51bWJlcjtcbiAgc2l6ZT86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFbmRwb2ludFRlc3RSZXN1bHQge1xuICBzdWNjZXNzOiBib29sZWFuO1xuICBodHRwU3RhdHVzQ29kZT86IG51bWJlcjtcbiAgcmVzcG9uc2VCb2R5Pzogc3RyaW5nO1xuICBlcnJvck1lc3NhZ2U/OiBzdHJpbmc7XG4gIGxhdGVuY3lNczogbnVtYmVyO1xuICAvKiogSHVtYW4tcmVhZGFibGUgc3VtbWFyeSwgZS5nLiBcIkVuZHBvaW50IHJldHVybmVkIG5vbi0yeHggc3RhdHVzXCIuICovXG4gIG1lc3NhZ2U/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgUmF0ZUxpbWl0SW5mbyB7XG4gIGxpbWl0OiBudW1iZXI7XG4gIHJlbWFpbmluZzogbnVtYmVyO1xuICAvKipcbiAgICogVW5peCB0aW1lc3RhbXAgaW4gKipzZWNvbmRzKiogYXQgd2hpY2ggdGhlIHdpbmRvdyByZXNldHMg4oCUIHRoZSByYXcgdmFsdWVcbiAgICogb2YgdGhlIGBYLVJhdGVMaW1pdC1SZXNldGAgaGVhZGVyLCB3aGljaCB0aGUgQVBJIHNlbmRzIGluIHNlY29uZHMsIG5vdFxuICAgKiBtaWxsaXNlY29uZHMuXG4gICAqL1xuICByZXNldDogbnVtYmVyO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFdlYmhvb2tFdmVudCB7XG4gIGV2ZW50SWQ6IHN0cmluZztcbiAgZGVsaXZlcnlJZDogc3RyaW5nO1xuICB0aW1lc3RhbXA6IG51bWJlcjtcbiAgdHlwZTogc3RyaW5nO1xuICBkYXRhOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbn1cblxuLy8g4pSA4pSAIEluY29taW5nIFdlYmhvb2tzIOKUgOKUgFxuXG5leHBvcnQgdHlwZSBQcm92aWRlclR5cGUgPSAnR0VORVJJQycgfCAnR0lUSFVCJyB8ICdHSVRMQUInIHwgJ1NUUklQRScgfCAnU0hPUElGWScgfCAnU0xBQ0snIHwgJ1RXSUxJTyc7XG5leHBvcnQgdHlwZSBWZXJpZmljYXRpb25Nb2RlID0gJ05PTkUnIHwgJ0hNQUNfR0VORVJJQyc7XG5leHBvcnQgdHlwZSBJbmNvbWluZ1NvdXJjZVN0YXR1cyA9ICdBQ1RJVkUnIHwgJ0RJU0FCTEVEJztcbmV4cG9ydCB0eXBlIEluY29taW5nQXV0aFR5cGUgPSAnTk9ORScgfCAnQkVBUkVSJyB8ICdCQVNJQycgfCAnQ1VTVE9NX0hFQURFUic7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5jb21pbmdTb3VyY2Uge1xuICBpZDogc3RyaW5nO1xuICBwcm9qZWN0SWQ6IHN0cmluZztcbiAgbmFtZTogc3RyaW5nO1xuICBzbHVnOiBzdHJpbmc7XG4gIHByb3ZpZGVyVHlwZTogUHJvdmlkZXJUeXBlO1xuICBzdGF0dXM6IEluY29taW5nU291cmNlU3RhdHVzO1xuICBpbmdyZXNzUGF0aFRva2VuOiBzdHJpbmc7XG4gIGluZ3Jlc3NVcmw6IHN0cmluZztcbiAgdmVyaWZpY2F0aW9uTW9kZTogVmVyaWZpY2F0aW9uTW9kZTtcbiAgaG1hY0hlYWRlck5hbWU/OiBzdHJpbmc7XG4gIGhtYWNTaWduYXR1cmVQcmVmaXg/OiBzdHJpbmc7XG4gIGhtYWNTZWNyZXRDb25maWd1cmVkOiBib29sZWFuO1xuICByYXRlTGltaXRQZXJTZWNvbmQ/OiBudW1iZXI7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xuICB1cGRhdGVkQXQ/OiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5jb21pbmdTb3VyY2VDcmVhdGVQYXJhbXMge1xuICBuYW1lOiBzdHJpbmc7XG4gIHNsdWc/OiBzdHJpbmc7XG4gIHByb3ZpZGVyVHlwZT86IFByb3ZpZGVyVHlwZTtcbiAgdmVyaWZpY2F0aW9uTW9kZT86IFZlcmlmaWNhdGlvbk1vZGU7XG4gIGhtYWNTZWNyZXQ/OiBzdHJpbmc7XG4gIGhtYWNIZWFkZXJOYW1lPzogc3RyaW5nO1xuICBobWFjU2lnbmF0dXJlUHJlZml4Pzogc3RyaW5nO1xuICByYXRlTGltaXRQZXJTZWNvbmQ/OiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5jb21pbmdTb3VyY2VVcGRhdGVQYXJhbXMge1xuICBuYW1lPzogc3RyaW5nO1xuICBzbHVnPzogc3RyaW5nO1xuICBwcm92aWRlclR5cGU/OiBQcm92aWRlclR5cGU7XG4gIHN0YXR1cz86IEluY29taW5nU291cmNlU3RhdHVzO1xuICB2ZXJpZmljYXRpb25Nb2RlPzogVmVyaWZpY2F0aW9uTW9kZTtcbiAgaG1hY1NlY3JldD86IHN0cmluZztcbiAgaG1hY0hlYWRlck5hbWU/OiBzdHJpbmc7XG4gIGhtYWNTaWduYXR1cmVQcmVmaXg/OiBzdHJpbmc7XG4gIHJhdGVMaW1pdFBlclNlY29uZD86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmNvbWluZ0Rlc3RpbmF0aW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgaW5jb21pbmdTb3VyY2VJZDogc3RyaW5nO1xuICB1cmw6IHN0cmluZztcbiAgYXV0aFR5cGU6IEluY29taW5nQXV0aFR5cGU7XG4gIGF1dGhDb25maWd1cmVkOiBib29sZWFuO1xuICBjdXN0b21IZWFkZXJzSnNvbj86IHN0cmluZztcbiAgZW5hYmxlZDogYm9vbGVhbjtcbiAgbWF4QXR0ZW1wdHM6IG51bWJlcjtcbiAgdGltZW91dFNlY29uZHM6IG51bWJlcjtcbiAgcmV0cnlEZWxheXM/OiBzdHJpbmc7XG4gIHBheWxvYWRUcmFuc2Zvcm0/OiBzdHJpbmc7XG4gIHRyYW5zZm9ybWF0aW9uSWQ/OiBzdHJpbmc7XG4gIHRyYW5zZm9ybWF0aW9uTmFtZT86IHN0cmluZztcbiAgY3JlYXRlZEF0OiBzdHJpbmc7XG4gIHVwZGF0ZWRBdD86IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmNvbWluZ0Rlc3RpbmF0aW9uQ3JlYXRlUGFyYW1zIHtcbiAgdXJsOiBzdHJpbmc7XG4gIGF1dGhUeXBlPzogSW5jb21pbmdBdXRoVHlwZTtcbiAgYXV0aENvbmZpZz86IHN0cmluZztcbiAgY3VzdG9tSGVhZGVyc0pzb24/OiBzdHJpbmc7XG4gIGVuYWJsZWQ/OiBib29sZWFuO1xuICBtYXhBdHRlbXB0cz86IG51bWJlcjtcbiAgdGltZW91dFNlY29uZHM/OiBudW1iZXI7XG4gIHJldHJ5RGVsYXlzPzogc3RyaW5nO1xuICBwYXlsb2FkVHJhbnNmb3JtPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEluY29taW5nRGVzdGluYXRpb25VcGRhdGVQYXJhbXMge1xuICB1cmw/OiBzdHJpbmc7XG4gIGF1dGhUeXBlPzogSW5jb21pbmdBdXRoVHlwZTtcbiAgYXV0aENvbmZpZz86IHN0cmluZztcbiAgY3VzdG9tSGVhZGVyc0pzb24/OiBzdHJpbmc7XG4gIGVuYWJsZWQ/OiBib29sZWFuO1xuICBtYXhBdHRlbXB0cz86IG51bWJlcjtcbiAgdGltZW91dFNlY29uZHM/OiBudW1iZXI7XG4gIHJldHJ5RGVsYXlzPzogc3RyaW5nO1xuICBwYXlsb2FkVHJhbnNmb3JtPzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEluY29taW5nRXZlbnQge1xuICBpZDogc3RyaW5nO1xuICBpbmNvbWluZ1NvdXJjZUlkOiBzdHJpbmc7XG4gIHNvdXJjZU5hbWU6IHN0cmluZztcbiAgcmVxdWVzdElkOiBzdHJpbmc7XG4gIG1ldGhvZDogc3RyaW5nO1xuICBwYXRoOiBzdHJpbmc7XG4gIHF1ZXJ5UGFyYW1zPzogc3RyaW5nO1xuICBoZWFkZXJzSnNvbj86IHN0cmluZztcbiAgYm9keVJhdz86IHN0cmluZztcbiAgYm9keVNoYTI1Nj86IHN0cmluZztcbiAgY29udGVudFR5cGU/OiBzdHJpbmc7XG4gIGNsaWVudElwPzogc3RyaW5nO1xuICB1c2VyQWdlbnQ/OiBzdHJpbmc7XG4gIHZlcmlmaWVkPzogYm9vbGVhbjtcbiAgdmVyaWZpY2F0aW9uRXJyb3I/OiBzdHJpbmc7XG4gIHJlY2VpdmVkQXQ6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmNvbWluZ0V2ZW50TGlzdFBhcmFtcyB7XG4gIHNvdXJjZUlkPzogc3RyaW5nO1xuICBwYWdlPzogbnVtYmVyO1xuICBzaXplPzogbnVtYmVyO1xufVxuXG5leHBvcnQgdHlwZSBGb3J3YXJkQXR0ZW1wdFN0YXR1cyA9ICdQRU5ESU5HJyB8ICdQUk9DRVNTSU5HJyB8ICdTVUNDRVNTJyB8ICdGQUlMRUQnIHwgJ0RMUSc7XG5cbmV4cG9ydCBpbnRlcmZhY2UgSW5jb21pbmdGb3J3YXJkQXR0ZW1wdCB7XG4gIGlkOiBzdHJpbmc7XG4gIGluY29taW5nRXZlbnRJZDogc3RyaW5nO1xuICBkZXN0aW5hdGlvbklkOiBzdHJpbmc7XG4gIGRlc3RpbmF0aW9uVXJsOiBzdHJpbmc7XG4gIGF0dGVtcHROdW1iZXI6IG51bWJlcjtcbiAgc3RhdHVzOiBGb3J3YXJkQXR0ZW1wdFN0YXR1cztcbiAgc3RhcnRlZEF0Pzogc3RyaW5nO1xuICBmaW5pc2hlZEF0Pzogc3RyaW5nO1xuICByZXNwb25zZUNvZGU/OiBudW1iZXI7XG4gIHJlc3BvbnNlSGVhZGVyc0pzb24/OiBzdHJpbmc7XG4gIHJlc3BvbnNlQm9keVNuaXBwZXQ/OiBzdHJpbmc7XG4gIGVycm9yTWVzc2FnZT86IHN0cmluZztcbiAgbmV4dFJldHJ5QXQ/OiBzdHJpbmc7XG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFJlcGxheUV2ZW50UmVzcG9uc2Uge1xuICBzdGF0dXM6IHN0cmluZztcbiAgZXZlbnRJZDogc3RyaW5nO1xuICBkZXN0aW5hdGlvbnNDb3VudDogbnVtYmVyO1xufVxuIl19
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { WebhookEvent } from './types';
|
|
2
|
+
export interface WebhookHeaders {
|
|
3
|
+
'x-signature'?: string;
|
|
4
|
+
'x-timestamp'?: string;
|
|
5
|
+
'x-event-id'?: string;
|
|
6
|
+
'x-delivery-id'?: string;
|
|
7
|
+
[key: string]: string | undefined;
|
|
8
|
+
}
|
|
9
|
+
export interface VerifyOptions {
|
|
10
|
+
tolerance?: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Verifies the webhook signature using HMAC-SHA256.
|
|
14
|
+
*
|
|
15
|
+
* The header is `t=<unix-ms>,v1=<hex>`, and it may carry **more than one** `v1`.
|
|
16
|
+
* After you rotate an endpoint's secret, Railhook signs each delivery with both
|
|
17
|
+
* the new secret and the retired one for the endpoint's grace window (24 hours
|
|
18
|
+
* by default), so you can deploy the new secret whenever you like instead of at
|
|
19
|
+
* the instant you press rotate. The delivery is authentic if *any* `v1` matches,
|
|
20
|
+
* which is what this checks.
|
|
21
|
+
*
|
|
22
|
+
* @param payload - Raw request body as string
|
|
23
|
+
* @param signature - X-Signature header value (format: t=timestamp,v1=signature[,v1=...])
|
|
24
|
+
* @param secret - Endpoint webhook secret
|
|
25
|
+
* @param options - Verification options
|
|
26
|
+
* @returns true if signature is valid
|
|
27
|
+
* @throws RailhookError if signature is invalid
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifySignature(payload: string, signature: string, secret: string, options?: VerifyOptions): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Verifies the [Standard Webhooks](https://www.standardwebhooks.com) headers.
|
|
32
|
+
*
|
|
33
|
+
* Endpoints receive both header sets by default (`signatureScheme: 'BOTH'`), so use
|
|
34
|
+
* whichever you prefer — this one if you would rather your verification match what other
|
|
35
|
+
* providers send, `verifySignature` if you are already verifying `X-Signature`.
|
|
36
|
+
*
|
|
37
|
+
* Two things differ from Railhook's own scheme beyond the header names: the message id is
|
|
38
|
+
* part of what is signed, and the digest is base64 rather than hex. Rotation works the same
|
|
39
|
+
* way — during the grace window the header carries a space-separated signature per valid
|
|
40
|
+
* secret, and any one matching is enough.
|
|
41
|
+
*
|
|
42
|
+
* @param payload - Raw request body as string
|
|
43
|
+
* @param headers - Request headers, including the three `webhook-*` ones
|
|
44
|
+
* @param secret - The endpoint's `standardWebhooksSecret` (`whsec_…`), not the raw secret.
|
|
45
|
+
* A plain secret is accepted too and used as-is.
|
|
46
|
+
* @returns true if the signature is valid
|
|
47
|
+
* @throws RailhookError if it is not
|
|
48
|
+
*/
|
|
49
|
+
export declare function verifyStandardWebhook(payload: string, headers: WebhookHeaders, secret: string, options?: {
|
|
50
|
+
toleranceSeconds?: number;
|
|
51
|
+
}): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Constructs a webhook event from the request.
|
|
54
|
+
*
|
|
55
|
+
* What Railhook actually PUTs on the wire is the event's **payload**, not an
|
|
56
|
+
* envelope: a `client.events.send({ type: 'order.completed', data: {...} })`
|
|
57
|
+
* arrives at your endpoint as the `data` object alone, with the identifiers
|
|
58
|
+
* carried in headers (`X-Event-Id`, `X-Delivery-Id`, `X-Timestamp`,
|
|
59
|
+
* `X-Sequence-Number`). So:
|
|
60
|
+
*
|
|
61
|
+
* - `eventId` / `deliveryId` / `timestamp` come from the headers and are
|
|
62
|
+
* always populated for a real delivery.
|
|
63
|
+
* - `data` is the parsed body.
|
|
64
|
+
* - `type` is only populated when the body happens to carry a `type` key —
|
|
65
|
+
* which for a default subscription it does not. Route on the payload, or
|
|
66
|
+
* configure the subscription's `payloadTemplate` to wrap the event so that
|
|
67
|
+
* `type` is part of the body.
|
|
68
|
+
*
|
|
69
|
+
* @param payload - Raw request body as string
|
|
70
|
+
* @param headers - Request headers
|
|
71
|
+
* @param secret - Endpoint webhook secret
|
|
72
|
+
* @param options - Verification options
|
|
73
|
+
* @returns Parsed and verified webhook event
|
|
74
|
+
*/
|
|
75
|
+
export declare function constructEvent(payload: string, headers: WebhookHeaders, secret: string, options?: VerifyOptions): WebhookEvent;
|
|
76
|
+
/**
|
|
77
|
+
* Generates a signature for testing purposes
|
|
78
|
+
* @param payload - Request body as string
|
|
79
|
+
* @param secret - Webhook secret
|
|
80
|
+
* @param timestamp - Optional timestamp (defaults to now)
|
|
81
|
+
* @returns Signature string in format t=timestamp,v1=signature
|
|
82
|
+
*/
|
|
83
|
+
export declare function generateSignature(payload: string, secret: string, timestamp?: number): string;
|