@fastpix/fastpix-node 2.0.7 → 2.0.8

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.
Files changed (64) hide show
  1. package/README.md +92 -4
  2. package/dist/commonjs/index.d.ts +1 -0
  3. package/dist/commonjs/index.d.ts.map +1 -1
  4. package/dist/commonjs/index.js +1 -0
  5. package/dist/commonjs/index.js.map +1 -1
  6. package/dist/commonjs/lib/config.d.ts +13 -2
  7. package/dist/commonjs/lib/config.d.ts.map +1 -1
  8. package/dist/commonjs/lib/config.js +2 -2
  9. package/dist/commonjs/lib/config.js.map +1 -1
  10. package/dist/commonjs/lib/env.d.ts +1 -0
  11. package/dist/commonjs/lib/env.d.ts.map +1 -1
  12. package/dist/commonjs/lib/env.js +1 -0
  13. package/dist/commonjs/lib/env.js.map +1 -1
  14. package/dist/commonjs/lib/sdks.d.ts.map +1 -1
  15. package/dist/commonjs/lib/sdks.js +9 -1
  16. package/dist/commonjs/lib/sdks.js.map +1 -1
  17. package/dist/commonjs/sdk/sdk.d.ts +3 -0
  18. package/dist/commonjs/sdk/sdk.d.ts.map +1 -1
  19. package/dist/commonjs/sdk/sdk.js +11 -0
  20. package/dist/commonjs/sdk/sdk.js.map +1 -1
  21. package/dist/commonjs/sdk/webhooks.d.ts +151 -0
  22. package/dist/commonjs/sdk/webhooks.d.ts.map +1 -0
  23. package/dist/commonjs/sdk/webhooks.js +139 -0
  24. package/dist/commonjs/sdk/webhooks.js.map +1 -0
  25. package/dist/commonjs/types/primitives.d.ts +1 -1
  26. package/dist/commonjs/types/primitives.d.ts.map +1 -1
  27. package/dist/commonjs/types/primitives.js +7 -3
  28. package/dist/commonjs/types/primitives.js.map +1 -1
  29. package/dist/esm/index.d.ts +1 -0
  30. package/dist/esm/index.d.ts.map +1 -1
  31. package/dist/esm/index.js +1 -0
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/lib/config.d.ts +13 -2
  34. package/dist/esm/lib/config.d.ts.map +1 -1
  35. package/dist/esm/lib/config.js +2 -2
  36. package/dist/esm/lib/config.js.map +1 -1
  37. package/dist/esm/lib/env.d.ts +1 -0
  38. package/dist/esm/lib/env.d.ts.map +1 -1
  39. package/dist/esm/lib/env.js +1 -0
  40. package/dist/esm/lib/env.js.map +1 -1
  41. package/dist/esm/lib/sdks.d.ts.map +1 -1
  42. package/dist/esm/lib/sdks.js +9 -1
  43. package/dist/esm/lib/sdks.js.map +1 -1
  44. package/dist/esm/sdk/sdk.d.ts +3 -0
  45. package/dist/esm/sdk/sdk.d.ts.map +1 -1
  46. package/dist/esm/sdk/sdk.js +11 -0
  47. package/dist/esm/sdk/sdk.js.map +1 -1
  48. package/dist/esm/sdk/webhooks.d.ts +151 -0
  49. package/dist/esm/sdk/webhooks.d.ts.map +1 -0
  50. package/dist/esm/sdk/webhooks.js +134 -0
  51. package/dist/esm/sdk/webhooks.js.map +1 -0
  52. package/dist/esm/types/primitives.d.ts +1 -1
  53. package/dist/esm/types/primitives.d.ts.map +1 -1
  54. package/dist/esm/types/primitives.js +7 -3
  55. package/dist/esm/types/primitives.js.map +1 -1
  56. package/examples/webhooksServer.example.ts +93 -0
  57. package/package.json +3 -4
  58. package/src/index.ts +1 -0
  59. package/src/lib/config.ts +14 -2
  60. package/src/lib/env.ts +2 -2
  61. package/src/lib/sdks.ts +9 -1
  62. package/src/sdk/sdk.ts +8 -0
  63. package/src/sdk/webhooks.ts +329 -0
  64. package/src/types/primitives.ts +12 -7
