@mux/ai 0.1.2 → 0.1.3

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,409 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/primitives/index.ts
31
+ var primitives_exports = {};
32
+ __export(primitives_exports, {
33
+ DEFAULT_STORYBOARD_WIDTH: () => DEFAULT_STORYBOARD_WIDTH,
34
+ buildTranscriptUrl: () => buildTranscriptUrl,
35
+ chunkByTokens: () => chunkByTokens,
36
+ chunkText: () => chunkText,
37
+ chunkVTTCues: () => chunkVTTCues,
38
+ estimateTokenCount: () => estimateTokenCount,
39
+ extractTextFromVTT: () => extractTextFromVTT,
40
+ extractTimestampedTranscript: () => extractTimestampedTranscript,
41
+ fetchTranscriptForAsset: () => fetchTranscriptForAsset,
42
+ findCaptionTrack: () => findCaptionTrack,
43
+ getReadyTextTracks: () => getReadyTextTracks,
44
+ getStoryboardUrl: () => getStoryboardUrl,
45
+ getThumbnailUrls: () => getThumbnailUrls,
46
+ parseVTTCues: () => parseVTTCues,
47
+ vttTimestampToSeconds: () => vttTimestampToSeconds
48
+ });
49
+ module.exports = __toCommonJS(primitives_exports);
50
+
51
+ // src/lib/url-signing.ts
52
+ var import_mux_node = __toESM(require("@mux/mux-node"));
53
+
54
+ // src/env.ts
55
+ var import_node_path = __toESM(require("path"));
56
+ var import_dotenv = require("dotenv");
57
+ var import_dotenv_expand = require("dotenv-expand");
58
+ var import_zod = require("zod");
59
+ (0, import_dotenv_expand.expand)((0, import_dotenv.config)({
60
+ path: import_node_path.default.resolve(
61
+ process.cwd(),
62
+ process.env.NODE_ENV === "test" ? ".env.test" : ".env"
63
+ )
64
+ }));
65
+ function optionalString(description, message) {
66
+ return import_zod.z.preprocess(
67
+ (value) => typeof value === "string" && value.trim().length === 0 ? void 0 : value,
68
+ import_zod.z.string().trim().min(1, message).optional()
69
+ ).describe(description);
70
+ }
71
+ function requiredString(description, message) {
72
+ return import_zod.z.preprocess(
73
+ (value) => typeof value === "string" ? value.trim().length > 0 ? value.trim() : void 0 : value,
74
+ import_zod.z.string().trim().min(1, message)
75
+ ).describe(description);
76
+ }
77
+ var EnvSchema = import_zod.z.object({
78
+ NODE_ENV: import_zod.z.string().default("development").describe("Runtime environment."),
79
+ MUX_TOKEN_ID: requiredString("Mux access token ID.", "Required to access Mux APIs"),
80
+ MUX_TOKEN_SECRET: requiredString("Mux access token secret.", "Required to access Mux APIs"),
81
+ MUX_SIGNING_KEY: optionalString("Mux signing key ID for signed playback URLs.", "Used to sign playback URLs"),
82
+ MUX_PRIVATE_KEY: optionalString("Mux signing private key for signed playback URLs.", "Used to sign playback URLs"),
83
+ OPENAI_API_KEY: optionalString("OpenAI API key for OpenAI-backed workflows.", "OpenAI API key"),
84
+ ANTHROPIC_API_KEY: optionalString("Anthropic API key for Claude-backed workflows.", "Anthropic API key"),
85
+ GOOGLE_GENERATIVE_AI_API_KEY: optionalString("Google Generative AI API key for Gemini-backed workflows.", "Google Generative AI API key"),
86
+ ELEVENLABS_API_KEY: optionalString("ElevenLabs API key for audio translation.", "ElevenLabs API key"),
87
+ HIVE_API_KEY: optionalString("Hive Visual Moderation API key.", "Hive API key"),
88
+ S3_ENDPOINT: optionalString("S3-compatible endpoint for uploads.", "S3 endpoint"),
89
+ S3_REGION: optionalString("S3 region (defaults to 'auto' when omitted)."),
90
+ S3_BUCKET: optionalString("Bucket used for caption and audio uploads.", "S3 bucket"),
91
+ S3_ACCESS_KEY_ID: optionalString("Access key ID for S3-compatible uploads.", "S3 access key id"),
92
+ S3_SECRET_ACCESS_KEY: optionalString("Secret access key for S3-compatible uploads.", "S3 secret access key")
93
+ });
94
+ function parseEnv() {
95
+ const parsedEnv = EnvSchema.safeParse(process.env);
96
+ if (!parsedEnv.success) {
97
+ console.error("\u274C Invalid env:");
98
+ console.error(JSON.stringify(parsedEnv.error.flatten().fieldErrors, null, 2));
99
+ process.exit(1);
100
+ }
101
+ return parsedEnv.data;
102
+ }
103
+ var env = parseEnv();
104
+ var env_default = env;
105
+
106
+ // src/lib/url-signing.ts
107
+ function createSigningClient(context) {
108
+ return new import_mux_node.default({
109
+ // These are not needed for signing, but the SDK requires them
110
+ // Using empty strings as we only need the jwt functionality
111
+ tokenId: env_default.MUX_TOKEN_ID || "",
112
+ tokenSecret: env_default.MUX_TOKEN_SECRET || "",
113
+ jwtSigningKey: context.keyId,
114
+ jwtPrivateKey: context.keySecret
115
+ });
116
+ }
117
+ async function signPlaybackId(playbackId, context, type = "video", params) {
118
+ const client = createSigningClient(context);
119
+ const stringParams = params ? Object.fromEntries(
120
+ Object.entries(params).map(([key, value]) => [key, String(value)])
121
+ ) : void 0;
122
+ return client.jwt.signPlaybackId(playbackId, {
123
+ type,
124
+ expiration: context.expiration || "1h",
125
+ params: stringParams
126
+ });
127
+ }
128
+ async function signUrl(url, playbackId, context, type = "video", params) {
129
+ const token = await signPlaybackId(playbackId, context, type, params);
130
+ const separator = url.includes("?") ? "&" : "?";
131
+ return `${url}${separator}token=${token}`;
132
+ }
133
+
134
+ // src/primitives/storyboards.ts
135
+ var DEFAULT_STORYBOARD_WIDTH = 640;
136
+ async function getStoryboardUrl(playbackId, width = DEFAULT_STORYBOARD_WIDTH, signingContext) {
137
+ const baseUrl = `https://image.mux.com/${playbackId}/storyboard.png`;
138
+ if (signingContext) {
139
+ return signUrl(baseUrl, playbackId, signingContext, "storyboard", { width });
140
+ }
141
+ return `${baseUrl}?width=${width}`;
142
+ }
143
+
144
+ // src/primitives/text-chunking.ts
145
+ function estimateTokenCount(text) {
146
+ const words = text.trim().split(/\s+/).length;
147
+ return Math.ceil(words / 0.75);
148
+ }
149
+ function chunkByTokens(text, maxTokens, overlapTokens = 0) {
150
+ if (!text.trim()) {
151
+ return [];
152
+ }
153
+ const chunks = [];
154
+ const words = text.trim().split(/\s+/);
155
+ const wordsPerChunk = Math.floor(maxTokens * 0.75);
156
+ const overlapWords = Math.floor(overlapTokens * 0.75);
157
+ let chunkIndex = 0;
158
+ let currentPosition = 0;
159
+ while (currentPosition < words.length) {
160
+ const chunkWords = words.slice(
161
+ currentPosition,
162
+ currentPosition + wordsPerChunk
163
+ );
164
+ const chunkText2 = chunkWords.join(" ");
165
+ const tokenCount = estimateTokenCount(chunkText2);
166
+ chunks.push({
167
+ id: `chunk-${chunkIndex}`,
168
+ text: chunkText2,
169
+ tokenCount
170
+ });
171
+ currentPosition += wordsPerChunk - overlapWords;
172
+ chunkIndex++;
173
+ if (currentPosition <= (chunkIndex - 1) * (wordsPerChunk - overlapWords)) {
174
+ break;
175
+ }
176
+ }
177
+ return chunks;
178
+ }
179
+ function createChunkFromCues(cues, index) {
180
+ const text = cues.map((c) => c.text).join(" ");
181
+ return {
182
+ id: `chunk-${index}`,
183
+ text,
184
+ tokenCount: estimateTokenCount(text),
185
+ startTime: cues[0].startTime,
186
+ endTime: cues[cues.length - 1].endTime
187
+ };
188
+ }
189
+ function chunkVTTCues(cues, maxTokens, overlapCues = 2) {
190
+ if (cues.length === 0)
191
+ return [];
192
+ const chunks = [];
193
+ let currentCues = [];
194
+ let currentTokens = 0;
195
+ let chunkIndex = 0;
196
+ for (let i = 0; i < cues.length; i++) {
197
+ const cue = cues[i];
198
+ const cueTokens = estimateTokenCount(cue.text);
199
+ if (currentTokens + cueTokens > maxTokens && currentCues.length > 0) {
200
+ chunks.push(createChunkFromCues(currentCues, chunkIndex));
201
+ chunkIndex++;
202
+ const overlapStart = Math.max(0, currentCues.length - overlapCues);
203
+ currentCues = currentCues.slice(overlapStart);
204
+ currentTokens = currentCues.reduce(
205
+ (sum, c) => sum + estimateTokenCount(c.text),
206
+ 0
207
+ );
208
+ }
209
+ currentCues.push(cue);
210
+ currentTokens += cueTokens;
211
+ }
212
+ if (currentCues.length > 0) {
213
+ chunks.push(createChunkFromCues(currentCues, chunkIndex));
214
+ }
215
+ return chunks;
216
+ }
217
+ function chunkText(text, strategy) {
218
+ switch (strategy.type) {
219
+ case "token": {
220
+ return chunkByTokens(text, strategy.maxTokens, strategy.overlap ?? 0);
221
+ }
222
+ default: {
223
+ const exhaustiveCheck = strategy;
224
+ throw new Error(`Unsupported chunking strategy: ${exhaustiveCheck}`);
225
+ }
226
+ }
227
+ }
228
+
229
+ // src/primitives/thumbnails.ts
230
+ async function getThumbnailUrls(playbackId, duration, options = {}) {
231
+ const { interval = 10, width = 640, signingContext } = options;
232
+ const timestamps = [];
233
+ if (duration <= 50) {
234
+ const spacing = duration / 6;
235
+ for (let i = 1; i <= 5; i++) {
236
+ timestamps.push(Math.round(i * spacing));
237
+ }
238
+ } else {
239
+ for (let time = 0; time < duration; time += interval) {
240
+ timestamps.push(time);
241
+ }
242
+ }
243
+ const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;
244
+ const urlPromises = timestamps.map(async (time) => {
245
+ if (signingContext) {
246
+ return signUrl(baseUrl, playbackId, signingContext, "thumbnail", { time, width });
247
+ }
248
+ return `${baseUrl}?time=${time}&width=${width}`;
249
+ });
250
+ return Promise.all(urlPromises);
251
+ }
252
+
253
+ // src/primitives/transcripts.ts
254
+ function getReadyTextTracks(asset) {
255
+ return (asset.tracks || []).filter(
256
+ (track) => track.type === "text" && track.status === "ready"
257
+ );
258
+ }
259
+ function findCaptionTrack(asset, languageCode) {
260
+ const tracks = getReadyTextTracks(asset);
261
+ if (!tracks.length)
262
+ return void 0;
263
+ if (!languageCode) {
264
+ return tracks[0];
265
+ }
266
+ return tracks.find(
267
+ (track) => track.text_type === "subtitles" && track.language_code === languageCode
268
+ );
269
+ }
270
+ function extractTextFromVTT(vttContent) {
271
+ if (!vttContent.trim()) {
272
+ return "";
273
+ }
274
+ const lines = vttContent.split("\n");
275
+ const textLines = [];
276
+ for (let i = 0; i < lines.length; i++) {
277
+ const line = lines[i].trim();
278
+ if (!line)
279
+ continue;
280
+ if (line === "WEBVTT")
281
+ continue;
282
+ if (line.startsWith("NOTE "))
283
+ continue;
284
+ if (line.includes("-->"))
285
+ continue;
286
+ if (/^[\w-]+$/.test(line) && !line.includes(" "))
287
+ continue;
288
+ if (line.startsWith("STYLE") || line.startsWith("REGION"))
289
+ continue;
290
+ const cleanLine = line.replace(/<[^>]*>/g, "").trim();
291
+ if (cleanLine) {
292
+ textLines.push(cleanLine);
293
+ }
294
+ }
295
+ return textLines.join(" ").replace(/\s+/g, " ").trim();
296
+ }
297
+ function vttTimestampToSeconds(timestamp) {
298
+ const parts = timestamp.split(":");
299
+ if (parts.length !== 3)
300
+ return 0;
301
+ const hours = Number.parseInt(parts[0], 10) || 0;
302
+ const minutes = Number.parseInt(parts[1], 10) || 0;
303
+ const seconds = Number.parseFloat(parts[2]) || 0;
304
+ return hours * 3600 + minutes * 60 + seconds;
305
+ }
306
+ function extractTimestampedTranscript(vttContent) {
307
+ if (!vttContent.trim()) {
308
+ return "";
309
+ }
310
+ const lines = vttContent.split("\n");
311
+ const segments = [];
312
+ for (let i = 0; i < lines.length; i++) {
313
+ const line = lines[i].trim();
314
+ if (line.includes("-->")) {
315
+ const startTime = line.split(" --> ")[0].trim();
316
+ const timeInSeconds = vttTimestampToSeconds(startTime);
317
+ let j = i + 1;
318
+ while (j < lines.length && !lines[j].trim()) {
319
+ j++;
320
+ }
321
+ if (j < lines.length) {
322
+ const text = lines[j].trim().replace(/<[^>]*>/g, "");
323
+ if (text) {
324
+ segments.push({ time: timeInSeconds, text });
325
+ }
326
+ }
327
+ }
328
+ }
329
+ return segments.map((segment) => `[${Math.floor(segment.time)}s] ${segment.text}`).join("\n");
330
+ }
331
+ function parseVTTCues(vttContent) {
332
+ if (!vttContent.trim())
333
+ return [];
334
+ const lines = vttContent.split("\n");
335
+ const cues = [];
336
+ for (let i = 0; i < lines.length; i++) {
337
+ const line = lines[i].trim();
338
+ if (line.includes("-->")) {
339
+ const [startStr, endStr] = line.split(" --> ").map((s) => s.trim());
340
+ const startTime = vttTimestampToSeconds(startStr);
341
+ const endTime = vttTimestampToSeconds(endStr.split(" ")[0]);
342
+ const textLines = [];
343
+ let j = i + 1;
344
+ while (j < lines.length && lines[j].trim() && !lines[j].includes("-->")) {
345
+ const cleanLine = lines[j].trim().replace(/<[^>]*>/g, "");
346
+ if (cleanLine)
347
+ textLines.push(cleanLine);
348
+ j++;
349
+ }
350
+ if (textLines.length > 0) {
351
+ cues.push({
352
+ startTime,
353
+ endTime,
354
+ text: textLines.join(" ")
355
+ });
356
+ }
357
+ }
358
+ }
359
+ return cues;
360
+ }
361
+ async function buildTranscriptUrl(playbackId, trackId, signingContext) {
362
+ const baseUrl = `https://stream.mux.com/${playbackId}/text/${trackId}.vtt`;
363
+ if (signingContext) {
364
+ return signUrl(baseUrl, playbackId, signingContext, "video");
365
+ }
366
+ return baseUrl;
367
+ }
368
+ async function fetchTranscriptForAsset(asset, playbackId, options = {}) {
369
+ const { languageCode, cleanTranscript = true, signingContext } = options;
370
+ const track = findCaptionTrack(asset, languageCode);
371
+ if (!track) {
372
+ return { transcriptText: "" };
373
+ }
374
+ if (!track.id) {
375
+ return { transcriptText: "", track };
376
+ }
377
+ const transcriptUrl = await buildTranscriptUrl(playbackId, track.id, signingContext);
378
+ try {
379
+ const response = await fetch(transcriptUrl);
380
+ if (!response.ok) {
381
+ return { transcriptText: "", transcriptUrl, track };
382
+ }
383
+ const rawVtt = await response.text();
384
+ const transcriptText = cleanTranscript ? extractTextFromVTT(rawVtt) : rawVtt;
385
+ return { transcriptText, transcriptUrl, track };
386
+ } catch (error) {
387
+ console.warn("Failed to fetch transcript:", error);
388
+ return { transcriptText: "", transcriptUrl, track };
389
+ }
390
+ }
391
+ // Annotate the CommonJS export names for ESM import in node:
392
+ 0 && (module.exports = {
393
+ DEFAULT_STORYBOARD_WIDTH,
394
+ buildTranscriptUrl,
395
+ chunkByTokens,
396
+ chunkText,
397
+ chunkVTTCues,
398
+ estimateTokenCount,
399
+ extractTextFromVTT,
400
+ extractTimestampedTranscript,
401
+ fetchTranscriptForAsset,
402
+ findCaptionTrack,
403
+ getReadyTextTracks,
404
+ getStoryboardUrl,
405
+ getThumbnailUrls,
406
+ parseVTTCues,
407
+ vttTimestampToSeconds
408
+ });
409
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/primitives/index.ts","../../src/lib/url-signing.ts","../../src/env.ts","../../src/primitives/storyboards.ts","../../src/primitives/text-chunking.ts","../../src/primitives/thumbnails.ts","../../src/primitives/transcripts.ts"],"sourcesContent":["// primitives public surface intentionally minimal; provider plumbing lives in lib/providers\nexport * from \"./storyboards\";\nexport * from \"./text-chunking\";\nexport * from \"./thumbnails\";\nexport * from \"./transcripts\";\n","import Mux from \"@mux/mux-node\";\n\nimport env from \"../env\";\nimport type { MuxAIConfig } from \"../types\";\n\n/**\n * Context required to sign URLs for signed playback IDs.\n */\nexport interface SigningContext {\n /** The signing key ID from Mux dashboard. */\n keyId: string;\n /** The base64-encoded private key from Mux dashboard. */\n keySecret: string;\n /** Token expiration time (e.g. '1h', '1d'). Defaults to '1h'. */\n expiration?: string;\n}\n\n/**\n * Token type determines which Mux service the token is valid for.\n */\nexport type TokenType = \"video\" | \"thumbnail\" | \"storyboard\" | \"gif\";\n\n/**\n * Resolves signing context from config or environment variables.\n * Returns undefined if signing keys are not configured.\n */\nexport function resolveSigningContext(config: MuxAIConfig): SigningContext | undefined {\n const keyId = config.muxSigningKey ?? env.MUX_SIGNING_KEY;\n const keySecret = config.muxPrivateKey ?? env.MUX_PRIVATE_KEY;\n\n if (!keyId || !keySecret) {\n return undefined;\n }\n\n return { keyId, keySecret };\n}\n\n/**\n * Creates a Mux client configured for JWT signing.\n * This client is used internally for signing operations.\n */\nfunction createSigningClient(context: SigningContext): Mux {\n return new Mux({\n // These are not needed for signing, but the SDK requires them\n // Using empty strings as we only need the jwt functionality\n tokenId: env.MUX_TOKEN_ID || \"\",\n tokenSecret: env.MUX_TOKEN_SECRET || \"\",\n jwtSigningKey: context.keyId,\n jwtPrivateKey: context.keySecret,\n });\n}\n\n/**\n * Generates a signed token for a playback ID using the Mux SDK.\n *\n * @param playbackId - The Mux playback ID to sign\n * @param context - Signing context with key credentials\n * @param type - Token type (video, thumbnail, storyboard, gif)\n * @param params - Additional parameters for thumbnail/storyboard tokens (values will be stringified)\n * @returns Signed JWT token\n */\nexport async function signPlaybackId(\n playbackId: string,\n context: SigningContext,\n type: TokenType = \"video\",\n params?: Record<string, string | number>,\n): Promise<string> {\n const client = createSigningClient(context);\n\n // Convert params to Record<string, string> as required by the SDK\n const stringParams = params ?\n Object.fromEntries(\n Object.entries(params).map(([key, value]) => [key, String(value)]),\n ) :\n undefined;\n\n return client.jwt.signPlaybackId(playbackId, {\n type,\n expiration: context.expiration || \"1h\",\n params: stringParams,\n });\n}\n\n/**\n * Appends a signed token to a Mux URL.\n *\n * @param url - The base Mux URL (e.g. https://image.mux.com/{playbackId}/thumbnail.png)\n * @param playbackId - The Mux playback ID\n * @param context - Signing context with key credentials\n * @param type - Token type for the URL\n * @param params - Additional parameters for the token\n * @returns URL with token query parameter appended\n */\nexport async function signUrl(\n url: string,\n playbackId: string,\n context: SigningContext,\n type: TokenType = \"video\",\n params?: Record<string, string | number>,\n): Promise<string> {\n const token = await signPlaybackId(playbackId, context, type, params);\n const separator = url.includes(\"?\") ? \"&\" : \"?\";\n return `${url}${separator}token=${token}`;\n}\n","/* eslint-disable node/no-process-env */\nimport path from \"node:path\";\n\nimport { config } from \"dotenv\";\nimport { expand } from \"dotenv-expand\";\nimport { z } from \"zod\";\n\nexpand(config({\n path: path.resolve(\n process.cwd(),\n process.env.NODE_ENV === \"test\" ? \".env.test\" : \".env\",\n ),\n}));\n\nfunction optionalString(description: string, message?: string) {\n return z.preprocess(\n value => typeof value === \"string\" && value.trim().length === 0 ? undefined : value,\n z.string().trim().min(1, message).optional(),\n ).describe(description);\n}\n\nfunction requiredString(description: string, message?: string) {\n return z.preprocess(\n value => typeof value === \"string\" ? value.trim().length > 0 ? value.trim() : undefined : value,\n z.string().trim().min(1, message),\n ).describe(description);\n}\n\nconst EnvSchema = z.object({\n NODE_ENV: z.string().default(\"development\").describe(\"Runtime environment.\"),\n\n MUX_TOKEN_ID: requiredString(\"Mux access token ID.\", \"Required to access Mux APIs\"),\n MUX_TOKEN_SECRET: requiredString(\"Mux access token secret.\", \"Required to access Mux APIs\"),\n\n MUX_SIGNING_KEY: optionalString(\"Mux signing key ID for signed playback URLs.\", \"Used to sign playback URLs\"),\n MUX_PRIVATE_KEY: optionalString(\"Mux signing private key for signed playback URLs.\", \"Used to sign playback URLs\"),\n\n OPENAI_API_KEY: optionalString(\"OpenAI API key for OpenAI-backed workflows.\", \"OpenAI API key\"),\n ANTHROPIC_API_KEY: optionalString(\"Anthropic API key for Claude-backed workflows.\", \"Anthropic API key\"),\n GOOGLE_GENERATIVE_AI_API_KEY: optionalString(\"Google Generative AI API key for Gemini-backed workflows.\", \"Google Generative AI API key\"),\n\n ELEVENLABS_API_KEY: optionalString(\"ElevenLabs API key for audio translation.\", \"ElevenLabs API key\"),\n HIVE_API_KEY: optionalString(\"Hive Visual Moderation API key.\", \"Hive API key\"),\n\n S3_ENDPOINT: optionalString(\"S3-compatible endpoint for uploads.\", \"S3 endpoint\"),\n S3_REGION: optionalString(\"S3 region (defaults to 'auto' when omitted).\"),\n S3_BUCKET: optionalString(\"Bucket used for caption and audio uploads.\", \"S3 bucket\"),\n S3_ACCESS_KEY_ID: optionalString(\"Access key ID for S3-compatible uploads.\", \"S3 access key id\"),\n S3_SECRET_ACCESS_KEY: optionalString(\"Secret access key for S3-compatible uploads.\", \"S3 secret access key\"),\n});\n\nexport type Env = z.infer<typeof EnvSchema>;\n\nfunction parseEnv(): Env {\n const parsedEnv = EnvSchema.safeParse(process.env);\n\n if (!parsedEnv.success) {\n console.error(\"❌ Invalid env:\");\n console.error(JSON.stringify(parsedEnv.error.flatten().fieldErrors, null, 2));\n process.exit(1);\n }\n\n return parsedEnv.data;\n}\n\nconst env: Env = parseEnv();\n\nexport function reloadEnv(): Env {\n const parsed = parseEnv();\n Object.assign(env, parsed);\n return env;\n}\n\nexport { env };\nexport default env;\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\n\nexport const DEFAULT_STORYBOARD_WIDTH = 640;\n\n/**\n * Generates a storyboard URL for the given playback ID.\n * If a signing context is provided, the URL will be signed with a token.\n *\n * @param playbackId - The Mux playback ID\n * @param width - Width of the storyboard in pixels (default: 640)\n * @param signingContext - Optional signing context for signed playback IDs\n * @returns Storyboard URL (signed if context provided)\n */\nexport async function getStoryboardUrl(\n playbackId: string,\n width: number = DEFAULT_STORYBOARD_WIDTH,\n signingContext?: SigningContext,\n): Promise<string> {\n const baseUrl = `https://image.mux.com/${playbackId}/storyboard.png`;\n\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"storyboard\", { width });\n }\n\n return `${baseUrl}?width=${width}`;\n}\n","import type { ChunkingStrategy, TextChunk } from \"../types\";\n\nimport type { VTTCue } from \"./transcripts\";\n\n/**\n * Simple token counter that approximates tokens by word count.\n * For production use with OpenAI, consider using a proper tokenizer like tiktoken.\n * This approximation is generally close enough for chunking purposes (1 token ≈ 0.75 words).\n */\nexport function estimateTokenCount(text: string): number {\n const words = text.trim().split(/\\s+/).length;\n return Math.ceil(words / 0.75);\n}\n\n/**\n * Chunks text into overlapping segments based on token count.\n *\n * @param text - The text to chunk\n * @param maxTokens - Maximum tokens per chunk\n * @param overlapTokens - Number of tokens to overlap between chunks\n * @returns Array of text chunks with metadata\n */\nexport function chunkByTokens(\n text: string,\n maxTokens: number,\n overlapTokens: number = 0,\n): TextChunk[] {\n if (!text.trim()) {\n return [];\n }\n\n const chunks: TextChunk[] = [];\n const words = text.trim().split(/\\s+/);\n\n // Convert tokens to approximate word count\n const wordsPerChunk = Math.floor(maxTokens * 0.75);\n const overlapWords = Math.floor(overlapTokens * 0.75);\n\n let chunkIndex = 0;\n let currentPosition = 0;\n\n while (currentPosition < words.length) {\n const chunkWords = words.slice(\n currentPosition,\n currentPosition + wordsPerChunk,\n );\n const chunkText = chunkWords.join(\" \");\n const tokenCount = estimateTokenCount(chunkText);\n\n chunks.push({\n id: `chunk-${chunkIndex}`,\n text: chunkText,\n tokenCount,\n });\n\n // Move forward by chunk size minus overlap\n currentPosition += wordsPerChunk - overlapWords;\n chunkIndex++;\n\n // Prevent infinite loop if overlap is too large\n if (currentPosition <= (chunkIndex - 1) * (wordsPerChunk - overlapWords)) {\n break;\n }\n }\n\n return chunks;\n}\n\n/**\n * Creates a TextChunk from a group of VTT cues.\n */\nfunction createChunkFromCues(cues: VTTCue[], index: number): TextChunk {\n const text = cues.map(c => c.text).join(\" \");\n return {\n id: `chunk-${index}`,\n text,\n tokenCount: estimateTokenCount(text),\n startTime: cues[0].startTime,\n endTime: cues[cues.length - 1].endTime,\n };\n}\n\n/**\n * Chunks VTT cues into groups that respect natural cue boundaries.\n * Splits at cue boundaries rather than mid-sentence, preserving accurate timestamps.\n *\n * @param cues - Array of VTT cues to chunk\n * @param maxTokens - Maximum tokens per chunk\n * @param overlapCues - Number of cues to overlap between chunks (default: 2)\n * @returns Array of text chunks with accurate start/end times\n */\nexport function chunkVTTCues(\n cues: VTTCue[],\n maxTokens: number,\n overlapCues: number = 2,\n): TextChunk[] {\n if (cues.length === 0)\n return [];\n\n const chunks: TextChunk[] = [];\n let currentCues: VTTCue[] = [];\n let currentTokens = 0;\n let chunkIndex = 0;\n\n for (let i = 0; i < cues.length; i++) {\n const cue = cues[i];\n const cueTokens = estimateTokenCount(cue.text);\n\n // If adding this cue would exceed limit, finalize current chunk\n if (currentTokens + cueTokens > maxTokens && currentCues.length > 0) {\n chunks.push(createChunkFromCues(currentCues, chunkIndex));\n chunkIndex++;\n\n // Start new chunk with overlap from end of previous\n const overlapStart = Math.max(0, currentCues.length - overlapCues);\n currentCues = currentCues.slice(overlapStart);\n currentTokens = currentCues.reduce(\n (sum, c) => sum + estimateTokenCount(c.text),\n 0,\n );\n }\n\n currentCues.push(cue);\n currentTokens += cueTokens;\n }\n\n // Don't forget the last chunk\n if (currentCues.length > 0) {\n chunks.push(createChunkFromCues(currentCues, chunkIndex));\n }\n\n return chunks;\n}\n\n/**\n * Chunks text according to the specified strategy.\n *\n * @param text - The text to chunk\n * @param strategy - The chunking strategy to use\n * @returns Array of text chunks\n */\nexport function chunkText(text: string, strategy: ChunkingStrategy): TextChunk[] {\n switch (strategy.type) {\n case \"token\": {\n return chunkByTokens(text, strategy.maxTokens, strategy.overlap ?? 0);\n }\n default: {\n const exhaustiveCheck: never = strategy as never;\n throw new Error(`Unsupported chunking strategy: ${exhaustiveCheck}`);\n }\n }\n}\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\n\nexport interface ThumbnailOptions {\n /** Interval between thumbnails in seconds (default: 10) */\n interval?: number;\n /** Width of the thumbnail in pixels (default: 640) */\n width?: number;\n /** Optional signing context for signed playback IDs */\n signingContext?: SigningContext;\n}\n\n/**\n * Generates thumbnail URLs at regular intervals based on video duration.\n * If a signing context is provided, the URLs will be signed with tokens.\n *\n * @param playbackId - The Mux playback ID\n * @param duration - Video duration in seconds\n * @param options - Thumbnail generation options\n * @returns Array of thumbnail URLs (signed if context provided)\n */\nexport async function getThumbnailUrls(\n playbackId: string,\n duration: number,\n options: ThumbnailOptions = {},\n): Promise<string[]> {\n const { interval = 10, width = 640, signingContext } = options;\n const timestamps: number[] = [];\n\n if (duration <= 50) {\n const spacing = duration / 6;\n for (let i = 1; i <= 5; i++) {\n timestamps.push(Math.round(i * spacing));\n }\n } else {\n for (let time = 0; time < duration; time += interval) {\n timestamps.push(time);\n }\n }\n\n const baseUrl = `https://image.mux.com/${playbackId}/thumbnail.png`;\n\n const urlPromises = timestamps.map(async (time) => {\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"thumbnail\", { time, width });\n }\n\n return `${baseUrl}?time=${time}&width=${width}`;\n });\n\n return Promise.all(urlPromises);\n}\n","import type { SigningContext } from \"../lib/url-signing\";\nimport { signUrl } from \"../lib/url-signing\";\nimport type { AssetTextTrack, MuxAsset } from \"../types\";\n\n/** A single cue from a VTT file with timing info. */\nexport interface VTTCue {\n startTime: number;\n endTime: number;\n text: string;\n}\n\nexport interface TranscriptFetchOptions {\n languageCode?: string;\n cleanTranscript?: boolean;\n /** Optional signing context for signed playback IDs */\n signingContext?: SigningContext;\n}\n\nexport interface TranscriptResult {\n transcriptText: string;\n transcriptUrl?: string;\n track?: AssetTextTrack;\n}\n\nexport function getReadyTextTracks(asset: MuxAsset): AssetTextTrack[] {\n return (asset.tracks || []).filter(\n track => track.type === \"text\" && track.status === \"ready\",\n );\n}\n\nexport function findCaptionTrack(asset: MuxAsset, languageCode?: string): AssetTextTrack | undefined {\n const tracks = getReadyTextTracks(asset);\n if (!tracks.length)\n return undefined;\n\n if (!languageCode) {\n return tracks[0];\n }\n\n return tracks.find(\n track =>\n track.text_type === \"subtitles\" &&\n track.language_code === languageCode,\n );\n}\n\nexport function extractTextFromVTT(vttContent: string): string {\n if (!vttContent.trim()) {\n return \"\";\n }\n\n const lines = vttContent.split(\"\\n\");\n const textLines: string[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (!line)\n continue;\n if (line === \"WEBVTT\")\n continue;\n if (line.startsWith(\"NOTE \"))\n continue;\n if (line.includes(\"-->\"))\n continue;\n if (/^[\\w-]+$/.test(line) && !line.includes(\" \"))\n continue;\n if (line.startsWith(\"STYLE\") || line.startsWith(\"REGION\"))\n continue;\n\n const cleanLine = line.replace(/<[^>]*>/g, \"\").trim();\n\n if (cleanLine) {\n textLines.push(cleanLine);\n }\n }\n\n return textLines.join(\" \").replace(/\\s+/g, \" \").trim();\n}\n\nexport function vttTimestampToSeconds(timestamp: string): number {\n const parts = timestamp.split(\":\");\n if (parts.length !== 3)\n return 0;\n\n const hours = Number.parseInt(parts[0], 10) || 0;\n const minutes = Number.parseInt(parts[1], 10) || 0;\n const seconds = Number.parseFloat(parts[2]) || 0;\n\n return hours * 3600 + minutes * 60 + seconds;\n}\n\nexport function extractTimestampedTranscript(vttContent: string): string {\n if (!vttContent.trim()) {\n return \"\";\n }\n\n const lines = vttContent.split(\"\\n\");\n const segments: Array<{ time: number; text: string }> = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (line.includes(\"-->\")) {\n const startTime = line.split(\" --> \")[0].trim();\n const timeInSeconds = vttTimestampToSeconds(startTime);\n\n let j = i + 1;\n while (j < lines.length && !lines[j].trim()) {\n j++;\n }\n\n if (j < lines.length) {\n const text = lines[j].trim().replace(/<[^>]*>/g, \"\");\n if (text) {\n segments.push({ time: timeInSeconds, text });\n }\n }\n }\n }\n\n return segments\n .map(segment => `[${Math.floor(segment.time)}s] ${segment.text}`)\n .join(\"\\n\");\n}\n\n/**\n * Parses VTT content into structured cues with timing.\n *\n * @param vttContent - Raw VTT file content\n * @returns Array of VTT cues with start/end times and text\n */\nexport function parseVTTCues(vttContent: string): VTTCue[] {\n if (!vttContent.trim())\n return [];\n\n const lines = vttContent.split(\"\\n\");\n const cues: VTTCue[] = [];\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i].trim();\n\n if (line.includes(\"-->\")) {\n const [startStr, endStr] = line.split(\" --> \").map(s => s.trim());\n const startTime = vttTimestampToSeconds(startStr);\n const endTime = vttTimestampToSeconds(endStr.split(\" \")[0]); // Handle cue settings\n\n // Collect text lines until empty line or next timestamp\n const textLines: string[] = [];\n let j = i + 1;\n while (j < lines.length && lines[j].trim() && !lines[j].includes(\"-->\")) {\n const cleanLine = lines[j].trim().replace(/<[^>]*>/g, \"\");\n if (cleanLine)\n textLines.push(cleanLine);\n j++;\n }\n\n if (textLines.length > 0) {\n cues.push({\n startTime,\n endTime,\n text: textLines.join(\" \"),\n });\n }\n }\n }\n\n return cues;\n}\n\n/**\n * Builds a transcript URL for the given playback ID and track ID.\n * If a signing context is provided, the URL will be signed with a token.\n *\n * @param playbackId - The Mux playback ID\n * @param trackId - The text track ID\n * @param signingContext - Optional signing context for signed playback IDs\n * @returns Transcript URL (signed if context provided)\n */\nexport async function buildTranscriptUrl(\n playbackId: string,\n trackId: string,\n signingContext?: SigningContext,\n): Promise<string> {\n const baseUrl = `https://stream.mux.com/${playbackId}/text/${trackId}.vtt`;\n\n if (signingContext) {\n return signUrl(baseUrl, playbackId, signingContext, \"video\");\n }\n\n return baseUrl;\n}\n\nexport async function fetchTranscriptForAsset(\n asset: MuxAsset,\n playbackId: string,\n options: TranscriptFetchOptions = {},\n): Promise<TranscriptResult> {\n const { languageCode, cleanTranscript = true, signingContext } = options;\n const track = findCaptionTrack(asset, languageCode);\n\n if (!track) {\n return { transcriptText: \"\" };\n }\n\n if (!track.id) {\n return { transcriptText: \"\", track };\n }\n\n const transcriptUrl = await buildTranscriptUrl(playbackId, track.id, signingContext);\n\n try {\n const response = await fetch(transcriptUrl);\n if (!response.ok) {\n return { transcriptText: \"\", transcriptUrl, track };\n }\n\n const rawVtt = await response.text();\n const transcriptText = cleanTranscript ? extractTextFromVTT(rawVtt) : rawVtt;\n\n return { transcriptText, transcriptUrl, track };\n } catch (error) {\n console.warn(\"Failed to fetch transcript:\", error);\n return { transcriptText: \"\", transcriptUrl, track };\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,sBAAgB;;;ACChB,uBAAiB;AAEjB,oBAAuB;AACvB,2BAAuB;AACvB,iBAAkB;AAAA,IAElB,iCAAO,sBAAO;AAAA,EACZ,MAAM,iBAAAA,QAAK;AAAA,IACT,QAAQ,IAAI;AAAA,IACZ,QAAQ,IAAI,aAAa,SAAS,cAAc;AAAA,EAClD;AACF,CAAC,CAAC;AAEF,SAAS,eAAe,aAAqB,SAAkB;AAC7D,SAAO,aAAE;AAAA,IACP,WAAS,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,WAAW,IAAI,SAAY;AAAA,IAC9E,aAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO,EAAE,SAAS;AAAA,EAC7C,EAAE,SAAS,WAAW;AACxB;AAEA,SAAS,eAAe,aAAqB,SAAkB;AAC7D,SAAO,aAAE;AAAA,IACP,WAAS,OAAO,UAAU,WAAW,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI,SAAY;AAAA,IAC1F,aAAE,OAAO,EAAE,KAAK,EAAE,IAAI,GAAG,OAAO;AAAA,EAClC,EAAE,SAAS,WAAW;AACxB;AAEA,IAAM,YAAY,aAAE,OAAO;AAAA,EACzB,UAAU,aAAE,OAAO,EAAE,QAAQ,aAAa,EAAE,SAAS,sBAAsB;AAAA,EAE3E,cAAc,eAAe,wBAAwB,6BAA6B;AAAA,EAClF,kBAAkB,eAAe,4BAA4B,6BAA6B;AAAA,EAE1F,iBAAiB,eAAe,gDAAgD,4BAA4B;AAAA,EAC5G,iBAAiB,eAAe,qDAAqD,4BAA4B;AAAA,EAEjH,gBAAgB,eAAe,+CAA+C,gBAAgB;AAAA,EAC9F,mBAAmB,eAAe,kDAAkD,mBAAmB;AAAA,EACvG,8BAA8B,eAAe,6DAA6D,8BAA8B;AAAA,EAExI,oBAAoB,eAAe,6CAA6C,oBAAoB;AAAA,EACpG,cAAc,eAAe,mCAAmC,cAAc;AAAA,EAE9E,aAAa,eAAe,uCAAuC,aAAa;AAAA,EAChF,WAAW,eAAe,8CAA8C;AAAA,EACxE,WAAW,eAAe,8CAA8C,WAAW;AAAA,EACnF,kBAAkB,eAAe,4CAA4C,kBAAkB;AAAA,EAC/F,sBAAsB,eAAe,gDAAgD,sBAAsB;AAC7G,CAAC;AAID,SAAS,WAAgB;AACvB,QAAM,YAAY,UAAU,UAAU,QAAQ,GAAG;AAEjD,MAAI,CAAC,UAAU,SAAS;AACtB,YAAQ,MAAM,qBAAgB;AAC9B,YAAQ,MAAM,KAAK,UAAU,UAAU,MAAM,QAAQ,EAAE,aAAa,MAAM,CAAC,CAAC;AAC5E,YAAQ,KAAK,CAAC;AAAA,EAChB;AAEA,SAAO,UAAU;AACnB;AAEA,IAAM,MAAW,SAAS;AAS1B,IAAO,cAAQ;;;ADjCf,SAAS,oBAAoB,SAA8B;AACzD,SAAO,IAAI,gBAAAC,QAAI;AAAA;AAAA;AAAA,IAGb,SAAS,YAAI,gBAAgB;AAAA,IAC7B,aAAa,YAAI,oBAAoB;AAAA,IACrC,eAAe,QAAQ;AAAA,IACvB,eAAe,QAAQ;AAAA,EACzB,CAAC;AACH;AAWA,eAAsB,eACpB,YACA,SACA,OAAkB,SAClB,QACiB;AACjB,QAAM,SAAS,oBAAoB,OAAO;AAG1C,QAAM,eAAe,SACjB,OAAO;AAAA,IACL,OAAO,QAAQ,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,KAAK,OAAO,KAAK,CAAC,CAAC;AAAA,EACnE,IACF;AAEF,SAAO,OAAO,IAAI,eAAe,YAAY;AAAA,IAC3C;AAAA,IACA,YAAY,QAAQ,cAAc;AAAA,IAClC,QAAQ;AAAA,EACV,CAAC;AACH;AAYA,eAAsB,QACpB,KACA,YACA,SACA,OAAkB,SAClB,QACiB;AACjB,QAAM,QAAQ,MAAM,eAAe,YAAY,SAAS,MAAM,MAAM;AACpE,QAAM,YAAY,IAAI,SAAS,GAAG,IAAI,MAAM;AAC5C,SAAO,GAAG,GAAG,GAAG,SAAS,SAAS,KAAK;AACzC;;;AEpGO,IAAM,2BAA2B;AAWxC,eAAsB,iBACpB,YACA,QAAgB,0BAChB,gBACiB;AACjB,QAAM,UAAU,yBAAyB,UAAU;AAEnD,MAAI,gBAAgB;AAClB,WAAO,QAAQ,SAAS,YAAY,gBAAgB,cAAc,EAAE,MAAM,CAAC;AAAA,EAC7E;AAEA,SAAO,GAAG,OAAO,UAAU,KAAK;AAClC;;;ACjBO,SAAS,mBAAmB,MAAsB;AACvD,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK,EAAE;AACvC,SAAO,KAAK,KAAK,QAAQ,IAAI;AAC/B;AAUO,SAAS,cACd,MACA,WACA,gBAAwB,GACX;AACb,MAAI,CAAC,KAAK,KAAK,GAAG;AAChB,WAAO,CAAC;AAAA,EACV;AAEA,QAAM,SAAsB,CAAC;AAC7B,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AAGrC,QAAM,gBAAgB,KAAK,MAAM,YAAY,IAAI;AACjD,QAAM,eAAe,KAAK,MAAM,gBAAgB,IAAI;AAEpD,MAAI,aAAa;AACjB,MAAI,kBAAkB;AAEtB,SAAO,kBAAkB,MAAM,QAAQ;AACrC,UAAM,aAAa,MAAM;AAAA,MACvB;AAAA,MACA,kBAAkB;AAAA,IACpB;AACA,UAAMC,aAAY,WAAW,KAAK,GAAG;AACrC,UAAM,aAAa,mBAAmBA,UAAS;AAE/C,WAAO,KAAK;AAAA,MACV,IAAI,SAAS,UAAU;AAAA,MACvB,MAAMA;AAAA,MACN;AAAA,IACF,CAAC;AAGD,uBAAmB,gBAAgB;AACnC;AAGA,QAAI,oBAAoB,aAAa,MAAM,gBAAgB,eAAe;AACxE;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAKA,SAAS,oBAAoB,MAAgB,OAA0B;AACrE,QAAM,OAAO,KAAK,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,GAAG;AAC3C,SAAO;AAAA,IACL,IAAI,SAAS,KAAK;AAAA,IAClB;AAAA,IACA,YAAY,mBAAmB,IAAI;AAAA,IACnC,WAAW,KAAK,CAAC,EAAE;AAAA,IACnB,SAAS,KAAK,KAAK,SAAS,CAAC,EAAE;AAAA,EACjC;AACF;AAWO,SAAS,aACd,MACA,WACA,cAAsB,GACT;AACb,MAAI,KAAK,WAAW;AAClB,WAAO,CAAC;AAEV,QAAM,SAAsB,CAAC;AAC7B,MAAI,cAAwB,CAAC;AAC7B,MAAI,gBAAgB;AACpB,MAAI,aAAa;AAEjB,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,UAAM,MAAM,KAAK,CAAC;AAClB,UAAM,YAAY,mBAAmB,IAAI,IAAI;AAG7C,QAAI,gBAAgB,YAAY,aAAa,YAAY,SAAS,GAAG;AACnE,aAAO,KAAK,oBAAoB,aAAa,UAAU,CAAC;AACxD;AAGA,YAAM,eAAe,KAAK,IAAI,GAAG,YAAY,SAAS,WAAW;AACjE,oBAAc,YAAY,MAAM,YAAY;AAC5C,sBAAgB,YAAY;AAAA,QAC1B,CAAC,KAAK,MAAM,MAAM,mBAAmB,EAAE,IAAI;AAAA,QAC3C;AAAA,MACF;AAAA,IACF;AAEA,gBAAY,KAAK,GAAG;AACpB,qBAAiB;AAAA,EACnB;AAGA,MAAI,YAAY,SAAS,GAAG;AAC1B,WAAO,KAAK,oBAAoB,aAAa,UAAU,CAAC;AAAA,EAC1D;AAEA,SAAO;AACT;AASO,SAAS,UAAU,MAAc,UAAyC;AAC/E,UAAQ,SAAS,MAAM;AAAA,IACrB,KAAK,SAAS;AACZ,aAAO,cAAc,MAAM,SAAS,WAAW,SAAS,WAAW,CAAC;AAAA,IACtE;AAAA,IACA,SAAS;AACP,YAAM,kBAAyB;AAC/B,YAAM,IAAI,MAAM,kCAAkC,eAAe,EAAE;AAAA,IACrE;AAAA,EACF;AACF;;;AClIA,eAAsB,iBACpB,YACA,UACA,UAA4B,CAAC,GACV;AACnB,QAAM,EAAE,WAAW,IAAI,QAAQ,KAAK,eAAe,IAAI;AACvD,QAAM,aAAuB,CAAC;AAE9B,MAAI,YAAY,IAAI;AAClB,UAAM,UAAU,WAAW;AAC3B,aAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,iBAAW,KAAK,KAAK,MAAM,IAAI,OAAO,CAAC;AAAA,IACzC;AAAA,EACF,OAAO;AACL,aAAS,OAAO,GAAG,OAAO,UAAU,QAAQ,UAAU;AACpD,iBAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,QAAM,UAAU,yBAAyB,UAAU;AAEnD,QAAM,cAAc,WAAW,IAAI,OAAO,SAAS;AACjD,QAAI,gBAAgB;AAClB,aAAO,QAAQ,SAAS,YAAY,gBAAgB,aAAa,EAAE,MAAM,MAAM,CAAC;AAAA,IAClF;AAEA,WAAO,GAAG,OAAO,SAAS,IAAI,UAAU,KAAK;AAAA,EAC/C,CAAC;AAED,SAAO,QAAQ,IAAI,WAAW;AAChC;;;AC3BO,SAAS,mBAAmB,OAAmC;AACpE,UAAQ,MAAM,UAAU,CAAC,GAAG;AAAA,IAC1B,WAAS,MAAM,SAAS,UAAU,MAAM,WAAW;AAAA,EACrD;AACF;AAEO,SAAS,iBAAiB,OAAiB,cAAmD;AACnG,QAAM,SAAS,mBAAmB,KAAK;AACvC,MAAI,CAAC,OAAO;AACV,WAAO;AAET,MAAI,CAAC,cAAc;AACjB,WAAO,OAAO,CAAC;AAAA,EACjB;AAEA,SAAO,OAAO;AAAA,IACZ,WACE,MAAM,cAAc,eACpB,MAAM,kBAAkB;AAAA,EAC5B;AACF;AAEO,SAAS,mBAAmB,YAA4B;AAC7D,MAAI,CAAC,WAAW,KAAK,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,QAAM,YAAsB,CAAC;AAE7B,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AAE3B,QAAI,CAAC;AACH;AACF,QAAI,SAAS;AACX;AACF,QAAI,KAAK,WAAW,OAAO;AACzB;AACF,QAAI,KAAK,SAAS,KAAK;AACrB;AACF,QAAI,WAAW,KAAK,IAAI,KAAK,CAAC,KAAK,SAAS,GAAG;AAC7C;AACF,QAAI,KAAK,WAAW,OAAO,KAAK,KAAK,WAAW,QAAQ;AACtD;AAEF,UAAM,YAAY,KAAK,QAAQ,YAAY,EAAE,EAAE,KAAK;AAEpD,QAAI,WAAW;AACb,gBAAU,KAAK,SAAS;AAAA,IAC1B;AAAA,EACF;AAEA,SAAO,UAAU,KAAK,GAAG,EAAE,QAAQ,QAAQ,GAAG,EAAE,KAAK;AACvD;AAEO,SAAS,sBAAsB,WAA2B;AAC/D,QAAM,QAAQ,UAAU,MAAM,GAAG;AACjC,MAAI,MAAM,WAAW;AACnB,WAAO;AAET,QAAM,QAAQ,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK;AAC/C,QAAM,UAAU,OAAO,SAAS,MAAM,CAAC,GAAG,EAAE,KAAK;AACjD,QAAM,UAAU,OAAO,WAAW,MAAM,CAAC,CAAC,KAAK;AAE/C,SAAO,QAAQ,OAAO,UAAU,KAAK;AACvC;AAEO,SAAS,6BAA6B,YAA4B;AACvE,MAAI,CAAC,WAAW,KAAK,GAAG;AACtB,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,QAAM,WAAkD,CAAC;AAEzD,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AAE3B,QAAI,KAAK,SAAS,KAAK,GAAG;AACxB,YAAM,YAAY,KAAK,MAAM,OAAO,EAAE,CAAC,EAAE,KAAK;AAC9C,YAAM,gBAAgB,sBAAsB,SAAS;AAErD,UAAI,IAAI,IAAI;AACZ,aAAO,IAAI,MAAM,UAAU,CAAC,MAAM,CAAC,EAAE,KAAK,GAAG;AAC3C;AAAA,MACF;AAEA,UAAI,IAAI,MAAM,QAAQ;AACpB,cAAM,OAAO,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,YAAY,EAAE;AACnD,YAAI,MAAM;AACR,mBAAS,KAAK,EAAE,MAAM,eAAe,KAAK,CAAC;AAAA,QAC7C;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,SAAO,SACJ,IAAI,aAAW,IAAI,KAAK,MAAM,QAAQ,IAAI,CAAC,MAAM,QAAQ,IAAI,EAAE,EAC/D,KAAK,IAAI;AACd;AAQO,SAAS,aAAa,YAA8B;AACzD,MAAI,CAAC,WAAW,KAAK;AACnB,WAAO,CAAC;AAEV,QAAM,QAAQ,WAAW,MAAM,IAAI;AACnC,QAAM,OAAiB,CAAC;AAExB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,OAAO,MAAM,CAAC,EAAE,KAAK;AAE3B,QAAI,KAAK,SAAS,KAAK,GAAG;AACxB,YAAM,CAAC,UAAU,MAAM,IAAI,KAAK,MAAM,OAAO,EAAE,IAAI,OAAK,EAAE,KAAK,CAAC;AAChE,YAAM,YAAY,sBAAsB,QAAQ;AAChD,YAAM,UAAU,sBAAsB,OAAO,MAAM,GAAG,EAAE,CAAC,CAAC;AAG1D,YAAM,YAAsB,CAAC;AAC7B,UAAI,IAAI,IAAI;AACZ,aAAO,IAAI,MAAM,UAAU,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC,MAAM,CAAC,EAAE,SAAS,KAAK,GAAG;AACvE,cAAM,YAAY,MAAM,CAAC,EAAE,KAAK,EAAE,QAAQ,YAAY,EAAE;AACxD,YAAI;AACF,oBAAU,KAAK,SAAS;AAC1B;AAAA,MACF;AAEA,UAAI,UAAU,SAAS,GAAG;AACxB,aAAK,KAAK;AAAA,UACR;AAAA,UACA;AAAA,UACA,MAAM,UAAU,KAAK,GAAG;AAAA,QAC1B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AAWA,eAAsB,mBACpB,YACA,SACA,gBACiB;AACjB,QAAM,UAAU,0BAA0B,UAAU,SAAS,OAAO;AAEpE,MAAI,gBAAgB;AAClB,WAAO,QAAQ,SAAS,YAAY,gBAAgB,OAAO;AAAA,EAC7D;AAEA,SAAO;AACT;AAEA,eAAsB,wBACpB,OACA,YACA,UAAkC,CAAC,GACR;AAC3B,QAAM,EAAE,cAAc,kBAAkB,MAAM,eAAe,IAAI;AACjE,QAAM,QAAQ,iBAAiB,OAAO,YAAY;AAElD,MAAI,CAAC,OAAO;AACV,WAAO,EAAE,gBAAgB,GAAG;AAAA,EAC9B;AAEA,MAAI,CAAC,MAAM,IAAI;AACb,WAAO,EAAE,gBAAgB,IAAI,MAAM;AAAA,EACrC;AAEA,QAAM,gBAAgB,MAAM,mBAAmB,YAAY,MAAM,IAAI,cAAc;AAEnF,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,aAAa;AAC1C,QAAI,CAAC,SAAS,IAAI;AAChB,aAAO,EAAE,gBAAgB,IAAI,eAAe,MAAM;AAAA,IACpD;AAEA,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,UAAM,iBAAiB,kBAAkB,mBAAmB,MAAM,IAAI;AAEtE,WAAO,EAAE,gBAAgB,eAAe,MAAM;AAAA,EAChD,SAAS,OAAO;AACd,YAAQ,KAAK,+BAA+B,KAAK;AACjD,WAAO,EAAE,gBAAgB,IAAI,eAAe,MAAM;AAAA,EACpD;AACF;","names":["path","Mux","chunkText"]}