@rstreamlabs/tunnels 3.1.0 → 3.2.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 CHANGED
@@ -172,8 +172,9 @@ credentials are additionally capped by the PAT expiration.
172
172
 
173
173
  ## Webhooks
174
174
 
175
- Validate signed engine webhook payloads with constant-time signature comparison
176
- and schema parsing:
175
+ Validate signed webhook payloads with constant-time signature comparison and
176
+ schema parsing. Webhook parsing accepts lifecycle events only; stream summaries
177
+ and connection logs use the separate project log event schema.
177
178
 
178
179
  ```ts
179
180
  const event = await client.webhooks.event(
@@ -185,6 +186,57 @@ const event = await client.webhooks.event(
185
186
  console.log(event.type);
186
187
  ```
187
188
 
189
+ For a receiving backend, verify the signature before touching the JSON payload
190
+ and use the event id as the idempotency key.
191
+
192
+ ```ts
193
+ import { RstreamWebhookResource, type WebhookEvent } from "@rstreamlabs/tunnels";
194
+
195
+ const webhooks = new RstreamWebhookResource();
196
+
197
+ declare function markOnline(
198
+ eventId: string,
199
+ resourceId: string,
200
+ labels: Record<string, string>,
201
+ ): Promise<void>;
202
+
203
+ declare function markOffline(
204
+ eventId: string,
205
+ resourceId: string,
206
+ labels: Record<string, string>,
207
+ ): Promise<void>;
208
+
209
+ async function handleLifecycleEvent(
210
+ event: WebhookEvent & { id: string },
211
+ ): Promise<void> {
212
+ switch (event.type) {
213
+ case "client.created":
214
+ case "tunnel.created":
215
+ await markOnline(event.id, event.object.id, event.object.labels ?? {});
216
+ return;
217
+ case "client.deleted":
218
+ case "tunnel.deleted":
219
+ await markOffline(event.id, event.object.id, event.object.labels ?? {});
220
+ return;
221
+ }
222
+ }
223
+
224
+ export async function receiveWebhook(request: Request) {
225
+ const rawBody = Buffer.from(await request.arrayBuffer());
226
+ const signature = request.headers.get("rstream-signature");
227
+ if (!signature) throw new Error("Missing webhook signature.");
228
+
229
+ const event = await webhooks.event(
230
+ rawBody,
231
+ signature,
232
+ process.env.WEBHOOK_SECRET!,
233
+ );
234
+ if (!event.id) throw new Error("Missing webhook event id.");
235
+
236
+ await handleLifecycleEvent(event);
237
+ }
238
+ ```
239
+
188
240
  ## WebTTY Helpers
189
241
 
190
242
  Use `parseWebTTYServers()` to derive WebTTY server metadata from tunnel
@@ -324,15 +324,23 @@ var commonEventsSchema = [
324
324
  object: tunnelSchema2
325
325
  })
326
326
  ];
327
+ var webhookDeliverableEventsSchema = [
328
+ commonEventsSchema[0],
329
+ commonEventsSchema[2],
330
+ commonEventsSchema[3],
331
+ commonEventsSchema[5]
332
+ ];
327
333
  var wsEventsSchema = z4.union([
328
334
  stateInitialEventSchema,
329
335
  ...commonEventsSchema
330
336
  ]);
331
- var webhookEventsSchema = z4.union([
332
- ...commonEventsSchema,
333
- streamSummaryEventSchema
337
+ var webhookEventsSchema = z4.union(webhookDeliverableEventsSchema);
338
+ var projectLogEventsSchema = streamSummaryEventSchema;
339
+ var eventSchema = z4.union([
340
+ wsEventsSchema,
341
+ webhookEventsSchema,
342
+ projectLogEventsSchema
334
343
  ]);
335
- var eventSchema = z4.union([wsEventsSchema, webhookEventsSchema]);
336
344
 
337
345
  // src/openapi.ts
338
346
  import * as z5 from "zod";
@@ -688,8 +696,10 @@ export {
688
696
  streamTLSInfoSchema,
689
697
  streamEndpointSchema,
690
698
  streamSummarySchema,
699
+ streamSummaryEventSchema,
691
700
  wsEventsSchema,
692
701
  webhookEventsSchema,
702
+ projectLogEventsSchema,
693
703
  eventSchema,
694
704
  tunnelFilterSchema,
695
705
  listTunnelsParamsSchema,