Skip to the content
Krizaka TypeScript
Krizaka TypeScript

@krizaka/video

Video behind one port: server-signed resumable uploads, playback tokens and signed HLS links, signed webhook statuses.

Install

bashTerminal
npm install @krizaka/video

Also published as subpath exports: @krizaka/video/testkit.

Video behind one port: server-signed resumable uploads, playback tokens and signed links, webhook statuses. Bunny Stream is the first adapter (streamVideo); the port is open to others. The client never holds a library key. No vendor SDK, no environment variable, no wall clock.

  • Uploads. createVideo then uploadSession(videoId, ttl): a TUS endpoint and the four headers (AuthorizationSignature, AuthorizationExpire, VideoId, LibraryId), signed on the server for this video only.
  • Playback. viewToken(videoId, ttl, "embed" | "mobile") (the embedded web player's token, or the mobile SDKs'; the lifetime is passed in, 1 to 5 minutes is the norm) and playbackUrls(videoId, ttl): the HLS playlist signed for the whole video directory (the token sits in the path, so every rendition and segment is covered) and a signed poster.
  • Webhooks. parseWebhook(rawBody, headers) verifies the HMAC-SHA256 of the raw body with the library's read-only key, in constant time, and answers { videoId, status } (ready, playable, failed, upload_failed…); a status it does not track answers null.
  • Proofs. The formulas come from Bunny's documentation (TUS, embedded view token, mobile SDK token, webhooks) and the CDN forms are the ones run in production. The documentation publishes no expected outputs, so the tests compute them independently from the documented formulas and never use an invented vector.
  • Not here yet. Captions, collections and listing are follow-ups.
import { streamVideo } from "@krizaka/video";

const video = streamVideo({ libraryId, libraryKey, tokenKey, readOnlyKey, cdnHostname, fetch, clock });
const { videoId } = await video.createVideo({ title: "Moment" });
const session = video.uploadSession(videoId, 3600); // hand it to the client's TUS uploader
const { token, expires } = video.viewToken(videoId, 120, "embed");

videoProviderContract (@krizaka/video/testkit) is the contract every adapter runs.

Apache-2.0.

Exports

The 19 names the package exports, read from its types.

NameKindWhat it is
Clocktype
embedTokenfunctionThe token of the embedded web player (Stream docs, « Embedded view token authentication »): hex SHA-256 of tokenKey + videoId + expires.
FetchLiketypeThe part of fetch the adapters use: inject the global one (fetch), or a fake in a test.
mobileViewTokenfunctionThe token of the mobile SDKs (Stream docs, « Token authentication with Mobile SDKs »): HMAC-SHA256, keyed by the library API key, over `libraryKey + videoId…
PlaybackUrlstype
signedDirectoryUrlfunctionCDN token authentication for a DIRECTORY (a video's playlist, renditions and segments): SHA-256 of key + path + expires + [ip] + "token_path=" + path, URL-…
signedFileUrlfunctionCDN token authentication for ONE FILE (a poster, a preview): SHA-256 of key + path + expires, URL-safe base64, sent as ?token=…&expires=….
streamVideofunctionBunny Stream, behind the VideoProvider port.
StreamVideoOptionstype
tusSignaturefunctionThe signature of a TUS upload (Stream docs, « TUS resumable uploads »): hex SHA-256 of libraryId + libraryKey + expires + videoId, concatenated with no sep…
UploadSessiontypeWhere a client uploads, resumably (TUS), and the headers it must send: short-lived, for this video only.
VIDEO_CODEconstant
VIDEO_STATUSconstant
VideoCodetype
VideoErrorclass
VideoEventtypeWhat a provider's webhook says happened to one video.
VideoProvidertypeOne video provider.
VideoStatustype
ViewTokentypeA token the player is given for one video.

@krizaka/video/testkit

NameKindWhat it is
videoProviderContractfunctionWhat every VideoProvider must do: the same behaviour behind the same port.

Package

Version on npm0.2.2 (npm)
LicenceApache-2.0
Node.js>=22
Dependencies@krizaka/db workspace:^
Peer dependenciesvitest >=4
Sourcevideo

Changelog

0.2.2

Patch changes

  • The READMEs, comments and published declarations no longer name the products that left the organisation (krizaka/.github#413, rule no-departed-published). The sources were cleaned in #262 with an empty changeset, so the published tarballs still carried the old text; this release replaces them. No behaviour change.

0.2.1

Patch changes

0.2.0

Minor changes

  • New packages (#44). @krizaka/storage: the ObjectStore port (put, get, head, delete, list, signedUrl, publicUrl), remoteStore (HTTP zone, token-signed links), bucketStore (any S3-compatible service, Signature V4 checked against AWS's vectors), folderStore, memoryObjectStore, createStorage (size limit passed in, declared layout, magic-number check, content-hashed names), checkEndpoint, @krizaka/storage/settings (storage.provider local / http / s3, limits and coordinates; storeFromSettings) and objectStoreContract. @krizaka/video: the VideoProvider port, streamVideo (Bunny Stream: create, delete, server-signed TUS sessions, embed and mobile view tokens, signed HLS and poster links, signed webhooks), the signing helpers and videoProviderContract.

On this page