@@ -0,0 +1,151 @@
1
+ import { ClientSDK } from "../lib/sdks.js";
2
+ import type { CreateLiveStreamResponseDTO } from "../models/createlivestreamresponsedto.js";
3
+ import type { Media } from "../models/media.js";
4
+ import { Buffer } from "node:buffer";
5
+ /**
6
+ * The raw, unparsed webhook request body. Always pass the bytes exactly as they
7
+ * arrived on the wire — verification fails if the body was re-serialized.
8
+ */
9
+ export type WebhookRawBody = string | Buffer | Uint8Array;
10
+ /**
11
+ * Inbound request headers. Accepts a WHATWG `Headers` instance or a plain object
12
+ * such as Node's `IncomingHttpHeaders` (values may be `string` or `string[]`).
13
+ */
14
+ export type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;
15
+ /** The `object` envelope field: the resource this event is about. */
16
+ export interface WebhookEventObject {
17
+ /** The resource type, e.g. "media" or "live-stream". */
18
+ type: string;
19
+ /** The affected resource id (equal to `data.id`). */
20
+ id: string;
21
+ }
22
+ /** The `workspace` envelope field. */
23
+ export interface WebhookWorkspace {
24
+ id: string;
25
+ name: string;
26
+ }
27
+ /** Every webhook event type whose `data` payload is a {@link Media}. */
28
+ export type MediaWebhookEventType = "video.media.created" | "video.media.updated" | "video.media.ready" | "video.media.failed" | "video.media.deleted" | "video.media.track.created" | "video.media.track.ready" | "video.media.track.updated" | "video.media.track.deleted" | "video.media.upload.cancelled" | "video.media.subtitle.generated.ready" | "video.media.source.ready" | "video.media.source.deleted" | "video.media.mp4Support.ready";
29
+ /**
30
+ * Every webhook event type whose `data` payload is a
31
+ * {@link CreateLiveStreamResponseDTO}.
32
+ */
33
+ export type LiveStreamWebhookEventType = "video.live_stream.created" | "video.live_stream.updated" | "video.live_stream.deleted" | "video.live_stream.simulcast_target.updated" | "video.live_stream.simulcast_target.deleted";
34
+ /** Union of all known FastPix webhook event `type` strings. */
35
+ export type WebhookEventType = MediaWebhookEventType | LiveStreamWebhookEventType;
36
+ /**
37
+ * A verified FastPix webhook event.
38
+ *
39
+ * Route on `type`, dedupe on the top-level `id` (the idempotency key — NOT
40
+ * `object.id`), and read the affected resource id from `object.id`
41
+ * (== `data.id`). `data` carries the full entity payload.
42
+ *
43
+ * Two type parameters, both with sensible defaults:
44
+ * - `TData` — the shape of `data` (defaults to a loose record).
45
+ * - `TType` — the literal `type` (defaults to any `string`).
46
+ *
47
+ * Most callers don't use these directly: {@link Webhooks.unwrap} returns the
48
+ * discriminated {@link FastpixWebhookEvent} union, which narrows both for you.
49
+ */
50
+ export interface WebhookEvent<TData = Record<string, unknown>, TType extends string = string> {
51
+ /** Routing key, e.g. "video.media.updated". */
52
+ type: TType;
53
+ /** The resource this event concerns. */
54
+ object: WebhookEventObject;
55
+ /** Event id — the idempotency key. Dedupe on this. */
56
+ id: string;
57
+ /** The workspace that produced the event. */
58
+ workspace: WebhookWorkspace;
59
+ /** Coarse status string, e.g. "media_created". */
60
+ status: string;
61
+ /** Full entity payload (has its own id/status/playbackIds/tracks/...). */
62
+ data: TData;
63
+ /** ISO-8601 timestamp string. */
64
+ createdAt: string;
65
+ /** Delivery attempt metadata. */
66
+ attempts: unknown[];
67
+ }
68
+ /** A `video.media.*` event. `data` is a {@link Media}. */
69
+ export type MediaWebhookEvent = WebhookEvent<Media, MediaWebhookEventType>;
70
+ /**
71
+ * A `video.live_stream.*` event. `data` is a
72
+ * {@link CreateLiveStreamResponseDTO}.
73
+ */
74
+ export type LiveStreamWebhookEvent = WebhookEvent<CreateLiveStreamResponseDTO, LiveStreamWebhookEventType>;
75
+ /**
76
+ * The discriminated union of every known FastPix webhook event. This is what
77
+ * {@link Webhooks.unwrap} returns: `switch (event.type)` narrows `event.data`
78
+ * to the right payload type automatically.
79
+ *
80
+ * ```ts
81
+ * const event = fastpix.webhooks.unwrap(body, headers);
82
+ * switch (event.type) {
83
+ * case "video.media.ready":
84
+ * event.data.playbackIds; // ✅ typed as Media
85
+ * break;
86
+ * case "video.live_stream.created":
87
+ * event.data.streamKey; // ✅ typed as CreateLiveStreamResponseDTO
88
+ * break;
89
+ * }
90
+ * ```
91
+ */
92
+ export type FastpixWebhookEvent = MediaWebhookEvent | LiveStreamWebhookEvent;
93
+ /**
94
+ * Thrown when a webhook cannot be verified. Catch this to return `400` (bad
95
+ * signature / malformed input) versus `500` (unexpected server error).
96
+ */
97
+ export declare class WebhookVerificationError extends Error {
98
+ constructor(message: string, options?: {
99
+ cause?: unknown;
100
+ });
101
+ }
102
+ /**
103
+ * Webhooks resource — verifies and unwraps inbound FastPix webhook deliveries.
104
+ *
105
+ * Accessed as `fastpix.webhooks`. The signing secret defaults to the client's
106
+ * `webhookSecret` option (which itself falls back to
107
+ * `process.env.FASTPIX_WEBHOOK_SECRET`), and can be overridden per call.
108
+ */
109
+ export declare class Webhooks extends ClientSDK {
110
+ /**
111
+ * Verify the signature and return the parsed event.
112
+ *
113
+ * This is the single function most integrations need: hand it the raw body and
114
+ * request headers and it returns a typed {@link WebhookEvent}, throwing
115
+ * {@link WebhookVerificationError} if anything is wrong.
116
+ *
117
+ * @param body The raw, unparsed request body (string or Buffer/Uint8Array).
118
+ * @param headers The inbound request headers.
119
+ * @param secret Optional override for the webhook signing secret. Defaults to
120
+ * the client's `webhookSecret` option.
121
+ * @returns The verified, parsed webhook event.
122
+ */
123
+ unwrap(body: WebhookRawBody, headers: WebhookHeaders, secret?: string | null): FastpixWebhookEvent;
124
+ /**
125
+ * Escape hatch: supply your own `data` shape (e.g. for an event type the SDK
126
+ * doesn't model yet) by passing an explicit type argument.
127
+ */
128
+ unwrap<TData>(body: WebhookRawBody, headers: WebhookHeaders, secret?: string | null): WebhookEvent<TData>;
129
+ /**
130
+ * Verify the signature without parsing. Throws {@link WebhookVerificationError}
131
+ * on any failure (missing secret, parsed-instead-of-raw body, missing header,
132
+ * or signature mismatch). Returns `void` on success.
133
+ */
134
+ verifySignature(body: WebhookRawBody, headers: WebhookHeaders, secret?: string | null): void;
135
+ /**
136
+ * Compute the base64 HMAC-SHA256 of the raw payload using the base64-decoded
137
+ * secret as the key. Matches FastPix's signing scheme exactly.
138
+ */
139
+ private computeSignature;
140
+ /**
141
+ * Constant-time string comparison. Performs a length check first (lengths are
142
+ * not secret), then delegates to `crypto.timingSafeEqual`.
143
+ */
144
+ private timingSafeEqual;
145
+ /**
146
+ * Read the `FastPix-Signature` header case-insensitively. If a framework hands
147
+ * back an array of values, the first one is used.
148
+ */
149
+ private extractSignature;
150
+ }
151
+ //# sourceMappingURL=webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.d.ts","sourceRoot":"","sources":["../../../src/sdk/webhooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,134 @@
1
+ /*
2
+ * FastPix webhook verification and unwrapping.
3
+ *
4
+ * Unlike the other files under `src/sdk/`, this resource is hand-written rather
5
+ * than code-generated, but it follows the exact same conventions: it extends the
6
+ * shared `ClientSDK` base class and reads its configuration from `this._options`
7
+ * (here, the webhook signing secret resolved by the base constructor).
8
+ *
9
+ * Signature scheme (verified against a live FastPix delivery):
10
+ * - The signature travels in the `FastPix-Signature` header (read lowercase as
11
+ * `fastpix-signature`). It is a SINGLE base64 value — there is no `t=`/`v1=`
12
+ * structure to parse. A real digest looks like
13
+ * "oeDnZHgmhQ3UJ7qUw7uJAzo0O3Dbulfr0w89eoy0lVA=" (44 base64 chars => 32-byte
14
+ * HMAC-SHA256 output).
15
+ * - The signing secret is itself base64-encoded; decode it with
16
+ * `Buffer.from(secret, "base64")` and use those raw bytes as the HMAC key.
17
+ * - The HMAC-SHA256 is computed over the RAW REQUEST BODY ONLY (no timestamp
18
+ * prefix) and the digest is encoded as base64 (not hex).
19
+ * - No timestamp is signed, so there is no replay/tolerance window to enforce.
20
+ * Callers MUST instead dedupe on the top-level event `id` for idempotency.
21
+ */
22
+ /// <reference types="node" />
23
+ import { createHmac, timingSafeEqual as nodeTimingSafeEqual } from "node:crypto";
24
+ import { ClientSDK } from "../lib/sdks.js";
25
+ import { Buffer } from "node:buffer";
26
+ /**
27
+ * Thrown when a webhook cannot be verified. Catch this to return `400` (bad
28
+ * signature / malformed input) versus `500` (unexpected server error).
29
+ */
30
+ export class WebhookVerificationError extends Error {
31
+ constructor(message, options) {
32
+ super(message, options);
33
+ this.name = "WebhookVerificationError";
34
+ }
35
+ }
36
+ /** Header name we read, always lower-cased per the HTTP spec. */
37
+ const SIGNATURE_HEADER = "fastpix-signature";
38
+ /**
39
+ * Webhooks resource — verifies and unwraps inbound FastPix webhook deliveries.
40
+ *
41
+ * Accessed as `fastpix.webhooks`. The signing secret defaults to the client's
42
+ * `webhookSecret` option (which itself falls back to
43
+ * `process.env.FASTPIX_WEBHOOK_SECRET`), and can be overridden per call.
44
+ */
45
+ export class Webhooks extends ClientSDK {
46
+ unwrap(body, headers, secret) {
47
+ this.verifySignature(body, headers, secret);
48
+ const raw = typeof body === "string" ? body : Buffer.from(body).toString("utf8");
49
+ try {
50
+ return JSON.parse(raw);
51
+ }
52
+ catch (cause) {
53
+ throw new WebhookVerificationError("Webhook signature verified but the body is not valid JSON.", { cause });
54
+ }
55
+ }
56
+ /**
57
+ * Verify the signature without parsing. Throws {@link WebhookVerificationError}
58
+ * on any failure (missing secret, parsed-instead-of-raw body, missing header,
59
+ * or signature mismatch). Returns `void` on success.
60
+ */
61
+ verifySignature(body, headers, secret) {
62
+ // 1. Resolve the signing secret. Explicit arg wins, then the client option.
63
+ const signingSecret = secret ?? this._options.webhookSecret;
64
+ if (!signingSecret) {
65
+ throw new WebhookVerificationError("Missing webhook secret. Pass one to unwrap()/verifySignature(), set the "
66
+ + "`webhookSecret` client option, or set the FASTPIX_WEBHOOK_SECRET "
67
+ + "environment variable.");
68
+ }
69
+ // 2. The body MUST be the raw bytes. A plain object means the caller already
70
+ // JSON.parsed it, which destroys the exact bytes the signature covers.
71
+ if (typeof body !== "string"
72
+ && !Buffer.isBuffer(body)
73
+ && !(body instanceof Uint8Array)) {
74
+ throw new WebhookVerificationError("Webhook body must be the raw request payload as a string or Buffer. It "
75
+ + "looks like the body was already parsed into an object — configure your "
76
+ + "framework to expose the raw body (e.g. express.raw({ type: "
77
+ + "'application/json' })).");
78
+ }
79
+ // 3. Pull the signature header (single base64 value, no `t=`/`v1=` parts).
80
+ const provided = this.extractSignature(headers);
81
+ if (!provided) {
82
+ throw new WebhookVerificationError(`Missing "FastPix-Signature" header on the webhook request.`);
83
+ }
84
+ // 4. Compute the expected signature over the raw body and compare in
85
+ // constant time.
86
+ const expected = this.computeSignature(body, signingSecret);
87
+ if (!this.timingSafeEqual(provided, expected)) {
88
+ throw new WebhookVerificationError("Webhook signature mismatch. The payload may have been tampered with, or "
89
+ + "a different signing secret was used.");
90
+ }
91
+ }
92
+ /**
93
+ * Compute the base64 HMAC-SHA256 of the raw payload using the base64-decoded
94
+ * secret as the key. Matches FastPix's signing scheme exactly.
95
+ */
96
+ computeSignature(payload, secret) {
97
+ const key = Buffer.from(secret, "base64");
98
+ return createHmac("sha256", key).update(payload).digest("base64");
99
+ }
100
+ /**
101
+ * Constant-time string comparison. Performs a length check first (lengths are
102
+ * not secret), then delegates to `crypto.timingSafeEqual`.
103
+ */
104
+ timingSafeEqual(a, b) {
105
+ const ab = Buffer.from(a);
106
+ const bb = Buffer.from(b);
107
+ if (ab.length !== bb.length) {
108
+ return false;
109
+ }
110
+ return nodeTimingSafeEqual(ab, bb);
111
+ }
112
+ /**
113
+ * Read the `FastPix-Signature` header case-insensitively. If a framework hands
114
+ * back an array of values, the first one is used.
115
+ */
116
+ extractSignature(headers) {
117
+ if (typeof Headers !== "undefined" && headers instanceof Headers) {
118
+ return headers.get(SIGNATURE_HEADER) ?? undefined;
119
+ }
120
+ const record = headers;
121
+ // Fast path: HTTP servers (e.g. Node) already lower-case header names.
122
+ let value = record[SIGNATURE_HEADER];
123
+ if (value === undefined) {
124
+ for (const key of Object.keys(record)) {
125
+ if (key.toLowerCase() === SIGNATURE_HEADER) {
126
+ value = record[key];
127
+ break;
128
+ }
129
+ }
130
+ }
131
+ return Array.isArray(value) ? value[0] : value;
132
+ }
133
+ }
134
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../../src/sdk/webhooks.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,6 @@ export declare function bigint(): z.ZodMiniType<bigint>;
6
6
  export declare function date(): z.ZodMiniType<Date>;
