Skip to content

Commit e8e3334

Browse files
author
meorphis
committed
chore(internal): restore custom code
1 parent 6ad1698 commit e8e3334

28 files changed

Lines changed: 2320 additions & 114 deletions

.tool-versions

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
nodejs 18.17.0
2+
yarn 1.22.22

CHANGELOG.md

Lines changed: 353 additions & 0 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 214 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44

55
This library provides convenient access to the Mux REST API from server-side TypeScript or JavaScript.
66

7+
> [!NOTE]
8+
> In February 2024 this SDK was updated to Version 8.0. For upgrading to 8.x see [UPGRADE_8.x.md](https://github.com/muxinc/mux-node-sdk/blob/master/UPGRADE_8.x.md)
9+
710
The REST API documentation can be found on [docs.mux.com](https://docs.mux.com). The full API of this library can be found in [api.md](api.md).
811

912
## Installation
@@ -63,6 +66,215 @@ main();
6366

6467
Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.
6568

69+
## JWT Helpers ([API Reference](https://github.com/muxinc/mux-node-sdk/blob/master/api.md#jwt))
70+
71+
You can use any JWT-compatible library, but we've included some light helpers in the SDK to make it easier to get up and running.
72+
73+
```js
74+
// Assuming you have your signing key specified in your environment variables:
75+
// Signing token ID: process.env.MUX_SIGNING_KEY
76+
// Signing token secret: process.env.MUX_PRIVATE_KEY
77+
78+
// Most simple request, defaults to type video and is valid for 7 days.
79+
const token = mux.jwt.signPlaybackId('some-playback-id');
80+
// https://stream.mux.com/some-playback-id.m3u8?token=${token}
81+
82+
// If you wanted to sign a thumbnail
83+
const thumbParams = { time: 14, width: 100 };
84+
const thumbToken = mux.jwt.signPlaybackId('some-playback-id', {
85+
type: 'thumbnail',
86+
params: thumbParams,
87+
});
88+
// https://image.mux.com/some-playback-id/thumbnail.jpg?token=${token}
89+
90+
// If you wanted to sign a gif
91+
const gifToken = mux.jwt.signPlaybackId('some-playback-id', { type: 'gif' });
92+
// https://image.mux.com/some-playback-id/animated.gif?token=${token}
93+
94+
// Here's an example for a storyboard
95+
const storyboardToken = mux.jwt.signPlaybackId('some-playback-id', {
96+
type: 'storyboard',
97+
});
98+
99+
// https://image.mux.com/some-playback-id/storyboard.jpg?token=${token}
100+
101+
// You can also use `signViewerCounts` to get a token
102+
// used for requests to the Mux Engagement Counts API
103+
// https://docs.mux.com/guides/see-how-many-people-are-watching
104+
const statsToken = mux.jwt.signViewerCounts('some-live-stream-id', {
105+
type: 'live_stream',
106+
});
107+
108+
// https://stats.mux.com/counts?token={statsToken}
109+
```
110+
111+
### Signing multiple JWTs at once
112+
In cases you need multiple tokens, like when using Mux Player, things can get unwieldy pretty quickly. For example,
113+
```tsx
114+
const playbackToken = await mux.jwt.signPlaybackId(id, {
115+
expiration: "1d",
116+
type: "playback"
117+
})
118+
const thumbnailToken = await mux.jwt.signPlaybackId(id, {
119+
expiration: "1d",
120+
type: "thumbnail",
121+
})
122+
const storyboardToken = await mux.jwt.signPlaybackId(id, {
123+
expiration: "1d",
124+
type: "storyboard"
125+
})
126+
const drmToken = await mux.jwt.signPlaybackId(id, {
127+
expiration: "1d",
128+
type: "drm_license"
129+
})
130+
131+
<mux-player
132+
playback-token={playbackToken}
133+
thumbanil-token={thumbnailToken}
134+
storyboard-token={storyboardToken}
135+
drm-token={drmToken}
136+
playbackId={id}
137+
></mux-player>
138+
```
139+
140+
To simplify this use-case, you can provide multiple types to `signPlaybackId` to recieve multiple tokens. These tokens are provided in a format that Mux Player can take as props:
141+
```tsx
142+
// { "playback-token", "thumbnail-token", "storyboard-token", "drm-token" }
143+
const tokens = await mux.jwt.signPlaybackId(id, {
144+
expiration: "1d",
145+
type: ["playback", "thumbnail", "storyboard", "drm_license"]
146+
})
147+
148+
<mux-player
149+
{...tokens}
150+
playbackId={id}
151+
></mux-player>
152+
```
153+
154+
If you would like to provide params to a single token (e.g., if you would like to have a thumbnail `time`), you can provide `[type, typeParams]` instead of `type`:
155+
```tsx
156+
const tokens = await mux.jwt.signPlaybackId(id, {
157+
expiration: "1d",
158+
type: ["playback", ["thumbnail", { time: 2 }], "storyboard", "drm_license"]
159+
})
160+
```
161+
162+
## Parsing Webhook payloads
163+
164+
To validate that the given payload was sent by Mux and parse the webhook payload for use in your application,
165+
you can use the `mux.webhooks.unwrap` utility method.
166+
167+
This method accepts a raw `body` string and a list of headers. As long as you have set your `webhookSecret` in the
168+
appropriate configuration property when instantiating the library, all webhooks will be verified for authenticity automatically.
169+
170+
The following example shows how you can handle a webhook using a Next.js app directory API route:
171+
172+
```js
173+
// app/api/mux/webhooks/route.ts
174+
import { revalidatePath } from 'next/cache';
175+
import { headers } from 'next/headers';
176+
177+
import Mux from '@mux/mux-node';
178+
179+
const mux = new Mux({
180+
webhookSecret: process.env.MUX_WEBHOOK_SECRET,
181+
});
182+
183+
export async function POST(request: Request) {
184+
const headersList = headers();
185+
const body = await request.text();
186+
const event = mux.webhooks.unwrap(body, headersList);
187+
188+
switch (event.type) {
189+
case 'video.live_stream.active':
190+
case 'video.live_stream.idle':
191+
case 'video.live_stream.disabled':
192+
/**
193+
* `event` is now understood to be one of the following types:
194+
*
195+
* | Mux.Webhooks.VideoLiveStreamActiveWebhookEvent
196+
* | Mux.Webhooks.VideoLiveStreamIdleWebhookEvent
197+
* | Mux.Webhooks.VideoLiveStreamDisabledWebhookEvent
198+
*/
199+
if (event.data.id === 'MySpecialTVLiveStreamID') {
200+
revalidatePath('/tv');
201+
}
202+
break;
203+
default:
204+
break;
205+
}
206+
207+
return Response.json({ message: 'ok' });
208+
}
209+
```
210+
211+
## Verifying Webhook Signatures
212+
213+
Verifying Webhook Signatures is _optional but encouraged_. Learn more in our [Webhook Security Guide](https://docs.mux.com/docs/webhook-security)
214+
215+
```js
216+
/*
217+
If the header is valid, this function will not throw an error and will not return a value.
218+
If the header is invalid, this function will throw one of the following errors:
219+
- new Error(
220+
"The webhook secret must either be set using the env var, MUX_WEBHOOK_SECRET, on the client class, Mux({ webhookSecret: '123' }), or passed to this function",
221+
);
222+
- new Error('Could not find a mux-signature header');
223+
- new Error(
224+
'Webhook body must be passed as the raw JSON string sent from the server (do not parse it first).',
225+
);
226+
- new Error('Unable to extract timestamp and signatures from header')
227+
- new Error('No v1 signatures found');
228+
- new Error('No signatures found matching the expected signature for payload.')
229+
- new Error('Webhook timestamp is too old')
230+
*/
231+
232+
/*
233+
`body` is the raw request body. It should be a string representation of a JSON object.
234+
`headers` is the value in request.headers
235+
`secret` is the signing secret for this configured webhook. You can find that in your webhooks dashboard
236+
(note that this secret is different than your API Secret Key)
237+
*/
238+
239+
mux.webhooks.verifySignature(body, headers, secret);
240+
```
241+
242+
Note that when passing in the payload (body) you want to pass in the raw un-parsed request body, not the parsed JSON. Here's an example if you are using express.
243+
244+
```js
245+
const Mux = require('@mux/mux-node');
246+
const mux = new Mux();
247+
const express = require('express');
248+
const bodyParser = require('body-parser');
249+
250+
/**
251+
* You'll need to make sure this is externally accessible. ngrok (https://ngrok.com/)
252+
* makes this really easy.
253+
*/
254+
255+
const webhookSecret = process.env.WEBHOOK_SECRET;
256+
const app = express();
257+
258+
app.post('/webhooks', bodyParser.raw({ type: 'application/json' }), async (req, res) => {
259+
try {
260+
// will raise an exception if the signature is invalid
261+
const isValidSignature = mux.webhooks.verifySignature(req.body, req.headers, webhookSecret);
262+
console.log('Success:', isValidSignature);
263+
// convert the raw req.body to JSON, which is originally Buffer (raw)
264+
const jsonFormattedBody = JSON.parse(req.body);
265+
// await doSomething();
266+
res.json({ received: true });
267+
} catch (err) {
268+
// On error, return the error message
269+
return res.status(400).send(`Webhook Error: ${err.message}`);
270+
}
271+
});
272+
273+
app.listen(3000, () => {
274+
console.log('Example app listening on port 3000!');
275+
});
276+
```
277+
66278
## Handling errors
67279

68280
When the library is unable to connect to the API,
@@ -222,7 +434,7 @@ await client.post('/some/path', {
222434
});
223435
```
224436

225-
#### Undocumented request params
437+
#### Undocumented params
226438

227439
To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented
228440
parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you
@@ -243,7 +455,7 @@ extra param in the body.
243455
If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request
244456
options.
245457

246-
#### Undocumented response properties
458+
#### Undocumented properties
247459

248460
To access undocumented response properties, you may access the response object with `// @ts-expect-error` on
249461
the response object, or cast the response object to the requisite type. Like the request params, we do not

UPGRADE_8.x.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# Upgrading to 8.x
2+
3+
If you're coming a version of this SDK before 8.0 then a lot has changed.
4+
5+
For context & background see the [announcement issue](https://github.com/muxinc/mux-node-sdk/issues/327).
6+
7+
## Codemod
8+
9+
There is a codemod script you can run which will modify the old function calls to the new 8.0 syntax:
10+
11+
```
12+
npx @getgrit/launcher apply mux_v8
13+
```
14+
15+
This will edit the files in your project in a way that converts your existing code to the new v8 syntax. The codemod script is working well for us, but you should still verify your code changes and make sure it works as expected before deploying the new code to production.
16+
17+
This codemod script was tested and run against code running 7.x versions of the SDK. If you're on a version before 7.x you can still run it, but it might not work as reliably and if you're running into issues you may want to upgrade to 7.3.5 before running the codemod.
18+
19+
## Documentation
20+
21+
The current [README](https://github.com/muxinc/mux-node-sdk/blob/master/README.md) has everything else to get started with version 8.
22+
23+
You also may want to look at [api.md](https://github.com/muxinc/mux-node-sdk/blob/master/api.md) for a full API reference.

api.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ Methods:
2424
- <code title="post /video/v1/assets">client.video.assets.<a href="./src/resources/video/assets.ts">create</a>({ ...params }) -> Asset</code>
2525
- <code title="get /video/v1/assets/{ASSET_ID}">client.video.assets.<a href="./src/resources/video/assets.ts">retrieve</a>(assetId) -> Asset</code>
2626
- <code title="patch /video/v1/assets/{ASSET_ID}">client.video.assets.<a href="./src/resources/video/assets.ts">update</a>(assetId, { ...params }) -> Asset</code>
27-
- <code title="get /video/v1/assets">client.video.assets.<a href="./src/resources/video/assets.ts">list</a>({ ...params }) -> AssetsCursorPage</code>
27+
- <code title="get /video/v1/assets">client.video.assets.<a href="./src/resources/video/assets.ts">list</a>({ ...params }) -> AssetsBasePage</code>
2828
- <code title="delete /video/v1/assets/{ASSET_ID}">client.video.assets.<a href="./src/resources/video/assets.ts">delete</a>(assetId) -> void</code>
2929
- <code title="post /video/v1/assets/{ASSET_ID}/playback-ids">client.video.assets.<a href="./src/resources/video/assets.ts">createPlaybackId</a>(assetId, { ...params }) -> PlaybackID</code>
3030
- <code title="post /video/v1/assets/{ASSET_ID}/tracks">client.video.assets.<a href="./src/resources/video/assets.ts">createTrack</a>(assetId, { ...params }) -> Track</code>
@@ -370,4 +370,13 @@ Types:
370370

371371
Methods:
372372

373-
- <code>client.webhooks.<a href="./src/resources/webhooks.ts">unwrap</a>(body) -> void</code>
373+
- <code>client.webhooks.<a href="./src/resources/webhooks.ts">unwrap</a>(body, headers, secret) -> UnwrapWebhookEvent</code>
374+
- <code>client.webhooks.<a href="./src/resources/webhooks.ts">verifySignature</a>(body, headers, secret) -> void</code>
375+
376+
# JWT
377+
378+
Methods:
379+
380+
- <code>client.jwt.<a href="./src/resources/jwt.ts">signPlaybackId</a>(playbackId, config) -> Promise&lt;string&gt;</code>
381+
- <code>client.jwt.<a href="./src/resources/jwt.ts">signSpaceId</a>(spaceId, config) -> Promise&lt;string&gt;</code>
382+
- <code>client.jwt.<a href="./src/resources/jwt.ts">signViewerCounts</a>(id, config) -> Promise&lt;string&gt;</code>

0 commit comments

Comments
 (0)