@instantdb/webhooks 0.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/.tshy/build.json +8 -0
- package/.tshy/commonjs.json +16 -0
- package/.tshy/esm.json +15 -0
- package/.turbo/turbo-build.log +36 -0
- package/README.md +27 -0
- package/dist/commonjs/index.d.ts +430 -0
- package/dist/commonjs/index.d.ts.map +1 -0
- package/dist/commonjs/index.js +551 -0
- package/dist/commonjs/index.js.map +1 -0
- package/dist/commonjs/package.json +3 -0
- package/dist/esm/index.d.ts +430 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +546 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/package.json +3 -0
- package/instantdb-webhooks-0.0.0.tgz +0 -0
- package/package.json +61 -0
- package/src/index.ts +1047 -0
- package/tsconfig.dev.json +14 -0
- package/tsconfig.json +11 -0
- package/tsconfig.test.json +5 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import { InstantSchemaDef, ResolveAttrs } from '@instantdb/core';
|
|
2
|
+
type Config<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
3
|
+
appId?: string | null | undefined;
|
|
4
|
+
adminToken?: string | null | undefined;
|
|
5
|
+
token?: string | null | undefined;
|
|
6
|
+
apiURI?: string | null | undefined;
|
|
7
|
+
schema?: Schema | null | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Optional hook used by {@link WebhooksManager} to obtain the bearer token
|
|
10
|
+
* for each management request. Lets callers (e.g. the platform SDK) wrap
|
|
11
|
+
* the operation in token-refresh / retry logic.
|
|
12
|
+
*
|
|
13
|
+
* If omitted, the manager uses the static `adminToken`/`token` from this
|
|
14
|
+
* config.
|
|
15
|
+
*/
|
|
16
|
+
withAuth?: WithAuth;
|
|
17
|
+
};
|
|
18
|
+
type JsonFetch = (input: RequestInfo, init?: RequestInit | undefined) => Promise<any>;
|
|
19
|
+
/**
|
|
20
|
+
* Runs a webhook management operation that needs a bearer token. The runner
|
|
21
|
+
* is responsible for supplying the token, and may retry the operation with a
|
|
22
|
+
* fresh token if the first attempt fails with an auth error.
|
|
23
|
+
*/
|
|
24
|
+
export type WithAuth = <T>(operation: (token: string) => Promise<T>) => Promise<T>;
|
|
25
|
+
export type WebhookBody = {
|
|
26
|
+
payloadUrl: string;
|
|
27
|
+
token: string;
|
|
28
|
+
};
|
|
29
|
+
export type WebhookEntity<Schema extends InstantSchemaDef<any, any, any>, EtypeName extends keyof Schema['entities']> = {
|
|
30
|
+
id: string;
|
|
31
|
+
} & ResolveAttrs<Schema['entities'], EtypeName, false>;
|
|
32
|
+
export type WebhookPayloadRecord<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
33
|
+
[EtypeName in keyof Schema['entities']]: {
|
|
34
|
+
etype: EtypeName;
|
|
35
|
+
id: string;
|
|
36
|
+
action: 'create';
|
|
37
|
+
before: null;
|
|
38
|
+
after: WebhookEntity<Schema, EtypeName>;
|
|
39
|
+
idempotencyKey: string;
|
|
40
|
+
} | {
|
|
41
|
+
etype: EtypeName;
|
|
42
|
+
id: string;
|
|
43
|
+
action: 'update';
|
|
44
|
+
before: WebhookEntity<Schema, EtypeName>;
|
|
45
|
+
after: WebhookEntity<Schema, EtypeName>;
|
|
46
|
+
idempotencyKey: string;
|
|
47
|
+
} | {
|
|
48
|
+
etype: EtypeName;
|
|
49
|
+
id: string;
|
|
50
|
+
action: 'delete';
|
|
51
|
+
before: WebhookEntity<Schema, EtypeName>;
|
|
52
|
+
after: null;
|
|
53
|
+
idempotencyKey: string;
|
|
54
|
+
};
|
|
55
|
+
}[keyof Schema['entities']];
|
|
56
|
+
export type WebhookPayload<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
57
|
+
data: WebhookPayloadRecord<Schema>[];
|
|
58
|
+
idempotencyKey: string;
|
|
59
|
+
};
|
|
60
|
+
export type WebhookAction = 'create' | 'update' | 'delete';
|
|
61
|
+
/**
|
|
62
|
+
* Whether Instant will currently deliver events for a webhook.
|
|
63
|
+
* `disabled` webhooks remain configured but no new events are queued.
|
|
64
|
+
*/
|
|
65
|
+
export type WebhookStatus = 'active' | 'disabled';
|
|
66
|
+
/**
|
|
67
|
+
* Stage in the delivery lifecycle of a single webhook event.
|
|
68
|
+
*
|
|
69
|
+
* - `pending`: queued, not yet picked up for delivery
|
|
70
|
+
* - `processing`: a sender is actively attempting delivery
|
|
71
|
+
* - `success`: the receiver acknowledged with a 2xx response
|
|
72
|
+
* - `error`: an attempt failed; another retry is scheduled
|
|
73
|
+
* - `failed`: all retries exhausted; will not be retried automatically
|
|
74
|
+
* (use {@link WebhooksManager.resendEvent} to retry manually)
|
|
75
|
+
*/
|
|
76
|
+
export type WebhookEventStatus = 'pending' | 'processing' | 'success' | 'error' | 'failed';
|
|
77
|
+
export type WebhookInfo = {
|
|
78
|
+
/** Unique identifier for the webhook. */
|
|
79
|
+
id: string;
|
|
80
|
+
/** Where Instant POSTs event payloads to. */
|
|
81
|
+
sink: {
|
|
82
|
+
/** HTTPS endpoint that Instant POSTs to. */
|
|
83
|
+
url: string;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* The entity types (namespaces) this webhook listens to. `null` if every
|
|
87
|
+
* etype the webhook referenced has since been removed from the schema.
|
|
88
|
+
*/
|
|
89
|
+
etypes: string[] | null;
|
|
90
|
+
/** Which write actions trigger delivery. */
|
|
91
|
+
actions: WebhookAction[];
|
|
92
|
+
/** Whether the webhook is currently delivering events. */
|
|
93
|
+
status: WebhookStatus;
|
|
94
|
+
/**
|
|
95
|
+
* Human-readable reason the webhook is disabled. Set automatically when
|
|
96
|
+
* Instant disables the webhook (e.g. after repeated delivery failures) or
|
|
97
|
+
* supplied by the caller via {@link WebhooksManager.disable}. `null` when
|
|
98
|
+
* `status` is `'active'`.
|
|
99
|
+
*/
|
|
100
|
+
disabledReason: string | null;
|
|
101
|
+
/** When the webhook was created. */
|
|
102
|
+
createdAt: Date;
|
|
103
|
+
/** When the webhook's config was last changed. */
|
|
104
|
+
updatedAt: Date;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Record of a single HTTP delivery attempt for a webhook event.
|
|
108
|
+
* Stored in attempt order (oldest first) on the event's `attempts` array.
|
|
109
|
+
*/
|
|
110
|
+
export type WebhookAttempt = {
|
|
111
|
+
/** When the attempt started. */
|
|
112
|
+
attemptAt: Date | null;
|
|
113
|
+
/** Time from request start to response received (or error), in milliseconds. */
|
|
114
|
+
durationMs: number | null;
|
|
115
|
+
/** `true` if the receiver returned a 2xx response. */
|
|
116
|
+
success: boolean | null;
|
|
117
|
+
/** HTTP status code returned by the receiver, if a response was received. */
|
|
118
|
+
statusCode: number | null;
|
|
119
|
+
/**
|
|
120
|
+
* First 256 bytes of the response body, for debugging. `null` if no
|
|
121
|
+
* response was received (e.g. on a network error).
|
|
122
|
+
*/
|
|
123
|
+
responseText: string | null;
|
|
124
|
+
/**
|
|
125
|
+
* Short tag classifying a delivery failure. One of `timeout`, `dns`,
|
|
126
|
+
* `connect`, `tls`, `protocol`, `network`, or `unknown`. `null` on success.
|
|
127
|
+
*/
|
|
128
|
+
errorType: string | null;
|
|
129
|
+
/** Free-form description of the failure. `null` on success. */
|
|
130
|
+
errorMessage: string | null;
|
|
131
|
+
};
|
|
132
|
+
export type WebhookEventInfo = {
|
|
133
|
+
/**
|
|
134
|
+
* Instant Sequence Number — a stable, totally ordered identifier for the
|
|
135
|
+
* event. Doubles as the pagination cursor and is used to address the event
|
|
136
|
+
* in {@link WebhooksManager.getEvent} and {@link WebhooksManager.resendEvent}.
|
|
137
|
+
*/
|
|
138
|
+
isn: string;
|
|
139
|
+
/** Current stage in the delivery lifecycle. */
|
|
140
|
+
status: WebhookEventStatus;
|
|
141
|
+
/**
|
|
142
|
+
* Per-attempt records, in attempt order (oldest first). `null` if the
|
|
143
|
+
* event has not been attempted yet.
|
|
144
|
+
*/
|
|
145
|
+
attempts: WebhookAttempt[] | null;
|
|
146
|
+
/**
|
|
147
|
+
* The next retry will not happen before this time. `null` once the event
|
|
148
|
+
* reaches a terminal status (`success` or `failed`).
|
|
149
|
+
*/
|
|
150
|
+
nextAttemptAfter: Date | null;
|
|
151
|
+
/** When the event was queued. */
|
|
152
|
+
createdAt: Date;
|
|
153
|
+
/** When the event last transitioned status. */
|
|
154
|
+
updatedAt: Date;
|
|
155
|
+
};
|
|
156
|
+
export type WebhookEventsPage = {
|
|
157
|
+
/** The events on this page, newest first. */
|
|
158
|
+
events: WebhookEventInfo[];
|
|
159
|
+
pageInfo: {
|
|
160
|
+
/** Cursor pointing to the first event on this page. */
|
|
161
|
+
startCursor: string | null;
|
|
162
|
+
/**
|
|
163
|
+
* Cursor pointing to the last event on this page. Pass as
|
|
164
|
+
* {@link WebhooksManager.listEvents}'s `after` option to fetch the next page.
|
|
165
|
+
*/
|
|
166
|
+
endCursor: string | null;
|
|
167
|
+
/** Whether more events are available after `endCursor`. */
|
|
168
|
+
hasNextPage: boolean;
|
|
169
|
+
};
|
|
170
|
+
};
|
|
171
|
+
export type CreateWebhookParams<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
172
|
+
/**
|
|
173
|
+
* HTTPS endpoint Instant will POST events to. Must use the `https` scheme
|
|
174
|
+
* and resolve to a public host.
|
|
175
|
+
*/
|
|
176
|
+
url: string;
|
|
177
|
+
/**
|
|
178
|
+
* Entity types (namespaces) the webhook will listen to. Must reference at
|
|
179
|
+
* least one entity in the app's schema.
|
|
180
|
+
*/
|
|
181
|
+
etypes: (keyof Schema['entities'] & string)[];
|
|
182
|
+
/** Write actions that should trigger delivery. Must contain at least one. */
|
|
183
|
+
actions: WebhookAction[];
|
|
184
|
+
};
|
|
185
|
+
export type UpdateWebhookParams<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
186
|
+
/** New delivery URL. Omit to leave unchanged. */
|
|
187
|
+
url?: string;
|
|
188
|
+
/** New set of entity types. Omit to leave unchanged. */
|
|
189
|
+
etypes?: (keyof Schema['entities'] & string)[];
|
|
190
|
+
/** New set of actions. Omit to leave unchanged. */
|
|
191
|
+
actions?: WebhookAction[];
|
|
192
|
+
};
|
|
193
|
+
export type WebhookPayloadRecordFor<Schema extends InstantSchemaDef<any, any, any>, EtypeName extends keyof Schema['entities'], Action extends WebhookAction> = Extract<WebhookPayloadRecord<Schema>, {
|
|
194
|
+
etype: EtypeName;
|
|
195
|
+
action: Action;
|
|
196
|
+
}>;
|
|
197
|
+
export type WebhookHandlerFn<Schema extends InstantSchemaDef<any, any, any>, EtypeName extends keyof Schema['entities'], Action extends WebhookAction, Result = any> = (record: WebhookPayloadRecordFor<Schema, EtypeName, Action>) => Result | Promise<Result>;
|
|
198
|
+
export type DefaultKey = '$default';
|
|
199
|
+
export type ResolveHandlerAction<Action> = Action extends DefaultKey ? WebhookAction : Action extends WebhookAction ? Action : never;
|
|
200
|
+
export type WebhookHandlers<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
201
|
+
[EtypeName in keyof Schema['entities']]?: {
|
|
202
|
+
[Action in WebhookAction | DefaultKey]?: WebhookHandlerFn<Schema, EtypeName, ResolveHandlerAction<Action>, any>;
|
|
203
|
+
};
|
|
204
|
+
} & {
|
|
205
|
+
$default?: WebhookHandlerFn<Schema, keyof Schema['entities'], WebhookAction, any>;
|
|
206
|
+
};
|
|
207
|
+
export type TypedHandlerEntry<Schema extends InstantSchemaDef<any, any, any>, EtypeName extends keyof Schema['entities'], Action extends WebhookAction | DefaultKey> = {
|
|
208
|
+
[E in EtypeName]: {
|
|
209
|
+
[A in Action]: WebhookHandlerFn<Schema, EtypeName, ResolveHandlerAction<Action>, any>;
|
|
210
|
+
};
|
|
211
|
+
};
|
|
212
|
+
export type TypedDefaultEntry<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
213
|
+
$default: WebhookHandlerFn<Schema, keyof Schema['entities'], WebhookAction, any>;
|
|
214
|
+
};
|
|
215
|
+
export type WebhookHelpers<Schema extends InstantSchemaDef<any, any, any>> = {
|
|
216
|
+
typedHandlers: {
|
|
217
|
+
(etype: DefaultKey, handler: WebhookHandlerFn<Schema, keyof Schema['entities'], WebhookAction, any>): TypedDefaultEntry<Schema>;
|
|
218
|
+
<EtypeName extends keyof Schema['entities'], Action extends WebhookAction | DefaultKey>(etype: EtypeName, action: Action, handler: WebhookHandlerFn<Schema, EtypeName, ResolveHandlerAction<Action>, any>): TypedHandlerEntry<Schema, EtypeName, Action>;
|
|
219
|
+
};
|
|
220
|
+
combineHandlers: (...entries: Array<WebhookHandlers<Schema>>) => WebhookHandlers<Schema>;
|
|
221
|
+
};
|
|
222
|
+
type ImportAlgorithm = AlgorithmIdentifier | RsaHashedImportParams | EcKeyImportParams;
|
|
223
|
+
export declare class WebhooksManager<Schema extends InstantSchemaDef<any, any, any>> {
|
|
224
|
+
#private;
|
|
225
|
+
constructor(opts: {
|
|
226
|
+
appId: string | null | undefined;
|
|
227
|
+
apiURI: string;
|
|
228
|
+
token: string | null | undefined;
|
|
229
|
+
withAuth?: WithAuth;
|
|
230
|
+
jsonFetch: JsonFetch;
|
|
231
|
+
});
|
|
232
|
+
/**
|
|
233
|
+
* Returns every webhook configured on the app, newest first. Includes both
|
|
234
|
+
* active and disabled webhooks.
|
|
235
|
+
*/
|
|
236
|
+
list(): Promise<WebhookInfo[]>;
|
|
237
|
+
/**
|
|
238
|
+
* Creates a new webhook. The webhook is created in the `active` state and
|
|
239
|
+
* starts receiving matching events immediately.
|
|
240
|
+
*
|
|
241
|
+
* The server rejects the request if `url` is not an HTTPS URL pointing at a
|
|
242
|
+
* public host, if `etypes` doesn't reference any entity in the app's
|
|
243
|
+
* schema, if `actions` is empty, or if the app has hit its webhook limit.
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* const webhook = await db.webhooks.manager.create({
|
|
247
|
+
* url: 'https://example.com/instant',
|
|
248
|
+
* etypes: ['posts', 'comments'],
|
|
249
|
+
* actions: ['create', 'update'],
|
|
250
|
+
* });
|
|
251
|
+
*/
|
|
252
|
+
create(params: CreateWebhookParams<Schema>): Promise<WebhookInfo>;
|
|
253
|
+
/**
|
|
254
|
+
* Updates a webhook's `url`, `etypes`, and/or `actions`. Pass only the
|
|
255
|
+
* fields you want to change; omitted fields keep their current value.
|
|
256
|
+
*
|
|
257
|
+
* Does not affect the webhook's status — use {@link enable} or
|
|
258
|
+
* {@link disable} for that.
|
|
259
|
+
*/
|
|
260
|
+
update(webhookId: string, params: UpdateWebhookParams<Schema>): Promise<WebhookInfo>;
|
|
261
|
+
/**
|
|
262
|
+
* Deletes a webhook. No further events will be queued for it. Returns the
|
|
263
|
+
* webhook as it looked just before deletion.
|
|
264
|
+
*/
|
|
265
|
+
delete(webhookId: string): Promise<WebhookInfo>;
|
|
266
|
+
/**
|
|
267
|
+
* Re-enables a disabled webhook. Clears `disabledReason` and resumes
|
|
268
|
+
* delivery for new events. Has no effect if the webhook is already active.
|
|
269
|
+
*
|
|
270
|
+
* Events that occurred while the webhook was disabled are not retroactively
|
|
271
|
+
* delivered.
|
|
272
|
+
*/
|
|
273
|
+
enable(webhookId: string): Promise<WebhookInfo>;
|
|
274
|
+
/**
|
|
275
|
+
* Disables a webhook. No new events will be queued until it is re-enabled
|
|
276
|
+
* via {@link enable}. In-flight events already being processed will still
|
|
277
|
+
* complete.
|
|
278
|
+
*
|
|
279
|
+
* @param opts.reason Optional human-readable note stored on the webhook
|
|
280
|
+
* and surfaced in the dashboard.
|
|
281
|
+
*/
|
|
282
|
+
disable(webhookId: string, opts?: {
|
|
283
|
+
reason?: string | null | undefined;
|
|
284
|
+
} | null | undefined): Promise<WebhookInfo>;
|
|
285
|
+
/**
|
|
286
|
+
* Returns a page of events for a webhook, newest first.
|
|
287
|
+
*
|
|
288
|
+
* Events are retained for ~60 days. To paginate, pass the previous page's
|
|
289
|
+
* `pageInfo.endCursor` as `opts.after`; stop when `pageInfo.hasNextPage`
|
|
290
|
+
* is `false`.
|
|
291
|
+
*/
|
|
292
|
+
listEvents(webhookId: string, opts?: {
|
|
293
|
+
after?: string | null | undefined;
|
|
294
|
+
} | null | undefined): Promise<WebhookEventsPage>;
|
|
295
|
+
/**
|
|
296
|
+
* Fetches a single webhook event by its `isn`.
|
|
297
|
+
*/
|
|
298
|
+
getEvent(webhookId: string, isn: string): Promise<WebhookEventInfo>;
|
|
299
|
+
/** Returns the full payload for an event. */
|
|
300
|
+
getPayload(webhookId: string, isn: string): Promise<WebhookPayload<Schema>>;
|
|
301
|
+
/**
|
|
302
|
+
* Re-queues an event for delivery, regardless of its current status. Use
|
|
303
|
+
* this to retry a `failed` event or force a redelivery of a `success` one.
|
|
304
|
+
*
|
|
305
|
+
* The server rate-limits resends; if the event was queued or resent very
|
|
306
|
+
* recently the call will fail with a validation error asking you to try
|
|
307
|
+
* again in about a minute.
|
|
308
|
+
*/
|
|
309
|
+
resendEvent(webhookId: string, isn: string): Promise<WebhookEventInfo>;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Verify incoming webhook requests from Instant, dispatch their records to
|
|
313
|
+
* typed handlers, and manage webhook subscriptions (via {@link manager}).
|
|
314
|
+
*
|
|
315
|
+
* Usually accessed as `db.webhooks` on the admin or platform SDK rather than
|
|
316
|
+
* constructed directly.
|
|
317
|
+
*/
|
|
318
|
+
export declare class Webhooks<Schema extends InstantSchemaDef<any, any, any>> {
|
|
319
|
+
#private;
|
|
320
|
+
/** App this instance is bound to. */
|
|
321
|
+
appId: string | null | undefined;
|
|
322
|
+
/** Schema used to type webhook payloads and handler records. */
|
|
323
|
+
schema: Schema | null | undefined;
|
|
324
|
+
/** Base URL for the Instant API. */
|
|
325
|
+
apiURI: string;
|
|
326
|
+
/** Manage webhook subscriptions and inspect delivery events. */
|
|
327
|
+
manager: WebhooksManager<Schema>;
|
|
328
|
+
/**
|
|
329
|
+
* Schema-bound helpers for building typed handler maps.
|
|
330
|
+
*
|
|
331
|
+
* - `typedHandlers(etype, action, handler)` builds a single typed entry.
|
|
332
|
+
* Pass `'$default'` for `etype` to register a catch-all handler.
|
|
333
|
+
* - `combineHandlers(...entries)` merges entries into a
|
|
334
|
+
* {@link WebhookHandlers} object suitable for {@link processPayload} and
|
|
335
|
+
* {@link processRequest}.
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* const { typedHandlers, combineHandlers } = Webhooks.helpers<typeof schema>();
|
|
339
|
+
* const handlers = combineHandlers(
|
|
340
|
+
* typedHandlers('posts', 'create', (record) => { ... }),
|
|
341
|
+
* typedHandlers('comments', '$default', (record) => { ... }),
|
|
342
|
+
* typedHandlers('$default', (record) => { ... }),
|
|
343
|
+
* );
|
|
344
|
+
*/
|
|
345
|
+
static helpers<Schema extends InstantSchemaDef<any, any, any>>(): WebhookHelpers<Schema>;
|
|
346
|
+
constructor(config: Config<Schema>, jsonFetch?: JsonFetch);
|
|
347
|
+
/** Fetches Instant's JWK set for verifying webhook signatures. */
|
|
348
|
+
fetchJwks(): Promise<any>;
|
|
349
|
+
/**
|
|
350
|
+
* Resolves a `kid` to an imported {@link CryptoKey}, hitting a
|
|
351
|
+
* process-wide cache on repeat calls. Falls back to {@link fetchJwks} if
|
|
352
|
+
* the key isn't already known.
|
|
353
|
+
*/
|
|
354
|
+
keyOfKid(kid: string): Promise<{
|
|
355
|
+
alg: ImportAlgorithm;
|
|
356
|
+
key: CryptoKey;
|
|
357
|
+
}>;
|
|
358
|
+
/**
|
|
359
|
+
* Verifies an `Instant-Signature` header against a body and returns the
|
|
360
|
+
* parsed {@link WebhookBody} (containing the `payloadUrl` and a JWT
|
|
361
|
+
* `token` for fetching the records).
|
|
362
|
+
*
|
|
363
|
+
* Throws if the signature doesn't validate, the signature is older than
|
|
364
|
+
* `opts.tolerance` (default 300 seconds), or the body doesn't decode to
|
|
365
|
+
* the expected shape.
|
|
366
|
+
*
|
|
367
|
+
* @param body Either the raw body string, or a function returning it.
|
|
368
|
+
* Use a function to defer reading the body until after the
|
|
369
|
+
* header has been parsed.
|
|
370
|
+
*/
|
|
371
|
+
validate(signatureHeader: string, body: string | (() => Promise<string>), opts?: {
|
|
372
|
+
receivedAt?: Date | null | undefined;
|
|
373
|
+
tolerance?: number | null | undefined;
|
|
374
|
+
} | null | undefined): Promise<WebhookBody>;
|
|
375
|
+
/**
|
|
376
|
+
* Pulls the `Instant-Signature` header and body from a `Request` and
|
|
377
|
+
* delegates to {@link validate}. Throws if the header is missing.
|
|
378
|
+
*/
|
|
379
|
+
validateRequest(req: Request, opts?: {
|
|
380
|
+
tolerance?: number | null | undefined;
|
|
381
|
+
receivedAt?: Date | null | undefined;
|
|
382
|
+
} | null | undefined): Promise<WebhookBody>;
|
|
383
|
+
/**
|
|
384
|
+
* Fetches the records and `idempotencyKey` for a validated
|
|
385
|
+
* {@link WebhookBody}, authenticating with the JWT `token` it carries.
|
|
386
|
+
*/
|
|
387
|
+
fetchPayloads({ payloadUrl, token, }: WebhookBody): Promise<WebhookPayload<Schema>>;
|
|
388
|
+
/**
|
|
389
|
+
* Dispatches each record in `payload` to its matching handler in
|
|
390
|
+
* `handlers`. Resolution order per record: exact `etype` + `action` →
|
|
391
|
+
* `etype`'s `$default` → top-level `$default`. Records with no matching
|
|
392
|
+
* handler are skipped.
|
|
393
|
+
*
|
|
394
|
+
* Handlers run concurrently. The returned promise resolves once every
|
|
395
|
+
* handler has settled (success or failure); rejections in individual
|
|
396
|
+
* handlers do not bubble up.
|
|
397
|
+
*/
|
|
398
|
+
processPayload(handlers: WebhookHandlers<Schema>, payload: WebhookPayload<Schema>): Promise<void>;
|
|
399
|
+
/**
|
|
400
|
+
* The one-liner for handling webhooks. Hand it your handlers and the
|
|
401
|
+
* incoming `Request` — it verifies the signature, fetches the records, and
|
|
402
|
+
* dispatches each one to your code.
|
|
403
|
+
*
|
|
404
|
+
* Async handlers are executed in parallel, the return promise will resolve once
|
|
405
|
+
* all handlers complete and will reject if any of the handlers fails.
|
|
406
|
+
*
|
|
407
|
+
* @example
|
|
408
|
+
* const { typedHandlers, combineHandlers } = Webhooks.helpers<typeof schema>();
|
|
409
|
+
*
|
|
410
|
+
* const handlers = combineHandlers(
|
|
411
|
+
* typedHandlers('posts', 'create', async (record) => {
|
|
412
|
+
* await sendNewPostEmail(record.after);
|
|
413
|
+
* }),
|
|
414
|
+
* typedHandlers('$default', (record) => {
|
|
415
|
+
* console.log('webhook event', record);
|
|
416
|
+
* }),
|
|
417
|
+
* );
|
|
418
|
+
*
|
|
419
|
+
* export async function POST(req: Request) {
|
|
420
|
+
* await db.webhooks.processRequest(handlers, req);
|
|
421
|
+
* return new Response('ok');
|
|
422
|
+
* }
|
|
423
|
+
*/
|
|
424
|
+
processRequest(handlers: WebhookHandlers<Schema>, req: Request, opts?: {
|
|
425
|
+
tolerance?: number | null | undefined;
|
|
426
|
+
receivedAt?: Date | null | undefined;
|
|
427
|
+
} | null | undefined): Promise<void>;
|
|
428
|
+
}
|
|
429
|
+
export {};
|
|
430
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|