7
7
  export declare function literal<T extends string | number | boolean>(value: T): z.ZodMiniType<T>;
8
8
  export declare function literalBigInt<T extends bigint>(value: T): z.ZodMiniType<T>;
9
- export declare function optional<T extends z.ZodMiniType>(t: T): z.ZodMiniUnion<readonly [z.ZodMiniUndefined, z.ZodMiniPipe<z.ZodMiniNull, z.ZodMiniTransform<never, null>>, T]>;
9
+ export declare function optional<T extends z.ZodMiniType>(t: T): z.ZodMiniOptional<z.ZodMiniUnion<readonly [z.ZodMiniPipe<z.ZodMiniNull, z.ZodMiniTransform<never, null>>, T]>>;
10
10
  export declare function nullable<T extends z.ZodMiniType>(t: T): z.ZodMiniUnion<readonly [z.ZodMiniNull, z.ZodMiniPipe<z.ZodMiniUndefined, z.ZodMiniTransform<never, undefined>>, T]>;
11
11
  //# sourceMappingURL=primitives.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/types/primitives.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AAIjC,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAU9C;AAED,wBAAgB,OAAO,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAuBhD;AAED,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAyB9C;AAED,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAoB9C;AAED,wBAAgB,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CA0B1C;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,EACzD,KAAK,EAAE,CAAC,GACP,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAElB;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAU1E;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,mHAQrD;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,wHAQrD"}
