@hyperserve/hyperserve-js 0.1.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/normalize.ts","../src/storage.ts","../src/client.ts","../src/webhook.ts"],"names":["size"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Base class for all Hyperserve SDK errors.\n */\nexport class HyperserveError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly statusCode?: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveError\";\n\t\t// Maintain proper prototype chain in transpiled environments\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 4xx response.\n * Typically indicates a validation problem: unsupported file format,\n * file too large, invalid resolutions, video not in expected state, etc.\n */\nexport class HyperserveValidationError extends HyperserveError {\n\tconstructor(\n\t\tmessage: string,\n\t\tstatusCode: number,\n\t\tpublic readonly detail?: unknown,\n\t) {\n\t\tsuper(message, statusCode);\n\t\tthis.name = \"HyperserveValidationError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 404 response.\n */\nexport class HyperserveNotFoundError extends HyperserveError {\n\tconstructor(message = \"Resource not found\") {\n\t\tsuper(message, 404);\n\t\tthis.name = \"HyperserveNotFoundError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 5xx response.\n */\nexport class HyperserveApiError extends HyperserveError {\n\tconstructor(message: string, statusCode: number) {\n\t\tsuper(message, statusCode);\n\t\tthis.name = \"HyperserveApiError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The storage PUT request failed.\n */\nexport class HyperserveUploadError extends HyperserveError {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly uploadStatus?: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveUploadError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * A request exceeded the configured timeoutMs.\n */\nexport class HyperserveTimeoutError extends HyperserveError {\n\tconstructor(message = \"Request timed out\") {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveTimeoutError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n","import {\n\tHyperserveApiError,\n\tHyperserveError,\n\tHyperserveNotFoundError,\n\tHyperserveTimeoutError,\n\tHyperserveValidationError,\n} from \"./errors.js\";\n\ninterface RequestOptions {\n\tmethod: \"GET\" | \"POST\" | \"DELETE\";\n\turl: string;\n\tapiKey: string;\n\ttimeoutMs: number;\n\tbody?: unknown;\n\tretries?: number;\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryable(err: unknown): boolean {\n\t// Retry on 5xx API errors only — not 4xx, not timeouts\n\tif (err instanceof HyperserveApiError && err.statusCode !== undefined && err.statusCode >= 500)\n\t\treturn true;\n\t// Retry on network/infrastructure errors that aren't SDK-typed (e.g. TypeError: Failed to fetch)\n\tif (err instanceof Error && !(err instanceof HyperserveError)) return true;\n\treturn false;\n}\n\nexport async function apiRequest<T>(options: RequestOptions): Promise<T> {\n\tconst { retries = 0 } = options;\n\tlet attempt = 0;\n\n\twhile (true) {\n\t\ttry {\n\t\t\treturn await attemptRequest<T>(options);\n\t\t} catch (err) {\n\t\t\tif (attempt >= retries || !isRetryable(err)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\t// Full jitter: random delay up to min(10s, 100ms × 2^attempt)\n\t\t\tconst delay = Math.random() * Math.min(10_000, 100 * 2 ** attempt);\n\t\t\tawait sleep(delay);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\nasync function attemptRequest<T>(options: RequestOptions): Promise<T> {\n\tconst { method, url, apiKey, timeoutMs, body } = options;\n\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\n\tlet response: Response;\n\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\t\"X-API-KEY\": apiKey,\n\t\t\t\t...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n\t\t\t},\n\t\t\t// Omit body entirely when not present — passing body: null on DELETE requests\n\t\t\t// can be treated differently by some proxies and intermediaries.\n\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\tsignal: controller.signal,\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof Error && err.name === \"AbortError\") {\n\t\t\tthrow new HyperserveTimeoutError(`Request to ${url} timed out after ${timeoutMs}ms`);\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n\n\tif (response.ok) {\n\t\t// 204 No Content\n\t\tif (response.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\ttry {\n\t\t\treturn (await response.json()) as T;\n\t\t} catch {\n\t\t\tthrow new HyperserveApiError(`Failed to parse response from ${url}`, response.status);\n\t\t}\n\t}\n\n\tlet errorBody: { message?: string } = {};\n\ttry {\n\t\terrorBody = (await response.json()) as { message?: string };\n\t} catch {\n\t\t// ignore parse failure — use status text\n\t}\n\n\tconst message = errorBody.message ?? response.statusText;\n\n\tif (response.status === 404) {\n\t\tthrow new HyperserveNotFoundError(message);\n\t}\n\n\tif (response.status >= 400 && response.status < 500) {\n\t\tthrow new HyperserveValidationError(message, response.status, errorBody);\n\t}\n\n\tthrow new HyperserveApiError(message, response.status);\n}\n","/**\n * Normalizes the various accepted file input types into a { body, size } pair\n * suitable for use as a fetch/XHR request body.\n *\n * Size inference rules:\n * Blob / File → blob.size\n * Buffer → buffer.byteLength\n * ReadableStream → must be provided via fileSizeBytes\n */\nexport interface NormalizedFile {\n\tbody: Blob | ReadableStream;\n\tsize: number;\n}\n\nexport function normalizeFile(\n\tfile: Blob | Buffer | ReadableStream,\n\tfilename: string,\n\tfileSizeBytes?: number,\n): NormalizedFile {\n\tif (file instanceof ReadableStream) {\n\t\tif (fileSizeBytes === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"fileSizeBytes is required when file is a ReadableStream (size cannot be inferred)\",\n\t\t\t);\n\t\t}\n\t\treturn { body: file, size: fileSizeBytes };\n\t}\n\n\t// Node.js Buffer. `Buffer` is a Node global; all explicitly supported edge runtimes\n\t// (Cloudflare Workers, Vercel Edge) ship a Buffer compatibility layer, so this is safe\n\t// for the stated server targets. Pure browser or RN bundles never reach this branch\n\t// because normalize.ts is not imported by the browser or react-native entry points.\n\tif (Buffer.isBuffer(file)) {\n\t\tconst size = fileSizeBytes ?? file.byteLength;\n\t\t// Wrap in a Blob so fetch/XHR handle it uniformly\n\t\t// Copy into a plain ArrayBuffer to avoid SharedArrayBuffer assignability issues\n\t\tconst blob = new Blob([new Uint8Array(file)], { type: deriveTypeHint(filename) });\n\t\treturn { body: blob, size };\n\t}\n\n\t// Blob / File\n\tconst size = fileSizeBytes ?? file.size;\n\treturn { body: file, size };\n}\n\nfunction deriveTypeHint(filename: string): string {\n\t// Minimal hint — the actual Content-Type for the presigned PUT always\n\t// comes from the server, not from this inference. This is only used\n\t// so the Blob is constructed with a reasonable type attribute.\n\tconst ext = filename.slice(filename.lastIndexOf(\".\") + 1).toLowerCase();\n\tconst map: Record<string, string> = {\n\t\tmp4: \"video/mp4\",\n\t\tmov: \"video/quicktime\",\n\t\twebm: \"video/webm\",\n\t\tavi: \"video/x-msvideo\",\n\t\tmkv: \"video/x-matroska\",\n\t\tm4v: \"video/x-m4v\",\n\t};\n\treturn map[ext] ?? \"application/octet-stream\";\n}\n","import { HyperserveTimeoutError, HyperserveUploadError } from \"./errors.js\";\n\n/**\n * PUT a file to a presigned S3 URL.\n * Used internally by uploadVideo (server) and exported as putVideoToStorage (browser).\n *\n * When onProgress is provided, uses XMLHttpRequest for upload progress events.\n * Falls back to fetch otherwise.\n */\nexport async function putToStorage(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob | ReadableStream,\n\tonProgress?: (percent: number) => void,\n): Promise<void> {\n\t// XHR is used for progress reporting but does not support ReadableStream bodies.\n\t// Fall back to fetch (no progress) when the body is a stream.\n\tif (\n\t\tonProgress !== undefined &&\n\t\ttypeof XMLHttpRequest !== \"undefined\" &&\n\t\t!(body instanceof ReadableStream)\n\t) {\n\t\treturn putWithXhr(uploadUrl, contentType, body, onProgress);\n\t}\n\treturn putWithFetch(uploadUrl, contentType, body);\n}\n\nfunction putWithFetch(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob | ReadableStream,\n): Promise<void> {\n\treturn fetch(uploadUrl, {\n\t\tmethod: \"PUT\",\n\t\theaders: { \"Content-Type\": contentType },\n\t\t// duplex is required for ReadableStream bodies in some runtimes (Node 18)\n\t\t...(body instanceof ReadableStream ? { duplex: \"half\" } : {}),\n\t\tbody: body as BodyInit,\n\t}).then((response) => {\n\t\tif (!response.ok) {\n\t\t\tthrow new HyperserveUploadError(\n\t\t\t\t`Storage PUT failed with status ${response.status}`,\n\t\t\t\tresponse.status,\n\t\t\t);\n\t\t}\n\t});\n}\n\nfunction putWithXhr(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob,\n\tonProgress: (percent: number) => void,\n): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open(\"PUT\", uploadUrl);\n\t\txhr.setRequestHeader(\"Content-Type\", contentType);\n\n\t\txhr.upload.addEventListener(\"progress\", (event) => {\n\t\t\tif (event.lengthComputable) {\n\t\t\t\tonProgress(Math.round((event.loaded / event.total) * 100));\n\t\t\t}\n\t\t});\n\n\t\txhr.addEventListener(\"load\", () => {\n\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\n\t\t\t\tonProgress(100);\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(\n\t\t\t\t\tnew HyperserveUploadError(`Storage PUT failed with status ${xhr.status}`, xhr.status),\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\txhr.addEventListener(\"timeout\", () => {\n\t\t\treject(new HyperserveTimeoutError(\"Storage PUT timed out\"));\n\t\t});\n\n\t\txhr.addEventListener(\"error\", () => {\n\t\t\treject(new HyperserveUploadError(\"Storage PUT failed due to a network error\"));\n\t\t});\n\n\t\txhr.send(body);\n\t});\n}\n","import { apiRequest } from \"./http.js\";\nimport { normalizeFile } from \"./normalize.js\";\nimport { putToStorage } from \"./storage.js\";\nimport type {\n\tCompleteUploadResult,\n\tCreateVideoOptions,\n\tCreateVideoResult,\n\tGetVideoOptions,\n\tHyperserveClientOptions,\n\tUploadVideoOptions,\n\tVideoResult,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.hyperserve.io/api\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport class HyperserveClient {\n\tprivate readonly apiKey: string;\n\tprivate readonly baseUrl: string;\n\tprivate readonly timeoutMs: number;\n\tprivate readonly retries: number;\n\n\tconstructor(options: HyperserveClientOptions) {\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.baseUrl = options.baseUrl?.replace(/\\/$/, \"\") ?? DEFAULT_BASE_URL;\n\t\tthis.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\t\tthis.retries = options.retries ?? 0;\n\t}\n\n\t/**\n\t * Creates a video record and returns a presigned upload URL.\n\t * Pass uploadUrl and contentType to your frontend so it can PUT the file directly to storage.\n\t * Call completeUpload once the frontend confirms the PUT is done.\n\t */\n\tasync createVideo(options: CreateVideoOptions): Promise<CreateVideoResult> {\n\t\treturn apiRequest<CreateVideoResult>({\n\t\t\tmethod: \"POST\",\n\t\t\turl: `${this.baseUrl}/video`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t\tbody: {\n\t\t\t\tfilename: options.filename,\n\t\t\t\tfileSizeBytes: options.fileSizeBytes,\n\t\t\t\tresolutions: options.resolutions,\n\t\t\t\tisPublic: options.isPublic,\n\t\t\t\t...(options.thumbnailTimestampsSeconds !== undefined && {\n\t\t\t\t\tthumbnail_timestamps_seconds: options.thumbnailTimestampsSeconds,\n\t\t\t\t}),\n\t\t\t\t...(options.customMetadata !== undefined && {\n\t\t\t\t\tcustom_user_metadata: options.customMetadata,\n\t\t\t\t}),\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Notifies Hyperserve that the file has been uploaded to the presigned URL.\n\t * Hyperserve verifies the object and queues transcoding.\n\t * Call this after your frontend confirms the storage PUT is complete.\n\t */\n\tasync completeUpload(videoId: string): Promise<CompleteUploadResult> {\n\t\treturn apiRequest<CompleteUploadResult>({\n\t\t\tmethod: \"POST\",\n\t\t\turl: `${this.baseUrl}/video/${videoId}/complete-upload`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Retrieves the current state of a video, including per-resolution status and playback URLs.\n\t *\n\t * @param videoId - The video ID returned by createVideo or uploadVideo.\n\t * @param options.private - Return time-limited signed URLs instead of public URLs.\n\t * @param options.expirationSeconds - Signed URL TTL when private is true. Defaults to 3600.\n\t */\n\tasync getVideo(videoId: string, options?: GetVideoOptions): Promise<VideoResult> {\n\t\tconst isPrivate = options?.private === true;\n\t\tconst expiration = options?.expirationSeconds ?? 3600;\n\n\t\tconst url = isPrivate\n\t\t\t? `${this.baseUrl}/video/${videoId}/private/${expiration}`\n\t\t\t: `${this.baseUrl}/video/${videoId}/public`;\n\n\t\treturn apiRequest<VideoResult>({\n\t\t\tmethod: \"GET\",\n\t\t\turl,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes a video and all associated resolutions and thumbnails.\n\t */\n\tasync deleteVideo(videoId: string): Promise<void> {\n\t\treturn apiRequest<void>({\n\t\t\tmethod: \"DELETE\",\n\t\t\turl: `${this.baseUrl}/video/${videoId}`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes a single resolution for a video.\n\t */\n\tasync deleteResolution(resolutionId: string): Promise<void> {\n\t\treturn apiRequest<void>({\n\t\t\tmethod: \"DELETE\",\n\t\t\turl: `${this.baseUrl}/video/resolution/${resolutionId}`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Convenience method for server-side / script use cases.\n\t * Wraps createVideo, the storage PUT, and completeUpload into a single call.\n\t *\n\t * Not suitable for the browser proxy pattern — use createVideo + putVideoToStorage\n\t * from '@hyperserve/hyperserve-js/browser' + completeUpload separately for that flow.\n\t */\n\tasync uploadVideo(options: UploadVideoOptions): Promise<CompleteUploadResult> {\n\t\tconst { file, filename, resolutions, isPublic, thumbnailTimestampsSeconds, customMetadata } =\n\t\t\toptions;\n\n\t\tconst normalized = normalizeFile(file, filename, options.fileSizeBytes);\n\n\t\tconst upload = await this.createVideo({\n\t\t\tfilename,\n\t\t\tfileSizeBytes: normalized.size,\n\t\t\tresolutions,\n\t\t\tisPublic,\n\t\t\t...(thumbnailTimestampsSeconds !== undefined && { thumbnailTimestampsSeconds }),\n\t\t\t...(customMetadata !== undefined && { customMetadata }),\n\t\t});\n\n\t\tawait putToStorage(upload.uploadUrl, upload.contentType, normalized.body);\n\n\t\treturn this.completeUpload(upload.id);\n\t}\n}\n","import type { VerifyWebhookSignatureOptions } from \"./types.js\";\n\nconst DEFAULT_TOLERANCE_MS = 300_000; // 5 minutes — matches server-side enforcement\n\n/**\n * Verifies the x-hyperserve-signature header on an incoming webhook request.\n *\n * The signature header has the format \"{timestampMs}.{hmac-sha256-hex}\", where the HMAC\n * is computed over \"{timestampMs}.{rawBody}\" using your webhook signing secret. This proves\n * both when the request was sent (replay protection) and that the body was not tampered with\n * (integrity). Any modification to the body or timestamp will invalidate the signature.\n *\n * Returns true if the signature is valid and the timestamp is within the tolerance window.\n * Returns false if the signature is invalid, the timestamp has expired, or the header is malformed.\n *\n * Uses the Web Crypto API for a constant-time HMAC comparison — safe on Node 18+, Bun, Deno,\n * Cloudflare Workers, Vercel Edge, and all other supported server environments.\n *\n * IMPORTANT: pass the raw request body string exactly as received. Do not parse and re-serialize\n * JSON — any whitespace difference will invalidate the signature.\n *\n * @example\n * import { verifyWebhookSignature } from '@hyperserve/hyperserve-js';\n *\n * // Express (use express.raw, not express.json, so you get the raw body)\n * app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {\n * const isValid = await verifyWebhookSignature({\n * signature: req.headers['x-hyperserve-signature'] ?? '',\n * secret: process.env.HYPERSERVE_WEBHOOK_SECRET,\n * body: req.body.toString(),\n * });\n * if (!isValid) return res.status(401).end();\n * });\n *\n * // Next.js App Router\n * const body = await request.text();\n * const isValid = await verifyWebhookSignature({\n * signature: request.headers.get('x-hyperserve-signature') ?? '',\n * secret: process.env.HYPERSERVE_WEBHOOK_SECRET!,\n * body,\n * });\n */\nexport async function verifyWebhookSignature(\n\toptions: VerifyWebhookSignatureOptions,\n): Promise<boolean> {\n\tconst { signature, secret, body, toleranceMs = DEFAULT_TOLERANCE_MS } = options;\n\n\tconst dotIndex = signature.indexOf(\".\");\n\tif (dotIndex === -1) return false;\n\n\tconst timestampStr = signature.slice(0, dotIndex);\n\tconst receivedHex = signature.slice(dotIndex + 1);\n\n\t// Validate timestamp is a non-negative integer\n\tconst timestamp = Number(timestampStr);\n\tif (!Number.isInteger(timestamp) || timestamp < 0) return false;\n\n\t// Reject if timestamp is outside the tolerance window.\n\t// Math.abs handles future timestamps (clock skew or forged headers) — without it,\n\t// a negative difference would never exceed toleranceMs, accepting the signature forever.\n\tif (Math.abs(Date.now() - timestamp) > toleranceMs) return false;\n\n\tconst receivedBytes = hexToBytes(receivedHex);\n\tif (receivedBytes === null) return false;\n\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"verify\"],\n\t);\n\n\t// The signed message is \"{timestampMs}.{rawBody}\" — covers both freshness and integrity.\n\t// crypto.subtle.verify performs a constant-time comparison.\n\treturn crypto.subtle.verify(\n\t\t\"HMAC\",\n\t\tkey,\n\t\treceivedBytes,\n\t\tencoder.encode(`${timestampStr}.${body}`),\n\t);\n}\n\nfunction hexToBytes(hex: string): Uint8Array<ArrayBuffer> | null {\n\tif (hex.length === 0 || hex.length % 2 !== 0) return null;\n\tconst bytes = new Uint8Array(new ArrayBuffer(hex.length / 2));\n\tfor (let i = 0; i < hex.length; i += 2) {\n\t\tconst value = parseInt(hex.slice(i, i + 2), 16);\n\t\tif (Number.isNaN(value)) return null;\n\t\tbytes[i / 2] = value;\n\t}\n\treturn bytes;\n}\n"]}
@@ -0,0 +1,88 @@
1
+ import { H as HyperserveClientOptions, C as CreateVideoOptions, a as CreateVideoResult, b as CompleteUploadResult, G as GetVideoOptions, V as VideoResult, U as UploadVideoOptions, c as VerifyWebhookSignatureOptions } from './errors-C89laaKB.cjs';
2
+ export { d as HyperserveApiError, e as HyperserveError, f as HyperserveNotFoundError, g as HyperserveTimeoutError, h as HyperserveUploadError, i as HyperserveValidationError, P as PutVideoToStorageOptions, j as PutVideoToStorageRNOptions, k as VideoResolution, l as VideoResolutionResult, m as VideoStatus } from './errors-C89laaKB.cjs';
3
+
4
+ declare class HyperserveClient {
5
+ private readonly apiKey;
6
+ private readonly baseUrl;
7
+ private readonly timeoutMs;
8
+ private readonly retries;
9
+ constructor(options: HyperserveClientOptions);
10
+ /**
11
+ * Creates a video record and returns a presigned upload URL.
12
+ * Pass uploadUrl and contentType to your frontend so it can PUT the file directly to storage.
13
+ * Call completeUpload once the frontend confirms the PUT is done.
14
+ */
15
+ createVideo(options: CreateVideoOptions): Promise<CreateVideoResult>;
16
+ /**
17
+ * Notifies Hyperserve that the file has been uploaded to the presigned URL.
18
+ * Hyperserve verifies the object and queues transcoding.
19
+ * Call this after your frontend confirms the storage PUT is complete.
20
+ */
21
+ completeUpload(videoId: string): Promise<CompleteUploadResult>;
22
+ /**
23
+ * Retrieves the current state of a video, including per-resolution status and playback URLs.
24
+ *
25
+ * @param videoId - The video ID returned by createVideo or uploadVideo.
26
+ * @param options.private - Return time-limited signed URLs instead of public URLs.
27
+ * @param options.expirationSeconds - Signed URL TTL when private is true. Defaults to 3600.
28
+ */
29
+ getVideo(videoId: string, options?: GetVideoOptions): Promise<VideoResult>;
30
+ /**
31
+ * Deletes a video and all associated resolutions and thumbnails.
32
+ */
33
+ deleteVideo(videoId: string): Promise<void>;
34
+ /**
35
+ * Deletes a single resolution for a video.
36
+ */
37
+ deleteResolution(resolutionId: string): Promise<void>;
38
+ /**
39
+ * Convenience method for server-side / script use cases.
40
+ * Wraps createVideo, the storage PUT, and completeUpload into a single call.
41
+ *
42
+ * Not suitable for the browser proxy pattern — use createVideo + putVideoToStorage
43
+ * from '@hyperserve/hyperserve-js/browser' + completeUpload separately for that flow.
44
+ */
45
+ uploadVideo(options: UploadVideoOptions): Promise<CompleteUploadResult>;
46
+ }
47
+
48
+ /**
49
+ * Verifies the x-hyperserve-signature header on an incoming webhook request.
50
+ *
51
+ * The signature header has the format "{timestampMs}.{hmac-sha256-hex}", where the HMAC
52
+ * is computed over "{timestampMs}.{rawBody}" using your webhook signing secret. This proves
53
+ * both when the request was sent (replay protection) and that the body was not tampered with
54
+ * (integrity). Any modification to the body or timestamp will invalidate the signature.
55
+ *
56
+ * Returns true if the signature is valid and the timestamp is within the tolerance window.
57
+ * Returns false if the signature is invalid, the timestamp has expired, or the header is malformed.
58
+ *
59
+ * Uses the Web Crypto API for a constant-time HMAC comparison — safe on Node 18+, Bun, Deno,
60
+ * Cloudflare Workers, Vercel Edge, and all other supported server environments.
61
+ *
62
+ * IMPORTANT: pass the raw request body string exactly as received. Do not parse and re-serialize
63
+ * JSON — any whitespace difference will invalidate the signature.
64
+ *
65
+ * @example
66
+ * import { verifyWebhookSignature } from '@hyperserve/hyperserve-js';
67
+ *
68
+ * // Express (use express.raw, not express.json, so you get the raw body)
69
+ * app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
70
+ * const isValid = await verifyWebhookSignature({
71
+ * signature: req.headers['x-hyperserve-signature'] ?? '',
72
+ * secret: process.env.HYPERSERVE_WEBHOOK_SECRET,
73
+ * body: req.body.toString(),
74
+ * });
75
+ * if (!isValid) return res.status(401).end();
76
+ * });
77
+ *
78
+ * // Next.js App Router
79
+ * const body = await request.text();
80
+ * const isValid = await verifyWebhookSignature({
81
+ * signature: request.headers.get('x-hyperserve-signature') ?? '',
82
+ * secret: process.env.HYPERSERVE_WEBHOOK_SECRET!,
83
+ * body,
84
+ * });
85
+ */
86
+ declare function verifyWebhookSignature(options: VerifyWebhookSignatureOptions): Promise<boolean>;
87
+
88
+ export { CompleteUploadResult, CreateVideoOptions, CreateVideoResult, GetVideoOptions, HyperserveClient, HyperserveClientOptions, UploadVideoOptions, VerifyWebhookSignatureOptions, VideoResult, verifyWebhookSignature };
@@ -0,0 +1,88 @@
1
+ import { H as HyperserveClientOptions, C as CreateVideoOptions, a as CreateVideoResult, b as CompleteUploadResult, G as GetVideoOptions, V as VideoResult, U as UploadVideoOptions, c as VerifyWebhookSignatureOptions } from './errors-C89laaKB.js';
2
+ export { d as HyperserveApiError, e as HyperserveError, f as HyperserveNotFoundError, g as HyperserveTimeoutError, h as HyperserveUploadError, i as HyperserveValidationError, P as PutVideoToStorageOptions, j as PutVideoToStorageRNOptions, k as VideoResolution, l as VideoResolutionResult, m as VideoStatus } from './errors-C89laaKB.js';
3
+
4
+ declare class HyperserveClient {
5
+ private readonly apiKey;
6
+ private readonly baseUrl;
7
+ private readonly timeoutMs;
8
+ private readonly retries;
9
+ constructor(options: HyperserveClientOptions);
10
+ /**
11
+ * Creates a video record and returns a presigned upload URL.
12
+ * Pass uploadUrl and contentType to your frontend so it can PUT the file directly to storage.
13
+ * Call completeUpload once the frontend confirms the PUT is done.
14
+ */
15
+ createVideo(options: CreateVideoOptions): Promise<CreateVideoResult>;
16
+ /**
17
+ * Notifies Hyperserve that the file has been uploaded to the presigned URL.
18
+ * Hyperserve verifies the object and queues transcoding.
19
+ * Call this after your frontend confirms the storage PUT is complete.
20
+ */
21
+ completeUpload(videoId: string): Promise<CompleteUploadResult>;
22
+ /**
23
+ * Retrieves the current state of a video, including per-resolution status and playback URLs.
24
+ *
25
+ * @param videoId - The video ID returned by createVideo or uploadVideo.
26
+ * @param options.private - Return time-limited signed URLs instead of public URLs.
27
+ * @param options.expirationSeconds - Signed URL TTL when private is true. Defaults to 3600.
28
+ */
29
+ getVideo(videoId: string, options?: GetVideoOptions): Promise<VideoResult>;
30
+ /**
31
+ * Deletes a video and all associated resolutions and thumbnails.
32
+ */
33
+ deleteVideo(videoId: string): Promise<void>;
34
+ /**
35
+ * Deletes a single resolution for a video.
36
+ */
37
+ deleteResolution(resolutionId: string): Promise<void>;
38
+ /**
39
+ * Convenience method for server-side / script use cases.
40
+ * Wraps createVideo, the storage PUT, and completeUpload into a single call.
41
+ *
42
+ * Not suitable for the browser proxy pattern — use createVideo + putVideoToStorage
43
+ * from '@hyperserve/hyperserve-js/browser' + completeUpload separately for that flow.
44
+ */
45
+ uploadVideo(options: UploadVideoOptions): Promise<CompleteUploadResult>;
46
+ }
47
+
48
+ /**
49
+ * Verifies the x-hyperserve-signature header on an incoming webhook request.
50
+ *
51
+ * The signature header has the format "{timestampMs}.{hmac-sha256-hex}", where the HMAC
52
+ * is computed over "{timestampMs}.{rawBody}" using your webhook signing secret. This proves
53
+ * both when the request was sent (replay protection) and that the body was not tampered with
54
+ * (integrity). Any modification to the body or timestamp will invalidate the signature.
55
+ *
56
+ * Returns true if the signature is valid and the timestamp is within the tolerance window.
57
+ * Returns false if the signature is invalid, the timestamp has expired, or the header is malformed.
58
+ *
59
+ * Uses the Web Crypto API for a constant-time HMAC comparison — safe on Node 18+, Bun, Deno,
60
+ * Cloudflare Workers, Vercel Edge, and all other supported server environments.
61
+ *
62
+ * IMPORTANT: pass the raw request body string exactly as received. Do not parse and re-serialize
63
+ * JSON — any whitespace difference will invalidate the signature.
64
+ *
65
+ * @example
66
+ * import { verifyWebhookSignature } from '@hyperserve/hyperserve-js';
67
+ *
68
+ * // Express (use express.raw, not express.json, so you get the raw body)
69
+ * app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {
70
+ * const isValid = await verifyWebhookSignature({
71
+ * signature: req.headers['x-hyperserve-signature'] ?? '',
72
+ * secret: process.env.HYPERSERVE_WEBHOOK_SECRET,
73
+ * body: req.body.toString(),
74
+ * });
75
+ * if (!isValid) return res.status(401).end();
76
+ * });
77
+ *
78
+ * // Next.js App Router
79
+ * const body = await request.text();
80
+ * const isValid = await verifyWebhookSignature({
81
+ * signature: request.headers.get('x-hyperserve-signature') ?? '',
82
+ * secret: process.env.HYPERSERVE_WEBHOOK_SECRET!,
83
+ * body,
84
+ * });
85
+ */
86
+ declare function verifyWebhookSignature(options: VerifyWebhookSignatureOptions): Promise<boolean>;
87
+
88
+ export { CompleteUploadResult, CreateVideoOptions, CreateVideoResult, GetVideoOptions, HyperserveClient, HyperserveClientOptions, UploadVideoOptions, VerifyWebhookSignatureOptions, VideoResult, verifyWebhookSignature };
package/dist/index.js ADDED
@@ -0,0 +1,333 @@
1
+ // src/errors.ts
2
+ var HyperserveError = class extends Error {
3
+ constructor(message, statusCode) {
4
+ super(message);
5
+ this.statusCode = statusCode;
6
+ this.name = "HyperserveError";
7
+ Object.setPrototypeOf(this, new.target.prototype);
8
+ }
9
+ };
10
+ var HyperserveValidationError = class extends HyperserveError {
11
+ constructor(message, statusCode, detail) {
12
+ super(message, statusCode);
13
+ this.detail = detail;
14
+ this.name = "HyperserveValidationError";
15
+ Object.setPrototypeOf(this, new.target.prototype);
16
+ }
17
+ };
18
+ var HyperserveNotFoundError = class extends HyperserveError {
19
+ constructor(message = "Resource not found") {
20
+ super(message, 404);
21
+ this.name = "HyperserveNotFoundError";
22
+ Object.setPrototypeOf(this, new.target.prototype);
23
+ }
24
+ };
25
+ var HyperserveApiError = class extends HyperserveError {
26
+ constructor(message, statusCode) {
27
+ super(message, statusCode);
28
+ this.name = "HyperserveApiError";
29
+ Object.setPrototypeOf(this, new.target.prototype);
30
+ }
31
+ };
32
+ var HyperserveUploadError = class extends HyperserveError {
33
+ constructor(message, uploadStatus) {
34
+ super(message);
35
+ this.uploadStatus = uploadStatus;
36
+ this.name = "HyperserveUploadError";
37
+ Object.setPrototypeOf(this, new.target.prototype);
38
+ }
39
+ };
40
+ var HyperserveTimeoutError = class extends HyperserveError {
41
+ constructor(message = "Request timed out") {
42
+ super(message);
43
+ this.name = "HyperserveTimeoutError";
44
+ Object.setPrototypeOf(this, new.target.prototype);
45
+ }
46
+ };
47
+
48
+ // src/http.ts
49
+ function sleep(ms) {
50
+ return new Promise((resolve) => setTimeout(resolve, ms));
51
+ }
52
+ function isRetryable(err) {
53
+ if (err instanceof HyperserveApiError && err.statusCode !== void 0 && err.statusCode >= 500)
54
+ return true;
55
+ if (err instanceof Error && !(err instanceof HyperserveError)) return true;
56
+ return false;
57
+ }
58
+ async function apiRequest(options) {
59
+ const { retries = 0 } = options;
60
+ let attempt = 0;
61
+ while (true) {
62
+ try {
63
+ return await attemptRequest(options);
64
+ } catch (err) {
65
+ if (attempt >= retries || !isRetryable(err)) {
66
+ throw err;
67
+ }
68
+ const delay = Math.random() * Math.min(1e4, 100 * 2 ** attempt);
69
+ await sleep(delay);
70
+ attempt++;
71
+ }
72
+ }
73
+ }
74
+ async function attemptRequest(options) {
75
+ const { method, url, apiKey, timeoutMs, body } = options;
76
+ const controller = new AbortController();
77
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
78
+ let response;
79
+ try {
80
+ response = await fetch(url, {
81
+ method,
82
+ headers: {
83
+ "X-API-KEY": apiKey,
84
+ ...body !== void 0 ? { "Content-Type": "application/json" } : {}
85
+ },
86
+ // Omit body entirely when not present — passing body: null on DELETE requests
87
+ // can be treated differently by some proxies and intermediaries.
88
+ ...body !== void 0 ? { body: JSON.stringify(body) } : {},
89
+ signal: controller.signal
90
+ });
91
+ } catch (err) {
92
+ if (err instanceof Error && err.name === "AbortError") {
93
+ throw new HyperserveTimeoutError(`Request to ${url} timed out after ${timeoutMs}ms`);
94
+ }
95
+ throw err;
96
+ } finally {
97
+ clearTimeout(timer);
98
+ }
99
+ if (response.ok) {
100
+ if (response.status === 204) {
101
+ return void 0;
102
+ }
103
+ try {
104
+ return await response.json();
105
+ } catch {
106
+ throw new HyperserveApiError(`Failed to parse response from ${url}`, response.status);
107
+ }
108
+ }
109
+ let errorBody = {};
110
+ try {
111
+ errorBody = await response.json();
112
+ } catch {
113
+ }
114
+ const message = errorBody.message ?? response.statusText;
115
+ if (response.status === 404) {
116
+ throw new HyperserveNotFoundError(message);
117
+ }
118
+ if (response.status >= 400 && response.status < 500) {
119
+ throw new HyperserveValidationError(message, response.status, errorBody);
120
+ }
121
+ throw new HyperserveApiError(message, response.status);
122
+ }
123
+
124
+ // src/normalize.ts
125
+ function normalizeFile(file, filename, fileSizeBytes) {
126
+ if (file instanceof ReadableStream) {
127
+ if (fileSizeBytes === void 0) {
128
+ throw new TypeError(
129
+ "fileSizeBytes is required when file is a ReadableStream (size cannot be inferred)"
130
+ );
131
+ }
132
+ return { body: file, size: fileSizeBytes };
133
+ }
134
+ if (Buffer.isBuffer(file)) {
135
+ const size2 = fileSizeBytes ?? file.byteLength;
136
+ const blob = new Blob([new Uint8Array(file)], { type: deriveTypeHint(filename) });
137
+ return { body: blob, size: size2 };
138
+ }
139
+ const size = fileSizeBytes ?? file.size;
140
+ return { body: file, size };
141
+ }
142
+ function deriveTypeHint(filename) {
143
+ const ext = filename.slice(filename.lastIndexOf(".") + 1).toLowerCase();
144
+ const map = {
145
+ mp4: "video/mp4",
146
+ mov: "video/quicktime",
147
+ webm: "video/webm",
148
+ avi: "video/x-msvideo",
149
+ mkv: "video/x-matroska",
150
+ m4v: "video/x-m4v"
151
+ };
152
+ return map[ext] ?? "application/octet-stream";
153
+ }
154
+
155
+ // src/storage.ts
156
+ async function putToStorage(uploadUrl, contentType, body, onProgress) {
157
+ return putWithFetch(uploadUrl, contentType, body);
158
+ }
159
+ function putWithFetch(uploadUrl, contentType, body) {
160
+ return fetch(uploadUrl, {
161
+ method: "PUT",
162
+ headers: { "Content-Type": contentType },
163
+ // duplex is required for ReadableStream bodies in some runtimes (Node 18)
164
+ ...body instanceof ReadableStream ? { duplex: "half" } : {},
165
+ body
166
+ }).then((response) => {
167
+ if (!response.ok) {
168
+ throw new HyperserveUploadError(
169
+ `Storage PUT failed with status ${response.status}`,
170
+ response.status
171
+ );
172
+ }
173
+ });
174
+ }
175
+
176
+ // src/client.ts
177
+ var DEFAULT_BASE_URL = "https://api.hyperserve.io/api";
178
+ var DEFAULT_TIMEOUT_MS = 3e4;
179
+ var HyperserveClient = class {
180
+ constructor(options) {
181
+ this.apiKey = options.apiKey;
182
+ this.baseUrl = options.baseUrl?.replace(/\/$/, "") ?? DEFAULT_BASE_URL;
183
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
184
+ this.retries = options.retries ?? 0;
185
+ }
186
+ /**
187
+ * Creates a video record and returns a presigned upload URL.
188
+ * Pass uploadUrl and contentType to your frontend so it can PUT the file directly to storage.
189
+ * Call completeUpload once the frontend confirms the PUT is done.
190
+ */
191
+ async createVideo(options) {
192
+ return apiRequest({
193
+ method: "POST",
194
+ url: `${this.baseUrl}/video`,
195
+ apiKey: this.apiKey,
196
+ timeoutMs: this.timeoutMs,
197
+ retries: this.retries,
198
+ body: {
199
+ filename: options.filename,
200
+ fileSizeBytes: options.fileSizeBytes,
201
+ resolutions: options.resolutions,
202
+ isPublic: options.isPublic,
203
+ ...options.thumbnailTimestampsSeconds !== void 0 && {
204
+ thumbnail_timestamps_seconds: options.thumbnailTimestampsSeconds
205
+ },
206
+ ...options.customMetadata !== void 0 && {
207
+ custom_user_metadata: options.customMetadata
208
+ }
209
+ }
210
+ });
211
+ }
212
+ /**
213
+ * Notifies Hyperserve that the file has been uploaded to the presigned URL.
214
+ * Hyperserve verifies the object and queues transcoding.
215
+ * Call this after your frontend confirms the storage PUT is complete.
216
+ */
217
+ async completeUpload(videoId) {
218
+ return apiRequest({
219
+ method: "POST",
220
+ url: `${this.baseUrl}/video/${videoId}/complete-upload`,
221
+ apiKey: this.apiKey,
222
+ timeoutMs: this.timeoutMs,
223
+ retries: this.retries
224
+ });
225
+ }
226
+ /**
227
+ * Retrieves the current state of a video, including per-resolution status and playback URLs.
228
+ *
229
+ * @param videoId - The video ID returned by createVideo or uploadVideo.
230
+ * @param options.private - Return time-limited signed URLs instead of public URLs.
231
+ * @param options.expirationSeconds - Signed URL TTL when private is true. Defaults to 3600.
232
+ */
233
+ async getVideo(videoId, options) {
234
+ const isPrivate = options?.private === true;
235
+ const expiration = options?.expirationSeconds ?? 3600;
236
+ const url = isPrivate ? `${this.baseUrl}/video/${videoId}/private/${expiration}` : `${this.baseUrl}/video/${videoId}/public`;
237
+ return apiRequest({
238
+ method: "GET",
239
+ url,
240
+ apiKey: this.apiKey,
241
+ timeoutMs: this.timeoutMs,
242
+ retries: this.retries
243
+ });
244
+ }
245
+ /**
246
+ * Deletes a video and all associated resolutions and thumbnails.
247
+ */
248
+ async deleteVideo(videoId) {
249
+ return apiRequest({
250
+ method: "DELETE",
251
+ url: `${this.baseUrl}/video/${videoId}`,
252
+ apiKey: this.apiKey,
253
+ timeoutMs: this.timeoutMs,
254
+ retries: this.retries
255
+ });
256
+ }
257
+ /**
258
+ * Deletes a single resolution for a video.
259
+ */
260
+ async deleteResolution(resolutionId) {
261
+ return apiRequest({
262
+ method: "DELETE",
263
+ url: `${this.baseUrl}/video/resolution/${resolutionId}`,
264
+ apiKey: this.apiKey,
265
+ timeoutMs: this.timeoutMs,
266
+ retries: this.retries
267
+ });
268
+ }
269
+ /**
270
+ * Convenience method for server-side / script use cases.
271
+ * Wraps createVideo, the storage PUT, and completeUpload into a single call.
272
+ *
273
+ * Not suitable for the browser proxy pattern — use createVideo + putVideoToStorage
274
+ * from '@hyperserve/hyperserve-js/browser' + completeUpload separately for that flow.
275
+ */
276
+ async uploadVideo(options) {
277
+ const { file, filename, resolutions, isPublic, thumbnailTimestampsSeconds, customMetadata } = options;
278
+ const normalized = normalizeFile(file, filename, options.fileSizeBytes);
279
+ const upload = await this.createVideo({
280
+ filename,
281
+ fileSizeBytes: normalized.size,
282
+ resolutions,
283
+ isPublic,
284
+ ...thumbnailTimestampsSeconds !== void 0 && { thumbnailTimestampsSeconds },
285
+ ...customMetadata !== void 0 && { customMetadata }
286
+ });
287
+ await putToStorage(upload.uploadUrl, upload.contentType, normalized.body);
288
+ return this.completeUpload(upload.id);
289
+ }
290
+ };
291
+
292
+ // src/webhook.ts
293
+ var DEFAULT_TOLERANCE_MS = 3e5;
294
+ async function verifyWebhookSignature(options) {
295
+ const { signature, secret, body, toleranceMs = DEFAULT_TOLERANCE_MS } = options;
296
+ const dotIndex = signature.indexOf(".");
297
+ if (dotIndex === -1) return false;
298
+ const timestampStr = signature.slice(0, dotIndex);
299
+ const receivedHex = signature.slice(dotIndex + 1);
300
+ const timestamp = Number(timestampStr);
301
+ if (!Number.isInteger(timestamp) || timestamp < 0) return false;
302
+ if (Math.abs(Date.now() - timestamp) > toleranceMs) return false;
303
+ const receivedBytes = hexToBytes(receivedHex);
304
+ if (receivedBytes === null) return false;
305
+ const encoder = new TextEncoder();
306
+ const key = await crypto.subtle.importKey(
307
+ "raw",
308
+ encoder.encode(secret),
309
+ { name: "HMAC", hash: "SHA-256" },
310
+ false,
311
+ ["verify"]
312
+ );
313
+ return crypto.subtle.verify(
314
+ "HMAC",
315
+ key,
316
+ receivedBytes,
317
+ encoder.encode(`${timestampStr}.${body}`)
318
+ );
319
+ }
320
+ function hexToBytes(hex) {
321
+ if (hex.length === 0 || hex.length % 2 !== 0) return null;
322
+ const bytes = new Uint8Array(new ArrayBuffer(hex.length / 2));
323
+ for (let i = 0; i < hex.length; i += 2) {
324
+ const value = parseInt(hex.slice(i, i + 2), 16);
325
+ if (Number.isNaN(value)) return null;
326
+ bytes[i / 2] = value;
327
+ }
328
+ return bytes;
329
+ }
330
+
331
+ export { HyperserveApiError, HyperserveClient, HyperserveError, HyperserveNotFoundError, HyperserveTimeoutError, HyperserveUploadError, HyperserveValidationError, verifyWebhookSignature };
332
+ //# sourceMappingURL=index.js.map
333
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/normalize.ts","../src/storage.ts","../src/client.ts","../src/webhook.ts"],"names":["size"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Base class for all Hyperserve SDK errors.\n */\nexport class HyperserveError extends Error {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly statusCode?: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveError\";\n\t\t// Maintain proper prototype chain in transpiled environments\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 4xx response.\n * Typically indicates a validation problem: unsupported file format,\n * file too large, invalid resolutions, video not in expected state, etc.\n */\nexport class HyperserveValidationError extends HyperserveError {\n\tconstructor(\n\t\tmessage: string,\n\t\tstatusCode: number,\n\t\tpublic readonly detail?: unknown,\n\t) {\n\t\tsuper(message, statusCode);\n\t\tthis.name = \"HyperserveValidationError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 404 response.\n */\nexport class HyperserveNotFoundError extends HyperserveError {\n\tconstructor(message = \"Resource not found\") {\n\t\tsuper(message, 404);\n\t\tthis.name = \"HyperserveNotFoundError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The Hyperserve API returned a 5xx response.\n */\nexport class HyperserveApiError extends HyperserveError {\n\tconstructor(message: string, statusCode: number) {\n\t\tsuper(message, statusCode);\n\t\tthis.name = \"HyperserveApiError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * The storage PUT request failed.\n */\nexport class HyperserveUploadError extends HyperserveError {\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly uploadStatus?: number,\n\t) {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveUploadError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n\n/**\n * A request exceeded the configured timeoutMs.\n */\nexport class HyperserveTimeoutError extends HyperserveError {\n\tconstructor(message = \"Request timed out\") {\n\t\tsuper(message);\n\t\tthis.name = \"HyperserveTimeoutError\";\n\t\tObject.setPrototypeOf(this, new.target.prototype);\n\t}\n}\n","import {\n\tHyperserveApiError,\n\tHyperserveError,\n\tHyperserveNotFoundError,\n\tHyperserveTimeoutError,\n\tHyperserveValidationError,\n} from \"./errors.js\";\n\ninterface RequestOptions {\n\tmethod: \"GET\" | \"POST\" | \"DELETE\";\n\turl: string;\n\tapiKey: string;\n\ttimeoutMs: number;\n\tbody?: unknown;\n\tretries?: number;\n}\n\nfunction sleep(ms: number): Promise<void> {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryable(err: unknown): boolean {\n\t// Retry on 5xx API errors only — not 4xx, not timeouts\n\tif (err instanceof HyperserveApiError && err.statusCode !== undefined && err.statusCode >= 500)\n\t\treturn true;\n\t// Retry on network/infrastructure errors that aren't SDK-typed (e.g. TypeError: Failed to fetch)\n\tif (err instanceof Error && !(err instanceof HyperserveError)) return true;\n\treturn false;\n}\n\nexport async function apiRequest<T>(options: RequestOptions): Promise<T> {\n\tconst { retries = 0 } = options;\n\tlet attempt = 0;\n\n\twhile (true) {\n\t\ttry {\n\t\t\treturn await attemptRequest<T>(options);\n\t\t} catch (err) {\n\t\t\tif (attempt >= retries || !isRetryable(err)) {\n\t\t\t\tthrow err;\n\t\t\t}\n\t\t\t// Full jitter: random delay up to min(10s, 100ms × 2^attempt)\n\t\t\tconst delay = Math.random() * Math.min(10_000, 100 * 2 ** attempt);\n\t\t\tawait sleep(delay);\n\t\t\tattempt++;\n\t\t}\n\t}\n}\n\nasync function attemptRequest<T>(options: RequestOptions): Promise<T> {\n\tconst { method, url, apiKey, timeoutMs, body } = options;\n\n\tconst controller = new AbortController();\n\tconst timer = setTimeout(() => controller.abort(), timeoutMs);\n\n\tlet response: Response;\n\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tmethod,\n\t\t\theaders: {\n\t\t\t\t\"X-API-KEY\": apiKey,\n\t\t\t\t...(body !== undefined ? { \"Content-Type\": \"application/json\" } : {}),\n\t\t\t},\n\t\t\t// Omit body entirely when not present — passing body: null on DELETE requests\n\t\t\t// can be treated differently by some proxies and intermediaries.\n\t\t\t...(body !== undefined ? { body: JSON.stringify(body) } : {}),\n\t\t\tsignal: controller.signal,\n\t\t});\n\t} catch (err) {\n\t\tif (err instanceof Error && err.name === \"AbortError\") {\n\t\t\tthrow new HyperserveTimeoutError(`Request to ${url} timed out after ${timeoutMs}ms`);\n\t\t}\n\t\tthrow err;\n\t} finally {\n\t\tclearTimeout(timer);\n\t}\n\n\tif (response.ok) {\n\t\t// 204 No Content\n\t\tif (response.status === 204) {\n\t\t\treturn undefined as T;\n\t\t}\n\t\ttry {\n\t\t\treturn (await response.json()) as T;\n\t\t} catch {\n\t\t\tthrow new HyperserveApiError(`Failed to parse response from ${url}`, response.status);\n\t\t}\n\t}\n\n\tlet errorBody: { message?: string } = {};\n\ttry {\n\t\terrorBody = (await response.json()) as { message?: string };\n\t} catch {\n\t\t// ignore parse failure — use status text\n\t}\n\n\tconst message = errorBody.message ?? response.statusText;\n\n\tif (response.status === 404) {\n\t\tthrow new HyperserveNotFoundError(message);\n\t}\n\n\tif (response.status >= 400 && response.status < 500) {\n\t\tthrow new HyperserveValidationError(message, response.status, errorBody);\n\t}\n\n\tthrow new HyperserveApiError(message, response.status);\n}\n","/**\n * Normalizes the various accepted file input types into a { body, size } pair\n * suitable for use as a fetch/XHR request body.\n *\n * Size inference rules:\n * Blob / File → blob.size\n * Buffer → buffer.byteLength\n * ReadableStream → must be provided via fileSizeBytes\n */\nexport interface NormalizedFile {\n\tbody: Blob | ReadableStream;\n\tsize: number;\n}\n\nexport function normalizeFile(\n\tfile: Blob | Buffer | ReadableStream,\n\tfilename: string,\n\tfileSizeBytes?: number,\n): NormalizedFile {\n\tif (file instanceof ReadableStream) {\n\t\tif (fileSizeBytes === undefined) {\n\t\t\tthrow new TypeError(\n\t\t\t\t\"fileSizeBytes is required when file is a ReadableStream (size cannot be inferred)\",\n\t\t\t);\n\t\t}\n\t\treturn { body: file, size: fileSizeBytes };\n\t}\n\n\t// Node.js Buffer. `Buffer` is a Node global; all explicitly supported edge runtimes\n\t// (Cloudflare Workers, Vercel Edge) ship a Buffer compatibility layer, so this is safe\n\t// for the stated server targets. Pure browser or RN bundles never reach this branch\n\t// because normalize.ts is not imported by the browser or react-native entry points.\n\tif (Buffer.isBuffer(file)) {\n\t\tconst size = fileSizeBytes ?? file.byteLength;\n\t\t// Wrap in a Blob so fetch/XHR handle it uniformly\n\t\t// Copy into a plain ArrayBuffer to avoid SharedArrayBuffer assignability issues\n\t\tconst blob = new Blob([new Uint8Array(file)], { type: deriveTypeHint(filename) });\n\t\treturn { body: blob, size };\n\t}\n\n\t// Blob / File\n\tconst size = fileSizeBytes ?? file.size;\n\treturn { body: file, size };\n}\n\nfunction deriveTypeHint(filename: string): string {\n\t// Minimal hint — the actual Content-Type for the presigned PUT always\n\t// comes from the server, not from this inference. This is only used\n\t// so the Blob is constructed with a reasonable type attribute.\n\tconst ext = filename.slice(filename.lastIndexOf(\".\") + 1).toLowerCase();\n\tconst map: Record<string, string> = {\n\t\tmp4: \"video/mp4\",\n\t\tmov: \"video/quicktime\",\n\t\twebm: \"video/webm\",\n\t\tavi: \"video/x-msvideo\",\n\t\tmkv: \"video/x-matroska\",\n\t\tm4v: \"video/x-m4v\",\n\t};\n\treturn map[ext] ?? \"application/octet-stream\";\n}\n","import { HyperserveTimeoutError, HyperserveUploadError } from \"./errors.js\";\n\n/**\n * PUT a file to a presigned S3 URL.\n * Used internally by uploadVideo (server) and exported as putVideoToStorage (browser).\n *\n * When onProgress is provided, uses XMLHttpRequest for upload progress events.\n * Falls back to fetch otherwise.\n */\nexport async function putToStorage(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob | ReadableStream,\n\tonProgress?: (percent: number) => void,\n): Promise<void> {\n\t// XHR is used for progress reporting but does not support ReadableStream bodies.\n\t// Fall back to fetch (no progress) when the body is a stream.\n\tif (\n\t\tonProgress !== undefined &&\n\t\ttypeof XMLHttpRequest !== \"undefined\" &&\n\t\t!(body instanceof ReadableStream)\n\t) {\n\t\treturn putWithXhr(uploadUrl, contentType, body, onProgress);\n\t}\n\treturn putWithFetch(uploadUrl, contentType, body);\n}\n\nfunction putWithFetch(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob | ReadableStream,\n): Promise<void> {\n\treturn fetch(uploadUrl, {\n\t\tmethod: \"PUT\",\n\t\theaders: { \"Content-Type\": contentType },\n\t\t// duplex is required for ReadableStream bodies in some runtimes (Node 18)\n\t\t...(body instanceof ReadableStream ? { duplex: \"half\" } : {}),\n\t\tbody: body as BodyInit,\n\t}).then((response) => {\n\t\tif (!response.ok) {\n\t\t\tthrow new HyperserveUploadError(\n\t\t\t\t`Storage PUT failed with status ${response.status}`,\n\t\t\t\tresponse.status,\n\t\t\t);\n\t\t}\n\t});\n}\n\nfunction putWithXhr(\n\tuploadUrl: string,\n\tcontentType: string,\n\tbody: Blob,\n\tonProgress: (percent: number) => void,\n): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tconst xhr = new XMLHttpRequest();\n\n\t\txhr.open(\"PUT\", uploadUrl);\n\t\txhr.setRequestHeader(\"Content-Type\", contentType);\n\n\t\txhr.upload.addEventListener(\"progress\", (event) => {\n\t\t\tif (event.lengthComputable) {\n\t\t\t\tonProgress(Math.round((event.loaded / event.total) * 100));\n\t\t\t}\n\t\t});\n\n\t\txhr.addEventListener(\"load\", () => {\n\t\t\tif (xhr.status >= 200 && xhr.status < 300) {\n\t\t\t\tonProgress(100);\n\t\t\t\tresolve();\n\t\t\t} else {\n\t\t\t\treject(\n\t\t\t\t\tnew HyperserveUploadError(`Storage PUT failed with status ${xhr.status}`, xhr.status),\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\n\t\txhr.addEventListener(\"timeout\", () => {\n\t\t\treject(new HyperserveTimeoutError(\"Storage PUT timed out\"));\n\t\t});\n\n\t\txhr.addEventListener(\"error\", () => {\n\t\t\treject(new HyperserveUploadError(\"Storage PUT failed due to a network error\"));\n\t\t});\n\n\t\txhr.send(body);\n\t});\n}\n","import { apiRequest } from \"./http.js\";\nimport { normalizeFile } from \"./normalize.js\";\nimport { putToStorage } from \"./storage.js\";\nimport type {\n\tCompleteUploadResult,\n\tCreateVideoOptions,\n\tCreateVideoResult,\n\tGetVideoOptions,\n\tHyperserveClientOptions,\n\tUploadVideoOptions,\n\tVideoResult,\n} from \"./types.js\";\n\nconst DEFAULT_BASE_URL = \"https://api.hyperserve.io/api\";\nconst DEFAULT_TIMEOUT_MS = 30_000;\n\nexport class HyperserveClient {\n\tprivate readonly apiKey: string;\n\tprivate readonly baseUrl: string;\n\tprivate readonly timeoutMs: number;\n\tprivate readonly retries: number;\n\n\tconstructor(options: HyperserveClientOptions) {\n\t\tthis.apiKey = options.apiKey;\n\t\tthis.baseUrl = options.baseUrl?.replace(/\\/$/, \"\") ?? DEFAULT_BASE_URL;\n\t\tthis.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\t\tthis.retries = options.retries ?? 0;\n\t}\n\n\t/**\n\t * Creates a video record and returns a presigned upload URL.\n\t * Pass uploadUrl and contentType to your frontend so it can PUT the file directly to storage.\n\t * Call completeUpload once the frontend confirms the PUT is done.\n\t */\n\tasync createVideo(options: CreateVideoOptions): Promise<CreateVideoResult> {\n\t\treturn apiRequest<CreateVideoResult>({\n\t\t\tmethod: \"POST\",\n\t\t\turl: `${this.baseUrl}/video`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t\tbody: {\n\t\t\t\tfilename: options.filename,\n\t\t\t\tfileSizeBytes: options.fileSizeBytes,\n\t\t\t\tresolutions: options.resolutions,\n\t\t\t\tisPublic: options.isPublic,\n\t\t\t\t...(options.thumbnailTimestampsSeconds !== undefined && {\n\t\t\t\t\tthumbnail_timestamps_seconds: options.thumbnailTimestampsSeconds,\n\t\t\t\t}),\n\t\t\t\t...(options.customMetadata !== undefined && {\n\t\t\t\t\tcustom_user_metadata: options.customMetadata,\n\t\t\t\t}),\n\t\t\t},\n\t\t});\n\t}\n\n\t/**\n\t * Notifies Hyperserve that the file has been uploaded to the presigned URL.\n\t * Hyperserve verifies the object and queues transcoding.\n\t * Call this after your frontend confirms the storage PUT is complete.\n\t */\n\tasync completeUpload(videoId: string): Promise<CompleteUploadResult> {\n\t\treturn apiRequest<CompleteUploadResult>({\n\t\t\tmethod: \"POST\",\n\t\t\turl: `${this.baseUrl}/video/${videoId}/complete-upload`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Retrieves the current state of a video, including per-resolution status and playback URLs.\n\t *\n\t * @param videoId - The video ID returned by createVideo or uploadVideo.\n\t * @param options.private - Return time-limited signed URLs instead of public URLs.\n\t * @param options.expirationSeconds - Signed URL TTL when private is true. Defaults to 3600.\n\t */\n\tasync getVideo(videoId: string, options?: GetVideoOptions): Promise<VideoResult> {\n\t\tconst isPrivate = options?.private === true;\n\t\tconst expiration = options?.expirationSeconds ?? 3600;\n\n\t\tconst url = isPrivate\n\t\t\t? `${this.baseUrl}/video/${videoId}/private/${expiration}`\n\t\t\t: `${this.baseUrl}/video/${videoId}/public`;\n\n\t\treturn apiRequest<VideoResult>({\n\t\t\tmethod: \"GET\",\n\t\t\turl,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes a video and all associated resolutions and thumbnails.\n\t */\n\tasync deleteVideo(videoId: string): Promise<void> {\n\t\treturn apiRequest<void>({\n\t\t\tmethod: \"DELETE\",\n\t\t\turl: `${this.baseUrl}/video/${videoId}`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Deletes a single resolution for a video.\n\t */\n\tasync deleteResolution(resolutionId: string): Promise<void> {\n\t\treturn apiRequest<void>({\n\t\t\tmethod: \"DELETE\",\n\t\t\turl: `${this.baseUrl}/video/resolution/${resolutionId}`,\n\t\t\tapiKey: this.apiKey,\n\t\t\ttimeoutMs: this.timeoutMs,\n\t\t\tretries: this.retries,\n\t\t});\n\t}\n\n\t/**\n\t * Convenience method for server-side / script use cases.\n\t * Wraps createVideo, the storage PUT, and completeUpload into a single call.\n\t *\n\t * Not suitable for the browser proxy pattern — use createVideo + putVideoToStorage\n\t * from '@hyperserve/hyperserve-js/browser' + completeUpload separately for that flow.\n\t */\n\tasync uploadVideo(options: UploadVideoOptions): Promise<CompleteUploadResult> {\n\t\tconst { file, filename, resolutions, isPublic, thumbnailTimestampsSeconds, customMetadata } =\n\t\t\toptions;\n\n\t\tconst normalized = normalizeFile(file, filename, options.fileSizeBytes);\n\n\t\tconst upload = await this.createVideo({\n\t\t\tfilename,\n\t\t\tfileSizeBytes: normalized.size,\n\t\t\tresolutions,\n\t\t\tisPublic,\n\t\t\t...(thumbnailTimestampsSeconds !== undefined && { thumbnailTimestampsSeconds }),\n\t\t\t...(customMetadata !== undefined && { customMetadata }),\n\t\t});\n\n\t\tawait putToStorage(upload.uploadUrl, upload.contentType, normalized.body);\n\n\t\treturn this.completeUpload(upload.id);\n\t}\n}\n","import type { VerifyWebhookSignatureOptions } from \"./types.js\";\n\nconst DEFAULT_TOLERANCE_MS = 300_000; // 5 minutes — matches server-side enforcement\n\n/**\n * Verifies the x-hyperserve-signature header on an incoming webhook request.\n *\n * The signature header has the format \"{timestampMs}.{hmac-sha256-hex}\", where the HMAC\n * is computed over \"{timestampMs}.{rawBody}\" using your webhook signing secret. This proves\n * both when the request was sent (replay protection) and that the body was not tampered with\n * (integrity). Any modification to the body or timestamp will invalidate the signature.\n *\n * Returns true if the signature is valid and the timestamp is within the tolerance window.\n * Returns false if the signature is invalid, the timestamp has expired, or the header is malformed.\n *\n * Uses the Web Crypto API for a constant-time HMAC comparison — safe on Node 18+, Bun, Deno,\n * Cloudflare Workers, Vercel Edge, and all other supported server environments.\n *\n * IMPORTANT: pass the raw request body string exactly as received. Do not parse and re-serialize\n * JSON — any whitespace difference will invalidate the signature.\n *\n * @example\n * import { verifyWebhookSignature } from '@hyperserve/hyperserve-js';\n *\n * // Express (use express.raw, not express.json, so you get the raw body)\n * app.post('/webhook', express.raw({ type: 'application/json' }), async (req, res) => {\n * const isValid = await verifyWebhookSignature({\n * signature: req.headers['x-hyperserve-signature'] ?? '',\n * secret: process.env.HYPERSERVE_WEBHOOK_SECRET,\n * body: req.body.toString(),\n * });\n * if (!isValid) return res.status(401).end();\n * });\n *\n * // Next.js App Router\n * const body = await request.text();\n * const isValid = await verifyWebhookSignature({\n * signature: request.headers.get('x-hyperserve-signature') ?? '',\n * secret: process.env.HYPERSERVE_WEBHOOK_SECRET!,\n * body,\n * });\n */\nexport async function verifyWebhookSignature(\n\toptions: VerifyWebhookSignatureOptions,\n): Promise<boolean> {\n\tconst { signature, secret, body, toleranceMs = DEFAULT_TOLERANCE_MS } = options;\n\n\tconst dotIndex = signature.indexOf(\".\");\n\tif (dotIndex === -1) return false;\n\n\tconst timestampStr = signature.slice(0, dotIndex);\n\tconst receivedHex = signature.slice(dotIndex + 1);\n\n\t// Validate timestamp is a non-negative integer\n\tconst timestamp = Number(timestampStr);\n\tif (!Number.isInteger(timestamp) || timestamp < 0) return false;\n\n\t// Reject if timestamp is outside the tolerance window.\n\t// Math.abs handles future timestamps (clock skew or forged headers) — without it,\n\t// a negative difference would never exceed toleranceMs, accepting the signature forever.\n\tif (Math.abs(Date.now() - timestamp) > toleranceMs) return false;\n\n\tconst receivedBytes = hexToBytes(receivedHex);\n\tif (receivedBytes === null) return false;\n\n\tconst encoder = new TextEncoder();\n\tconst key = await crypto.subtle.importKey(\n\t\t\"raw\",\n\t\tencoder.encode(secret),\n\t\t{ name: \"HMAC\", hash: \"SHA-256\" },\n\t\tfalse,\n\t\t[\"verify\"],\n\t);\n\n\t// The signed message is \"{timestampMs}.{rawBody}\" — covers both freshness and integrity.\n\t// crypto.subtle.verify performs a constant-time comparison.\n\treturn crypto.subtle.verify(\n\t\t\"HMAC\",\n\t\tkey,\n\t\treceivedBytes,\n\t\tencoder.encode(`${timestampStr}.${body}`),\n\t);\n}\n\nfunction hexToBytes(hex: string): Uint8Array<ArrayBuffer> | null {\n\tif (hex.length === 0 || hex.length % 2 !== 0) return null;\n\tconst bytes = new Uint8Array(new ArrayBuffer(hex.length / 2));\n\tfor (let i = 0; i < hex.length; i += 2) {\n\t\tconst value = parseInt(hex.slice(i, i + 2), 16);\n\t\tif (Number.isNaN(value)) return null;\n\t\tbytes[i / 2] = value;\n\t}\n\treturn bytes;\n}\n"]}