1
+ {"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../../src/types/primitives.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AAIjC,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAU9C;AAED,wBAAgB,OAAO,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAuBhD;AAED,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAyB9C;AAED,wBAAgB,MAAM,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAoB9C;AAED,wBAAgB,IAAI,IAAI,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,CA0B1C;AAED,wBAAgB,OAAO,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,EACzD,KAAK,EAAE,CAAC,GACP,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAElB;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,EAAE,KAAK,EAAE,CAAC,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAU1E;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,kHAarD;AAED,wBAAgB,QAAQ,CAAC,CAAC,SAAS,CAAC,CAAC,WAAW,EAAE,CAAC,EAAE,CAAC,wHAQrD"}
@@ -105,12 +105,16 @@ export function literalBigInt(value) {
105
105
  z.transform(BigInt));
106
106
  }
107
107
  export function optional(t) {
108
- return z.union([
109
- z.undefined(),
108
+ // Wrap in `z.optional` so the object key is treated as optional regardless of
109
+ // zod version. zod >=4.4.0 changed object parsing so that a missing key whose
110
+ // value schema is merely a `union` containing `z.undefined()` is treated as
111
+ // required ("nonoptional"); `z.optional(...)` marks the key optional in every
112
+ // 4.x. The inner null->undefined pipe is preserved.
113
+ return z.optional(z.union([
110
114
  // Null -> undefined
111
115
  z.pipe(z.null(), z.transform(() => unrecognized(undefined))),
112
116
  t,
113
- ]);
117
+ ]));
114
118
  }
115
119
  export function nullable(t) {
116
120
  return z.union([
@@ -1 +1 @@
1
- {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../../src/types/primitives.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"primitives.js","sourceRoot":"","sources":["../../../src/types/primitives.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,CAAC,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,MAAM,EAAE;QAEV,0BAA0B;QAC1B,qBAAqB,CAAC,EAAE,CAAC;QAEzB,+BAA+B;QAC/B,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;KACrE,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,OAAO,EAAE;QAEX,6DAA6D;QAC7D,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,KAAK,GAAG,CAAC,CAAC,WAAW,EAAE,CAAC;YAC9B,IAAI,KAAK,KAAK,MAAM;gBAAE,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;YAChD,IAAI,KAAK,KAAK,OAAO;gBAAE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC;YAClD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;gBACd,KAAK,EAAE,CAAC;gBACR,IAAI,EAAE,cAAc;gBACpB,QAAQ,EAAE,SAAS;gBACnB,QAAQ,EAAE,QAAQ;aACnB,CAAC,CAAC;YACH,OAAO,CAAC,CAAC,KAAK,CAAC;QACjB,CAAC,CAAC,CACH;QAED,qBAAqB,CAAC,KAAK,CAAC;KAC7B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,MAAM,EAAE;QAEV,mBAAmB;QACnB,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;YACtB,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;oBACd,KAAK,EAAE,CAAC;oBACR,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,QAAQ;iBACnB,CAAC,CAAC;gBACH,OAAO,CAAC,CAAC,KAAK,CAAC;YACjB,CAAC;YACD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC,CAAC,CACH;QAED,yBAAyB;QACzB,qBAAqB,CAAC,CAAC,CAAC;KACzB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YACrB,IAAI,CAAC;gBACH,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC;YACnB,CAAC;YAAC,MAAM,CAAC;gBACP,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;oBACd,KAAK,EAAE,CAAC;oBACR,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,QAAQ;oBAClB,QAAQ,EAAE,QAAQ;iBACnB,CAAC,CAAC;gBACH,OAAO,CAAC,CAAC,KAAK,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CACH;QACD,qBAAqB,CAAC,EAAE,CAAC;KAC1B,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,IAAI;IAClB,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,qBAAqB,CAAC,CAAC,CAAC,CAAC,CAAC,EAC/C,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,CAChC,EACD,CAAC,CAAC,IAAI,EAAE,CACT;QACD,CAAC,CAAC,IAAI,CACJ,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;YACrB,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;YACzB,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBACjC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;oBACd,KAAK,EAAE,CAAC;oBACR,IAAI,EAAE,cAAc;oBACpB,QAAQ,EAAE,MAAM;oBAChB,QAAQ,EAAE,QAAQ;iBACnB,CAAC,CAAC;gBACH,OAAO,CAAC,CAAC,KAAK,CAAC;YACjB,CAAC;YACD,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC;QAC5B,CAAC,CAAC,CACH;KACF,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,KAAQ;IAER,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,qBAAqB,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,UAAU,aAAa,CAAmB,KAAQ;IACtD,OAAO,CAAC,CAAC,IAAI,CACX,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,+EAA+E;IAC/E,gFAAgF;IAChF,8DAA8D;IAC9D,CAAC,CAAC,SAAS,CAAC,MAAmC,CAAC,CAG1C,CAAC;AACX,CAAC;AAED,MAAM,UAAU,QAAQ,CAA0B,CAAI;IACpD,8EAA8E;IAC9E,8EAA8E;IAC9E,4EAA4E;IAC5E,8EAA8E;IAC9E,oDAAoD;IACpD,OAAO,CAAC,CAAC,QAAQ,CACf,CAAC,CAAC,KAAK,CAAC;QACN,oBAAoB;QACpB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,CAAC;QAC5D,CAAC;KACF,CAAC,CACH,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAA0B,CAAI;IACpD,OAAO,CAAC,CAAC,KAAK,CAAC;QACb,CAAC,CAAC,IAAI,EAAE;QAER,oBAAoB;QACpB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CAAC;QAClE,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,SAAS,qBAAqB,CAAI,KAAQ;IACxC,OAAO,CAAC,CAAC,IAAI,CACX,CAAC,CAAC,GAAG,EAAE,EACP,CAAC,CAAC,SAAS,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACzB,IAAI,KAAK,KAAK,SAAS;YAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC1D,IAAI,KAAK,KAAK,IAAI;YAAE,OAAO,kBAAkB,CAAC,KAAK,CAAC,CAAC;QACrD,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;YACd,KAAK,EAAE,KAAK;YACZ,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,WAAW;YACrB,QAAQ,EAAE,SAAS;SACpB,CAAC,CAAC;QACH,OAAO,CAAC,CAAC,KAAK,CAAC;IACjB,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Example: receiving FastPix webhooks with Express.
3
+ *
4
+ * To run this example from the examples directory:
5
+ * npm i express && npm i -D @types/express
6
+ * npm run build && npx tsx webhooksServer.example.ts
7
+ *
8
+ * Set FASTPIX_WEBHOOK_SECRET in your environment (or .env) to the webhook
9
+ * signing secret from the FastPix dashboard. It is base64-encoded and is NOT
10
+ * your API password.
11
+ */
12
+
13
+ import dotenv from "dotenv";
14
+ dotenv.config();
15
+
16
+ import express from "express";
17
+ import { Fastpix, WebhookVerificationError } from "@fastpix/fastpix-node";
18
+
19
+ // `security` here is only needed if this same client also makes API calls.
20
+ // Webhook verification uses `webhookSecret` (or FASTPIX_WEBHOOK_SECRET), which
21
+ // is completely separate from the API username/password.
22
+ const fastpix = new Fastpix({
23
+ webhookSecret: process.env.FASTPIX_WEBHOOK_SECRET, // defaults to this env var anyway
24
+ });
25
+
26
+ const app = express();
27
+
28
+ // Don't advertise the framework/version in responses (avoids the
29
+ // "X-Powered-By: Express" header). Recommended for production endpoints.
30
+ app.disable("x-powered-by");
31
+
32
+ // In-memory idempotency store. In production use a durable store (Redis, a DB
33
+ // table with a unique constraint on the event id, etc.) so dedupe survives
34
+ // restarts and works across instances.
35
+ const processedEventIds = new Set<string>();
36
+
37
+ app.post(
38
+ "/webhooks/fastpix",
39
+ // CRITICAL: capture the RAW body. The signature is computed over the exact
40
+ // bytes FastPix sent — express.json() would re-serialize and break verification.
41
+ express.raw({ type: "application/json" }),
42
+ (req, res) => {
43
+ const signature = req.header("FastPix-Signature");
44
+
45
+ // 1. Endpoint-validation PING.
46
+ // When you add/verify an endpoint, FastPix sends a probe with an empty
47
+ // body (or "{}") and NO signature. Acknowledge it with 200 BEFORE doing
48
+ // any verification, otherwise the endpoint can't be validated.
49
+ const rawText = req.body?.toString("utf8") ?? "";
50
+ const isPing = !signature && (rawText.trim() === "" || rawText.trim() === "{}");
51
+ if (isPing) {
52
+ return res.status(200).send("ok");
53
+ }
54
+
55
+ // 2. Real event: verify + parse in one call.
56
+ try {
57
+ const event = fastpix.webhooks.unwrap(req.body, req.headers);
58
+
59
+ // 3. Dedupe on the TOP-LEVEL event id (the idempotency key), not object.id.
60
+ // There is no signed timestamp, so idempotency is the only replay guard.
61
+ if (processedEventIds.has(event.id)) {
62
+ return res.status(202).send("duplicate ignored");
63
+ }
64
+ processedEventIds.add(event.id);
65
+
66
+ // 4. Route on `type`; the affected resource id is `object.id` (== data.id).
67
+ switch (event.type) {
68
+ case "video.media.created":
69
+ case "video.media.updated":
70
+ console.log(`media ${event.object.id} -> ${event.status}`);
71
+ break;
72
+ default:
73
+ console.log(`unhandled event type: ${event.type}`);
74
+ }
75
+
76
+ // Acknowledge fast (202 Accepted) and do heavy work asynchronously.
77
+ return res.status(202).send("accepted");
78
+ } catch (err) {
79
+ // Verification failures are client errors -> 400 so FastPix retries later.
80
+ if (err instanceof WebhookVerificationError) {
81
+ console.warn("webhook verification failed:", err.message);
82
+ return res.status(400).send("invalid signature");
83
+ }
84
+ throw err; // unexpected -> let Express return 500
85
+ }
86
+ },
87
+ );
88
+
89
+ const port = Number(process.env.PORT ?? 3000);
90
+ app.listen(port, () => {
91
+ console.log(`Listening for FastPix webhooks on http://localhost:${port}/webhooks/fastpix`);
92
+ });
93
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastpix/fastpix-node",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "author": {
5
5
  "name": "FastPix-Dev",
6
6
  "email": "devs@fastpix.com",
@@ -37,6 +37,7 @@
37
37
  "@eslint/js": "^9.19.0",
38
38
  "@types/js-yaml": "^4.0.9",
39
39
  "@types/node": "^25.0.2",
40
+ "dotenv": "^17.4.2",
40
41
  "eslint": "^9.19.0",
41
42
  "exceljs": "^4.4.0",
42
43
  "globals": "^15.14.0",
@@ -48,9 +49,7 @@
48
49
  "typescript-eslint": "^8.26.0"
49
50
  },
50
51
  "dependencies": {
51
- "@fastpix/fastpix-node": "^2.0.6",
52
- "dotenv": "^17.4.2",
53
- "zod": "^3.25.65 || ^4.0.0"
52
+ "zod": "^3.25.65 || >=4.0.0 <4.4.0"
54
53
  },
55
54
  "exports": {
56
55
  ".": {
package/src/index.ts CHANGED
@@ -9,3 +9,4 @@ export * as files from "./lib/files.js";
9
9
  export { HTTPClient } from "./lib/http.js";
10
10
  export type { Fetcher, HTTPClientOptions } from "./lib/http.js";
11
11
  export * from "./sdk/sdk.js";
12
+ export * from "./sdk/webhooks.js";
package/src/lib/config.ts CHANGED
@@ -26,6 +26,18 @@ export type SDKOptions = {
26
26
  */
27
27
  security?: models.Security | (() => Promise<models.Security>) | undefined;
28
28
 
29
+ /**
30
+ * The secret used to verify FastPix webhook signatures.
31
+ *
32
+ * This is the webhook signing secret shown in the FastPix dashboard, NOT the
33
+ * API password supplied via `security`. Keep the two separate: `security`
34
+ * authenticates outbound API requests, while `webhookSecret` verifies inbound
35
+ * webhook deliveries.
36
+ *
37
+ * Defaults to `process.env.FASTPIX_WEBHOOK_SECRET` when not provided.
38
+ */
39
+ webhookSecret?: string | null | undefined;
40
+
29
41
  httpClient?: HTTPClient;
30
42
  /**
31
43
  * Allows overriding the default server used by the SDK
@@ -67,8 +79,8 @@ export function serverURLFromOptions(options: SDKOptions): URL | null {
67
79
  export const SDK_METADATA = {
68
80
  language: "typescript",
69
81
  openapiDocVersion: "1.0.0",
70
- sdkVersion: "2.0.7",
82
+ sdkVersion: "2.0.8",
71
83
  genVersion: "2.781.2",
72
84
  userAgent:
73
- "fastpix-sdk/typescript 2.0.7 2.781.2 1.0.0 @fastpix/fastpix-node",
85
+ "fastpix-sdk/typescript 2.0.8 2.781.2 1.0.0 @fastpix/fastpix-node",
74
86
  } as const;
package/src/lib/env.ts CHANGED
@@ -10,14 +10,14 @@ import { dlv } from "./dlv.js";
10
10
  export interface Env {
11
11
  FASTPIX_USERNAME?: string | undefined;
12
12
  FASTPIX_PASSWORD?: string | undefined;
13
-
13
+ FASTPIX_WEBHOOK_SECRET?: string | undefined;
14
14
  FASTPIX_DEBUG?: boolean | undefined;
15
15
  }
16
16
 
17
17
  export const envSchema: z.ZodMiniType<Env, unknown> = z.object({
18
18
  FASTPIX_USERNAME: z.optional(z.string()),
19
19
  FASTPIX_PASSWORD: z.optional(z.string()),
20
-
20
+ FASTPIX_WEBHOOK_SECRET: z.optional(z.string()),
21
21
  FASTPIX_DEBUG: z.optional(z.coerce.boolean()),
22
22
  });
23
23
 
package/src/lib/sdks.ts CHANGED
@@ -198,7 +198,15 @@ export class ClientSDK {
198
198
  this._baseURL = url;
199
199
  this.#httpClient = options.httpClient || defaultHttpClient;
200
200
 
201
- this._options = { ...options, hooks: this.#hooks };
201
+ this._options = {
202
+ ...options,
203
+ // Resolve the webhook signing secret once, preferring an explicit option
204
+ // and falling back to the FASTPIX_WEBHOOK_SECRET env var. Kept separate
205
+ // from `security` (the API password) on purpose. Carried forward here so
206
+ // any cloned options (e.g. per-resource clients) inherit it.
207
+ webhookSecret: options.webhookSecret ?? env().FASTPIX_WEBHOOK_SECRET ?? null,
208
+ hooks: this.#hooks,
209
+ };
202
210
 
203
211
  this.#logger = this._options.debugLogger;
204
212
  if (!this.#logger && env().FASTPIX_DEBUG) {
package/src/sdk/sdk.ts CHANGED
@@ -25,6 +25,7 @@ import { SigningKeys } from "./signingkeys.js";
25
25
  import { Simulcasts } from "./simulcasts.js";
26
26
  import { SimulcastStreams } from "./simulcaststreams.js";
27
27
  import { Views } from "./views.js";
28
+ import { Webhooks } from "./webhooks.js";
28
29
 
29
30
  export class Fastpix extends ClientSDK {
30
31
  private _inputVideo?: InputVideo;
@@ -146,4 +147,11 @@ export class Fastpix extends ClientSDK {
146
147
  this._errors ??= new Errors(this._options);
147
148
  return this._errors;
148
149
  }
150
+
151
+ private _webhooks?: Webhooks;
152
+ get webhooks(): Webhooks {
153
+ this._webhooks ??= new Webhooks(this._options);
154
+ return this._webhooks;
155
+ }
156
+
149
157
  }