@effing/effie 0.1.2 → 0.2.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.
- package/dist/index.d.ts +27 -1
- package/dist/index.js +26 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -132,6 +132,17 @@ declare function effieDataForSegment(effieData: EffieData<EffieSources>, segment
|
|
|
132
132
|
*/
|
|
133
133
|
declare function effieDataForJoin<U extends string = EffieWebUrl, V extends string = EffieWebUrl>(effieData: EffieData<EffieSources<U>, U>, segmentSourceUrls: V[]): EffieData<EffieSources<U | V>, U | V>;
|
|
134
134
|
|
|
135
|
+
/**
|
|
136
|
+
* Source type for extraction
|
|
137
|
+
*/
|
|
138
|
+
type EffieSourceType = "image" | "video" | "audio" | "animation";
|
|
139
|
+
/**
|
|
140
|
+
* A source with its type information
|
|
141
|
+
*/
|
|
142
|
+
type EffieSourceWithType = {
|
|
143
|
+
url: string;
|
|
144
|
+
type: EffieSourceType;
|
|
145
|
+
};
|
|
135
146
|
/**
|
|
136
147
|
* Options for extracting sources from EffieData
|
|
137
148
|
*/
|
|
@@ -139,6 +150,21 @@ type ExtractSourcesOptions = {
|
|
|
139
150
|
/** Include data URLs in the result (default: false) */
|
|
140
151
|
includeDataUrls?: boolean;
|
|
141
152
|
};
|
|
153
|
+
/**
|
|
154
|
+
* Extract all source URLs from an EffieData composition with their types.
|
|
155
|
+
* Resolves #references and deduplicates results.
|
|
156
|
+
*
|
|
157
|
+
* @param effieData - The Effie composition
|
|
158
|
+
* @param options - Extraction options
|
|
159
|
+
* @returns Array of unique source URLs with their types
|
|
160
|
+
*
|
|
161
|
+
* @example
|
|
162
|
+
* ```ts
|
|
163
|
+
* const sources = extractEffieSourcesWithTypes(effieData);
|
|
164
|
+
* // [{ url: "https://cdn.example.com/bg.jpg", type: "image" }, ...]
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
declare function extractEffieSourcesWithTypes<U extends string = EffieWebUrl>(effieData: EffieData<EffieSources<U>, U>, options?: ExtractSourcesOptions): EffieSourceWithType[];
|
|
142
168
|
/**
|
|
143
169
|
* Extract all source URLs from an EffieData composition.
|
|
144
170
|
* Resolves #references and deduplicates results.
|
|
@@ -10469,4 +10495,4 @@ declare const effieDataSchema: z.ZodType<EffieData<EffieSources<EffieWebUrl>, Ef
|
|
|
10469
10495
|
type WebOrFileUrl = EffieWebUrl | EffieFileUrl;
|
|
10470
10496
|
declare const effieDataWithFilesSchema: z.ZodType<EffieData<EffieSources<WebOrFileUrl>, WebOrFileUrl>>;
|
|
10471
10497
|
|
|
10472
|
-
export { type EffieAudio, type EffieBackground, type EffieData, type EffieDataUrl, type EffieEffect, type EffieFileUrl, type EffieHttpUrl, type EffieLayer, type EffieMotion, type EffieResponseOptions, type EffieSegment, type EffieSource, type EffieSources, type EffieTransition, type EffieWebUrl, type ExtractSourcesOptions, createEffieAudioSchema, createEffieBackgroundSchema, createEffieDataSchema, createEffieLayerSchema, createEffieSegmentSchema, createEffieSourceSchema, createEffieSourcesSchema, effieAudioSchema, effieBackground, effieBackgroundSchema, effieData, effieDataForJoin, effieDataForSegment, effieDataSchema, effieDataUrlSchema, effieDataWithFilesSchema, effieEffectSchema, effieFileUrl, effieFileUrlSchema, effieHttpUrlSchema, effieLayer, effieLayerSchema, effieMotionSchema, effieResponse, effieSegment, effieSegmentSchema, effieSourceSchema, effieSourcesSchema, effieTransitionSchema, effieWebUrl, effieWebUrlSchema, extractEffieSources };
|
|
10498
|
+
export { type EffieAudio, type EffieBackground, type EffieData, type EffieDataUrl, type EffieEffect, type EffieFileUrl, type EffieHttpUrl, type EffieLayer, type EffieMotion, type EffieResponseOptions, type EffieSegment, type EffieSource, type EffieSourceType, type EffieSourceWithType, type EffieSources, type EffieTransition, type EffieWebUrl, type ExtractSourcesOptions, createEffieAudioSchema, createEffieBackgroundSchema, createEffieDataSchema, createEffieLayerSchema, createEffieSegmentSchema, createEffieSourceSchema, createEffieSourcesSchema, effieAudioSchema, effieBackground, effieBackgroundSchema, effieData, effieDataForJoin, effieDataForSegment, effieDataSchema, effieDataUrlSchema, effieDataWithFilesSchema, effieEffectSchema, effieFileUrl, effieFileUrlSchema, effieHttpUrlSchema, effieLayer, effieLayerSchema, effieMotionSchema, effieResponse, effieSegment, effieSegmentSchema, effieSourceSchema, effieSourcesSchema, effieTransitionSchema, effieWebUrl, effieWebUrlSchema, extractEffieSources, extractEffieSourcesWithTypes };
|
package/dist/index.js
CHANGED
|
@@ -122,10 +122,10 @@ function effieDataForJoin(effieData2, segmentSourceUrls) {
|
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
// src/extract.ts
|
|
125
|
-
function
|
|
125
|
+
function extractEffieSourcesWithTypes(effieData2, options = {}) {
|
|
126
126
|
const { includeDataUrls = false } = options;
|
|
127
|
-
const
|
|
128
|
-
const addSource = (src) => {
|
|
127
|
+
const sourceMap = /* @__PURE__ */ new Map();
|
|
128
|
+
const addSource = (src, type) => {
|
|
129
129
|
if (src.startsWith("#")) {
|
|
130
130
|
const name = src.slice(1);
|
|
131
131
|
if (effieData2.sources?.[name]) {
|
|
@@ -137,27 +137,38 @@ function extractEffieSources(effieData2, options = {}) {
|
|
|
137
137
|
if (!includeDataUrls && src.startsWith("data:")) {
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
|
-
|
|
140
|
+
if (!sourceMap.has(src)) {
|
|
141
|
+
sourceMap.set(src, type);
|
|
142
|
+
}
|
|
141
143
|
};
|
|
142
|
-
addSource(effieData2.cover);
|
|
143
|
-
if (effieData2.background.type
|
|
144
|
-
addSource(effieData2.background.source);
|
|
144
|
+
addSource(effieData2.cover, "image");
|
|
145
|
+
if (effieData2.background.type === "image") {
|
|
146
|
+
addSource(effieData2.background.source, "image");
|
|
147
|
+
} else if (effieData2.background.type === "video") {
|
|
148
|
+
addSource(effieData2.background.source, "video");
|
|
145
149
|
}
|
|
146
150
|
if (effieData2.audio) {
|
|
147
|
-
addSource(effieData2.audio.source);
|
|
151
|
+
addSource(effieData2.audio.source, "audio");
|
|
148
152
|
}
|
|
149
153
|
for (const segment of effieData2.segments) {
|
|
150
|
-
if (segment.background
|
|
151
|
-
|
|
154
|
+
if (segment.background) {
|
|
155
|
+
if (segment.background.type === "image") {
|
|
156
|
+
addSource(segment.background.source, "image");
|
|
157
|
+
} else if (segment.background.type === "video") {
|
|
158
|
+
addSource(segment.background.source, "video");
|
|
159
|
+
}
|
|
152
160
|
}
|
|
153
161
|
if (segment.audio) {
|
|
154
|
-
addSource(segment.audio.source);
|
|
162
|
+
addSource(segment.audio.source, "audio");
|
|
155
163
|
}
|
|
156
164
|
for (const layer of segment.layers) {
|
|
157
|
-
addSource(layer.source);
|
|
165
|
+
addSource(layer.source, layer.type);
|
|
158
166
|
}
|
|
159
167
|
}
|
|
160
|
-
return Array.from(
|
|
168
|
+
return Array.from(sourceMap.entries()).map(([url, type]) => ({ url, type }));
|
|
169
|
+
}
|
|
170
|
+
function extractEffieSources(effieData2, options = {}) {
|
|
171
|
+
return extractEffieSourcesWithTypes(effieData2, options).map((s) => s.url);
|
|
161
172
|
}
|
|
162
173
|
|
|
163
174
|
// src/response.ts
|
|
@@ -464,6 +475,7 @@ export {
|
|
|
464
475
|
effieTransitionSchema,
|
|
465
476
|
effieWebUrl,
|
|
466
477
|
effieWebUrlSchema,
|
|
467
|
-
extractEffieSources
|
|
478
|
+
extractEffieSources,
|
|
479
|
+
extractEffieSourcesWithTypes
|
|
468
480
|
};
|
|
469
481
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts","../src/partition.ts","../src/extract.ts","../src/response.ts","../src/schema.ts"],"sourcesContent":["export type EffieWebUrl = EffieHttpUrl | EffieDataUrl; // [!] does not include file URLs\nexport type EffieHttpUrl = `http${string}`; // HTTP URL starts with http: or https:\nexport type EffieDataUrl = `data${string}`; // data URL starts with data:\n\nexport type EffieFileUrl = `file${string}`; // file URL starts with file:\n\nexport type EffieSources<U extends string = EffieWebUrl> = {\n [key: string]: U; // key: source name, value: URL\n};\n\nexport type EffieSource<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = U | `#${Extract<keyof S, string>}`; // source name\n\nexport type EffieData<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n width: number; // frame width\n height: number; // frame height\n fps: number; // frames per second\n cover: EffieWebUrl; // cover image has to be a direct URL\n sources?: S; // common sources, to avoid duplication\n background: EffieBackground<S, U>; // all-encompassing background\n audio?: EffieAudio<S, U>; // general soundtrack audio\n segments: EffieSegment<S, U>[]; // consecutive video segments\n};\n\nexport type EffieBackground<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> =\n | {\n type: \"image\";\n source: EffieSource<S, U>;\n }\n | {\n type: \"video\";\n source: EffieSource<S, U>;\n seek?: number; // seek to this position in seconds\n }\n | {\n type: \"color\";\n color: string; // color name or [0x|#]RRGGBB[AA]\n };\n\nexport type EffieAudio<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n source: EffieSource<S, U>;\n volume?: number; // volume in range [0, 1]\n fadeIn?: number; // fade-in duration in seconds\n fadeOut?: number; // fade-out duration in seconds\n seek?: number; // seek to this position in seconds\n};\n\nexport type EffieSegment<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n duration: number;\n layers: EffieLayer<S, U>[];\n background?: EffieBackground<S, U>; // overrides global background for this segment\n audio?: EffieAudio<S, U>;\n transition?: EffieTransition; // ignored on the first segment\n};\n\nexport type EffieLayer<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n type:\n | \"image\" // png or jpeg\n | \"animation\"; // annie\n source: EffieSource<S, U>;\n delay?: number; // delay (before start) time in seconds\n from?: number; // clip from this time in seconds\n until?: number; // clip until this time in seconds\n effects?: EffieEffect[];\n motion?: EffieMotion;\n};\n\nexport type EffieTransition = {\n duration: number;\n} & (\n | { type: \"fade\"; easing?: \"linear\" | \"ease-in\" | \"ease-out\" }\n // Fade through color (always linear)\n | { type: \"fade\"; through: \"black\" | \"white\" | \"grays\" }\n // Barn door wipes (default: horizontal, open)\n | {\n type: \"barn\";\n orientation?: \"horizontal\" | \"vertical\";\n mode?: \"open\" | \"close\";\n }\n // Circle wipes (default: open)\n | { type: \"circle\"; mode?: \"open\" | \"close\" | \"crop\" }\n // Directional transitions (default: left)\n | {\n type: \"wipe\" | \"slide\" | \"smooth\" | \"slice\";\n direction?: \"left\" | \"right\" | \"up\" | \"down\";\n }\n // Zoom\n | { type: \"zoom\" }\n // Standalone transitions\n | { type: \"dissolve\" | \"pixelize\" | \"radial\" }\n);\n\nexport type EffieEffect = {\n duration: number;\n} & (\n | { type: \"fade-in\"; start: number }\n | { type: \"fade-out\"; start: number }\n | { type: \"saturate-in\"; start: number }\n | { type: \"saturate-out\"; start: number }\n | {\n type: \"scroll\";\n direction: \"left\" | \"right\" | \"up\" | \"down\";\n distance: number;\n }\n);\n\nexport type EffieMotion = {\n start?: number;\n duration?: number;\n} & (\n | { type: \"bounce\"; amplitude?: number }\n | { type: \"shake\"; intensity?: number; frequency?: number }\n | {\n type: \"slide\";\n direction: \"left\" | \"right\" | \"up\" | \"down\";\n distance?: number;\n reverse?: boolean;\n easing?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n }\n);\n\nexport function effieWebUrl(url: string) {\n if (url.startsWith(\"http\") || url.startsWith(\"data\")) {\n return url as EffieWebUrl;\n }\n throw new Error(`Invalid web URL: ${url}`);\n}\n\nexport function effieFileUrl(url: string) {\n if (url.startsWith(\"file\")) {\n return url as EffieFileUrl;\n }\n throw new Error(`Invalid file URL: ${url}`);\n}\n\nexport function effieData<S extends EffieSources>(data: EffieData<S>) {\n return data; // just for typing convenience\n}\n\nexport function effieBackground<S extends EffieSources>(\n background: EffieBackground<S>,\n) {\n return background; // just for typing convenience\n}\n\nexport function effieSegment<S extends EffieSources>(segment: EffieSegment<S>) {\n return segment; // just for typing convenience\n}\n\nexport function effieLayer<S extends EffieSources>(layer: EffieLayer<S>) {\n return layer; // just for typing convenience\n}\n","import type { EffieData, EffieSources, EffieWebUrl } from \"./types\";\n\n/**\n * Returns a minimal EffieData containing only what's needed to render a single segment.\n * Can be used for distributed rendering where each segment is rendered independently.\n */\nexport function effieDataForSegment(\n effieData: EffieData<EffieSources>,\n segmentIndex: number,\n): EffieData<EffieSources> {\n if (segmentIndex < 0 || segmentIndex >= effieData.segments.length) {\n throw new Error(\n `Invalid segment index: ${segmentIndex}. Must be between 0 and ${\n effieData.segments.length - 1\n }`,\n );\n }\n\n const segment = effieData.segments[segmentIndex];\n\n // Collect all source references used by this segment\n const usedSourceRefs = new Set<string>();\n\n // Check global background source\n if (effieData.background.type !== \"color\") {\n const bgSource = effieData.background.source;\n if (typeof bgSource === \"string\" && bgSource.startsWith(\"#\")) {\n usedSourceRefs.add(bgSource.slice(1));\n }\n }\n\n // Check segment background source\n if (segment.background && segment.background.type !== \"color\") {\n const segBgSource = segment.background.source;\n if (typeof segBgSource === \"string\" && segBgSource.startsWith(\"#\")) {\n usedSourceRefs.add(segBgSource.slice(1));\n }\n }\n\n // Check layer sources\n for (const layer of segment.layers) {\n if (typeof layer.source === \"string\" && layer.source.startsWith(\"#\")) {\n usedSourceRefs.add(layer.source.slice(1));\n }\n }\n\n // Check segment audio source\n if (segment.audio) {\n const audioSource = segment.audio.source;\n if (typeof audioSource === \"string\" && audioSource.startsWith(\"#\")) {\n usedSourceRefs.add(audioSource.slice(1));\n }\n }\n\n // Build minimal sources object with only referenced sources\n const minimalSources: EffieSources = {};\n if (effieData.sources) {\n for (const ref of usedSourceRefs) {\n if (ref in effieData.sources) {\n minimalSources[ref] = effieData.sources[ref];\n }\n }\n }\n\n // Build background with accumulated seek time for video backgrounds\n const background =\n effieData.background.type === \"video\"\n ? {\n ...effieData.background,\n seek:\n (effieData.background.seek ?? 0) +\n effieData.segments\n .slice(0, segmentIndex)\n .reduce((sum, seg) => sum + seg.duration, 0),\n }\n : effieData.background;\n\n // Create minimal effie data with just this segment\n return {\n width: effieData.width,\n height: effieData.height,\n fps: effieData.fps,\n cover: effieData.cover,\n background,\n segments: [segment], // Only include the target segment (with its background if any)\n ...(Object.keys(minimalSources).length > 0\n ? { sources: minimalSources }\n : {}),\n // Note: global audio is excluded - it's handled in the join phase\n };\n}\n\n/**\n * Returns EffieData for joining pre-rendered segments into a final video.\n * Each segment uses its corresponding pre-rendered video as both background and audio source.\n *\n * @param effieData - The original EffieData with segment metadata (durations, transitions)\n * @param segmentSourceUrls - URLs to pre-rendered segment videos (one per segment)\n */\nexport function effieDataForJoin<\n U extends string = EffieWebUrl,\n V extends string = EffieWebUrl,\n>(\n effieData: EffieData<EffieSources<U>, U>,\n segmentSourceUrls: V[],\n): EffieData<EffieSources<U | V>, U | V> {\n if (segmentSourceUrls.length !== effieData.segments.length) {\n throw new Error(\n `Expected ${effieData.segments.length} segment sources, got ${segmentSourceUrls.length}`,\n );\n }\n\n // Build sources object with segment references and global audio refs\n const sources: EffieSources<U | V> = {};\n\n // Add segment sources as named references (enables caching for background+audio reuse)\n // Using __segment_ prefix to avoid collisions with user-defined sources\n for (let i = 0; i < segmentSourceUrls.length; i++) {\n sources[`__segment_${i}`] = segmentSourceUrls[i];\n }\n\n // Include any source refs used by global audio\n if (effieData.audio) {\n const audioSource = effieData.audio.source;\n if (typeof audioSource === \"string\" && audioSource.startsWith(\"#\")) {\n const ref = audioSource.slice(1);\n if (effieData.sources && ref in effieData.sources) {\n sources[ref] = effieData.sources[ref];\n }\n }\n }\n\n return {\n width: effieData.width,\n height: effieData.height,\n fps: effieData.fps,\n cover: effieData.cover,\n background: { type: \"color\", color: \"black\" }, // Not used - each segment has its own background\n segments: effieData.segments.map((seg, i) => ({\n duration: seg.duration,\n layers: [], // Layers not needed - video is pre-rendered\n transition: seg.transition,\n background: { type: \"video\" as const, source: `#__segment_${i}` },\n audio: { source: `#__segment_${i}` }, // FFmpeg extracts audio from mp4\n })),\n audio: effieData.audio, // Global audio is mixed during render\n sources,\n };\n}\n","import type { EffieData, EffieSources, EffieWebUrl } from \"./types\";\n\n/**\n * Options for extracting sources from EffieData\n */\nexport type ExtractSourcesOptions = {\n /** Include data URLs in the result (default: false) */\n includeDataUrls?: boolean;\n};\n\n/**\n * Extract all source URLs from an EffieData composition.\n * Resolves #references and deduplicates results.\n *\n * @param effieData - The Effie composition\n * @param options - Extraction options\n * @returns Array of unique source URLs\n *\n * @example\n * ```ts\n * const sources = extractEffieSources(effieData);\n * // [\"https://cdn.example.com/bg.jpg\", \"https://api.example.com/annie/hero\", ...]\n * ```\n */\nexport function extractEffieSources<U extends string = EffieWebUrl>(\n effieData: EffieData<EffieSources<U>, U>,\n options: ExtractSourcesOptions = {},\n): string[] {\n const { includeDataUrls = false } = options;\n const sources = new Set<string>();\n\n const addSource = (src: string) => {\n // Resolve #references\n if (src.startsWith(\"#\")) {\n const name = src.slice(1);\n if (effieData.sources?.[name]) {\n src = effieData.sources[name];\n } else {\n return; // Reference not found, skip\n }\n }\n\n // Filter data URLs unless explicitly asked to include\n if (!includeDataUrls && src.startsWith(\"data:\")) {\n return;\n }\n\n sources.add(src);\n };\n\n // Cover image\n addSource(effieData.cover);\n\n // Global background\n if (effieData.background.type !== \"color\") {\n addSource(effieData.background.source);\n }\n\n // Global audio\n if (effieData.audio) {\n addSource(effieData.audio.source);\n }\n\n // Segments\n for (const segment of effieData.segments) {\n // Segment background\n if (segment.background && segment.background.type !== \"color\") {\n addSource(segment.background.source);\n }\n // Segment audio\n if (segment.audio) {\n addSource(segment.audio.source);\n }\n // Layers\n for (const layer of segment.layers) {\n addSource(layer.source);\n }\n }\n\n return Array.from(sources);\n}\n","import type { EffieData, EffieSources } from \"./types\";\n\n/**\n * Options for effie Response generation\n */\nexport type EffieResponseOptions = {\n /** Additional headers to include in the response */\n headers?: HeadersInit;\n /** Cache-Control header value (default: \"public, max-age=3600\") */\n cacheControl?: string;\n};\n\n/**\n * Create an HTTP Response containing effie JSON data\n *\n * This is the most convenient way to serve an effie composition from a web server.\n * It handles JSON serialization, content-type, and caching headers automatically.\n *\n * @param data The effie data to serialize\n * @param options Configuration options\n * @returns Response with JSON body\n *\n * @example\n * ```ts\n * // In a route handler:\n * export async function loader({ params }: LoaderFunctionArgs) {\n * const effie = await renderEffie(effieId, props, { width, height });\n * return effieResponse(effie);\n * }\n * ```\n */\nexport function effieResponse<S extends EffieSources>(\n data: EffieData<S>,\n options: EffieResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n return Response.json(data, { status: 200, headers });\n}\n","import { z } from \"zod\";\nimport type {\n EffieHttpUrl,\n EffieDataUrl,\n EffieWebUrl,\n EffieFileUrl,\n EffieSources,\n EffieData,\n EffieBackground,\n EffieAudio,\n EffieSegment,\n EffieLayer,\n EffieTransition,\n EffieEffect,\n EffieMotion,\n} from \"./types\";\n\n// URL schemas using z.custom to enforce exact type matching:\n\nexport const effieHttpUrlSchema = z.custom<EffieHttpUrl>(\n (val): val is EffieHttpUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") || val.startsWith(\"https://\")),\n { message: \"Must be an HTTP or HTTPS URL\" },\n);\n\nexport const effieDataUrlSchema = z.custom<EffieDataUrl>(\n (val): val is EffieDataUrl =>\n typeof val === \"string\" && val.startsWith(\"data:\"),\n { message: \"Must be a data URL\" },\n);\n\nexport const effieWebUrlSchema = z.custom<EffieWebUrl>(\n (val): val is EffieWebUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") ||\n val.startsWith(\"https://\") ||\n val.startsWith(\"data:\")),\n { message: \"Must be an HTTP, HTTPS, or data URL\" },\n) satisfies z.ZodType<EffieWebUrl>;\n\nexport const effieFileUrlSchema = z.custom<EffieFileUrl>(\n (val): val is EffieFileUrl =>\n typeof val === \"string\" && val.startsWith(\"file:\"),\n { message: \"Must be a file URL\" },\n) satisfies z.ZodType<EffieFileUrl>;\n\n// Source reference schema (matches #sourceName pattern)\nconst sourceRefSchema = z.custom<`#${string}`>(\n (val): val is `#${string}` => typeof val === \"string\" && val.startsWith(\"#\"),\n { message: \"Source reference must start with #\" },\n);\n\n// Transition schema\nexport const effieTransitionSchema = z.union([\n // Fade with easing\n z.strictObject({\n type: z.literal(\"fade\"),\n duration: z.number(),\n easing: z.enum([\"linear\", \"ease-in\", \"ease-out\"]).optional(),\n }),\n // Fade through color\n z.strictObject({\n type: z.literal(\"fade\"),\n duration: z.number(),\n through: z.enum([\"black\", \"white\", \"grays\"]),\n }),\n // Barn door wipes\n z.strictObject({\n type: z.literal(\"barn\"),\n duration: z.number(),\n orientation: z.enum([\"horizontal\", \"vertical\"]).optional(),\n mode: z.enum([\"open\", \"close\"]).optional(),\n }),\n // Circle wipes\n z.strictObject({\n type: z.literal(\"circle\"),\n duration: z.number(),\n mode: z.enum([\"open\", \"close\", \"crop\"]).optional(),\n }),\n // Directional transitions (wipe, slide, smooth, slice)\n z.strictObject({\n type: z.enum([\"wipe\", \"slide\", \"smooth\", \"slice\"]),\n duration: z.number(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]).optional(),\n }),\n // Zoom\n z.strictObject({\n type: z.literal(\"zoom\"),\n duration: z.number(),\n }),\n // Standalone transitions\n z.strictObject({\n type: z.enum([\"dissolve\", \"pixelize\", \"radial\"]),\n duration: z.number(),\n }),\n]) satisfies z.ZodType<EffieTransition>;\n\n// Effect schema\nexport const effieEffectSchema = z.union([\n z.strictObject({\n type: z.literal(\"fade-in\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"fade-out\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"saturate-in\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"saturate-out\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"scroll\"),\n duration: z.number(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]),\n distance: z.number(),\n }),\n]) satisfies z.ZodType<EffieEffect>;\n\n// Motion schema\nexport const effieMotionSchema = z.union([\n z.strictObject({\n type: z.literal(\"bounce\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n amplitude: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"shake\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n intensity: z.number().optional(),\n frequency: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"slide\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]),\n distance: z.number().optional(),\n reverse: z.boolean().optional(),\n easing: z.enum([\"linear\", \"ease-in\", \"ease-out\", \"ease-in-out\"]).optional(),\n }),\n]) satisfies z.ZodType<EffieMotion>;\n\n// Schema factories for generic types.\n// Note: These return inferred Zod types. Type checking happens on the concrete\n// exported schemas below via explicit type annotations (which use `satisfies`\n// semantics - assignment to a typed variable fails if types don't match).\n\nexport function createEffieSourcesSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n return z.record(z.string(), urlSchema);\n}\n\nexport function createEffieSourceSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n return z.union([urlSchema, sourceRefSchema]);\n}\n\nexport function createEffieBackgroundSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.union([\n z.strictObject({\n type: z.literal(\"image\"),\n source: sourceSchema,\n }),\n z.strictObject({\n type: z.literal(\"video\"),\n source: sourceSchema,\n seek: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"color\"),\n color: z.string(),\n }),\n ]);\n}\n\nexport function createEffieAudioSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.strictObject({\n source: sourceSchema,\n volume: z.number().min(0).max(1).optional(),\n fadeIn: z.number().optional(),\n fadeOut: z.number().optional(),\n seek: z.number().optional(),\n });\n}\n\nexport function createEffieLayerSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.strictObject({\n type: z.enum([\"image\", \"animation\"]),\n source: sourceSchema,\n delay: z.number().optional(),\n from: z.number().optional(),\n until: z.number().optional(),\n effects: z.array(effieEffectSchema).optional(),\n motion: effieMotionSchema.optional(),\n });\n}\n\nexport function createEffieSegmentSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const layerSchema = createEffieLayerSchema(urlSchema);\n const backgroundSchema = createEffieBackgroundSchema(urlSchema);\n const audioSchema = createEffieAudioSchema(urlSchema);\n\n return z.strictObject({\n duration: z.number(),\n layers: z.array(layerSchema),\n background: backgroundSchema.optional(),\n audio: audioSchema.optional(),\n transition: effieTransitionSchema.optional(),\n });\n}\n\n// Type for parsed data shape (matches Zod output, used for source ref collection)\ntype ParsedEffieData = {\n background: { source?: string } | { type: \"color\" };\n audio?: { source: string };\n segments: Array<{\n background?: { source?: string } | { type: \"color\" };\n audio?: { source: string };\n layers: Array<{ source: string }>;\n }>;\n};\n\n// Helper to collect all source references from parsed data\nfunction collectSourceRefs(data: ParsedEffieData): string[] {\n const refs: string[] = [];\n\n const addIfRef = (source: string) => {\n if (source.startsWith(\"#\")) {\n refs.push(source.slice(1));\n }\n };\n\n // Top-level background and audio\n if (\"source\" in data.background && data.background.source) {\n addIfRef(data.background.source);\n }\n if (data.audio) {\n addIfRef(data.audio.source);\n }\n\n // Segments\n for (const segment of data.segments) {\n if (\n segment.background &&\n \"source\" in segment.background &&\n segment.background.source\n ) {\n addIfRef(segment.background.source);\n }\n if (segment.audio) {\n addIfRef(segment.audio.source);\n }\n for (const layer of segment.layers) {\n addIfRef(layer.source);\n }\n }\n\n return refs;\n}\n\nexport function createEffieDataSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourcesSchema = createEffieSourcesSchema(urlSchema);\n const segmentSchema = createEffieSegmentSchema(urlSchema);\n const backgroundSchema = createEffieBackgroundSchema(urlSchema);\n const audioSchema = createEffieAudioSchema(urlSchema);\n\n return z\n .strictObject({\n width: z.number(),\n height: z.number(),\n fps: z.number(),\n cover: effieWebUrlSchema, // cover must always be a web URL\n sources: sourcesSchema.optional(),\n background: backgroundSchema,\n audio: audioSchema.optional(),\n segments: z.array(segmentSchema),\n })\n .superRefine((data, ctx) => {\n // Validate source references exist\n const definedSources = new Set(Object.keys(data.sources ?? {}));\n // Type assertion: Zod has validated the structure, but its inferred types\n // add spurious `| undefined` to required fields\n const referencedSources = collectSourceRefs(data as ParsedEffieData);\n\n for (const ref of referencedSources) {\n if (!definedSources.has(ref)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Source reference \"#${ref}\" not found in sources`,\n });\n }\n }\n\n // Validate transition durations: both current and previous segment must be\n // at least as long as the transition duration\n for (let i = 1; i < data.segments.length; i++) {\n const segment = data.segments[i];\n const prevSegment = data.segments[i - 1];\n\n if (segment.transition) {\n const transitionDuration = segment.transition.duration;\n\n if (segment.duration < transitionDuration) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Segment ${i} duration (${segment.duration}s) must be at least as long as its transition duration (${transitionDuration}s)`,\n path: [\"segments\", i, \"duration\"],\n });\n }\n\n if (prevSegment.duration < transitionDuration) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Segment ${i - 1} duration (${prevSegment.duration}s) must be at least as long as the following transition duration (${transitionDuration}s)`,\n path: [\"segments\", i - 1, \"duration\"],\n });\n }\n }\n }\n });\n}\n\n// Default schemas for web URLs (most common use case):\n\nexport const effieSourcesSchema: z.ZodType<EffieSources<EffieWebUrl>> =\n createEffieSourcesSchema(effieWebUrlSchema);\n\nexport const effieSourceSchema = createEffieSourceSchema(effieWebUrlSchema);\n\nexport const effieBackgroundSchema: z.ZodType<\n EffieBackground<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieBackgroundSchema(effieWebUrlSchema);\n\nexport const effieAudioSchema: z.ZodType<\n EffieAudio<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieAudioSchema(effieWebUrlSchema);\n\nexport const effieLayerSchema: z.ZodType<\n EffieLayer<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieLayerSchema(effieWebUrlSchema);\n\nexport const effieSegmentSchema: z.ZodType<\n EffieSegment<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieSegmentSchema(effieWebUrlSchema);\n\nexport const effieDataSchema: z.ZodType<\n EffieData<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieDataSchema(effieWebUrlSchema);\n\n// Schema for data that allows file URLs (for trusted operations)\ntype WebOrFileUrl = EffieWebUrl | EffieFileUrl;\nconst webOrFileUrlSchema = z.custom<WebOrFileUrl>(\n (val): val is WebOrFileUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") ||\n val.startsWith(\"https://\") ||\n val.startsWith(\"data:\") ||\n val.startsWith(\"file:\")),\n { message: \"Must be an HTTP, HTTPS, data, or file URL\" },\n);\n\nexport const effieDataWithFilesSchema: z.ZodType<\n EffieData<EffieSources<WebOrFileUrl>, WebOrFileUrl>\n> = createEffieDataSchema(webOrFileUrlSchema);\n"],"mappings":"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","names":["effieData","effieData"]}
|
|
1
|
+
{"version":3,"sources":["../src/types.ts","../src/partition.ts","../src/extract.ts","../src/response.ts","../src/schema.ts"],"sourcesContent":["export type EffieWebUrl = EffieHttpUrl | EffieDataUrl; // [!] does not include file URLs\nexport type EffieHttpUrl = `http${string}`; // HTTP URL starts with http: or https:\nexport type EffieDataUrl = `data${string}`; // data URL starts with data:\n\nexport type EffieFileUrl = `file${string}`; // file URL starts with file:\n\nexport type EffieSources<U extends string = EffieWebUrl> = {\n [key: string]: U; // key: source name, value: URL\n};\n\nexport type EffieSource<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = U | `#${Extract<keyof S, string>}`; // source name\n\nexport type EffieData<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n width: number; // frame width\n height: number; // frame height\n fps: number; // frames per second\n cover: EffieWebUrl; // cover image has to be a direct URL\n sources?: S; // common sources, to avoid duplication\n background: EffieBackground<S, U>; // all-encompassing background\n audio?: EffieAudio<S, U>; // general soundtrack audio\n segments: EffieSegment<S, U>[]; // consecutive video segments\n};\n\nexport type EffieBackground<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> =\n | {\n type: \"image\";\n source: EffieSource<S, U>;\n }\n | {\n type: \"video\";\n source: EffieSource<S, U>;\n seek?: number; // seek to this position in seconds\n }\n | {\n type: \"color\";\n color: string; // color name or [0x|#]RRGGBB[AA]\n };\n\nexport type EffieAudio<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n source: EffieSource<S, U>;\n volume?: number; // volume in range [0, 1]\n fadeIn?: number; // fade-in duration in seconds\n fadeOut?: number; // fade-out duration in seconds\n seek?: number; // seek to this position in seconds\n};\n\nexport type EffieSegment<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n duration: number;\n layers: EffieLayer<S, U>[];\n background?: EffieBackground<S, U>; // overrides global background for this segment\n audio?: EffieAudio<S, U>;\n transition?: EffieTransition; // ignored on the first segment\n};\n\nexport type EffieLayer<\n S extends EffieSources<U>,\n U extends string = EffieWebUrl,\n> = {\n type:\n | \"image\" // png or jpeg\n | \"animation\"; // annie\n source: EffieSource<S, U>;\n delay?: number; // delay (before start) time in seconds\n from?: number; // clip from this time in seconds\n until?: number; // clip until this time in seconds\n effects?: EffieEffect[];\n motion?: EffieMotion;\n};\n\nexport type EffieTransition = {\n duration: number;\n} & (\n | { type: \"fade\"; easing?: \"linear\" | \"ease-in\" | \"ease-out\" }\n // Fade through color (always linear)\n | { type: \"fade\"; through: \"black\" | \"white\" | \"grays\" }\n // Barn door wipes (default: horizontal, open)\n | {\n type: \"barn\";\n orientation?: \"horizontal\" | \"vertical\";\n mode?: \"open\" | \"close\";\n }\n // Circle wipes (default: open)\n | { type: \"circle\"; mode?: \"open\" | \"close\" | \"crop\" }\n // Directional transitions (default: left)\n | {\n type: \"wipe\" | \"slide\" | \"smooth\" | \"slice\";\n direction?: \"left\" | \"right\" | \"up\" | \"down\";\n }\n // Zoom\n | { type: \"zoom\" }\n // Standalone transitions\n | { type: \"dissolve\" | \"pixelize\" | \"radial\" }\n);\n\nexport type EffieEffect = {\n duration: number;\n} & (\n | { type: \"fade-in\"; start: number }\n | { type: \"fade-out\"; start: number }\n | { type: \"saturate-in\"; start: number }\n | { type: \"saturate-out\"; start: number }\n | {\n type: \"scroll\";\n direction: \"left\" | \"right\" | \"up\" | \"down\";\n distance: number;\n }\n);\n\nexport type EffieMotion = {\n start?: number;\n duration?: number;\n} & (\n | { type: \"bounce\"; amplitude?: number }\n | { type: \"shake\"; intensity?: number; frequency?: number }\n | {\n type: \"slide\";\n direction: \"left\" | \"right\" | \"up\" | \"down\";\n distance?: number;\n reverse?: boolean;\n easing?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n }\n);\n\nexport function effieWebUrl(url: string) {\n if (url.startsWith(\"http\") || url.startsWith(\"data\")) {\n return url as EffieWebUrl;\n }\n throw new Error(`Invalid web URL: ${url}`);\n}\n\nexport function effieFileUrl(url: string) {\n if (url.startsWith(\"file\")) {\n return url as EffieFileUrl;\n }\n throw new Error(`Invalid file URL: ${url}`);\n}\n\nexport function effieData<S extends EffieSources>(data: EffieData<S>) {\n return data; // just for typing convenience\n}\n\nexport function effieBackground<S extends EffieSources>(\n background: EffieBackground<S>,\n) {\n return background; // just for typing convenience\n}\n\nexport function effieSegment<S extends EffieSources>(segment: EffieSegment<S>) {\n return segment; // just for typing convenience\n}\n\nexport function effieLayer<S extends EffieSources>(layer: EffieLayer<S>) {\n return layer; // just for typing convenience\n}\n","import type { EffieData, EffieSources, EffieWebUrl } from \"./types\";\n\n/**\n * Returns a minimal EffieData containing only what's needed to render a single segment.\n * Can be used for distributed rendering where each segment is rendered independently.\n */\nexport function effieDataForSegment(\n effieData: EffieData<EffieSources>,\n segmentIndex: number,\n): EffieData<EffieSources> {\n if (segmentIndex < 0 || segmentIndex >= effieData.segments.length) {\n throw new Error(\n `Invalid segment index: ${segmentIndex}. Must be between 0 and ${\n effieData.segments.length - 1\n }`,\n );\n }\n\n const segment = effieData.segments[segmentIndex];\n\n // Collect all source references used by this segment\n const usedSourceRefs = new Set<string>();\n\n // Check global background source\n if (effieData.background.type !== \"color\") {\n const bgSource = effieData.background.source;\n if (typeof bgSource === \"string\" && bgSource.startsWith(\"#\")) {\n usedSourceRefs.add(bgSource.slice(1));\n }\n }\n\n // Check segment background source\n if (segment.background && segment.background.type !== \"color\") {\n const segBgSource = segment.background.source;\n if (typeof segBgSource === \"string\" && segBgSource.startsWith(\"#\")) {\n usedSourceRefs.add(segBgSource.slice(1));\n }\n }\n\n // Check layer sources\n for (const layer of segment.layers) {\n if (typeof layer.source === \"string\" && layer.source.startsWith(\"#\")) {\n usedSourceRefs.add(layer.source.slice(1));\n }\n }\n\n // Check segment audio source\n if (segment.audio) {\n const audioSource = segment.audio.source;\n if (typeof audioSource === \"string\" && audioSource.startsWith(\"#\")) {\n usedSourceRefs.add(audioSource.slice(1));\n }\n }\n\n // Build minimal sources object with only referenced sources\n const minimalSources: EffieSources = {};\n if (effieData.sources) {\n for (const ref of usedSourceRefs) {\n if (ref in effieData.sources) {\n minimalSources[ref] = effieData.sources[ref];\n }\n }\n }\n\n // Build background with accumulated seek time for video backgrounds\n const background =\n effieData.background.type === \"video\"\n ? {\n ...effieData.background,\n seek:\n (effieData.background.seek ?? 0) +\n effieData.segments\n .slice(0, segmentIndex)\n .reduce((sum, seg) => sum + seg.duration, 0),\n }\n : effieData.background;\n\n // Create minimal effie data with just this segment\n return {\n width: effieData.width,\n height: effieData.height,\n fps: effieData.fps,\n cover: effieData.cover,\n background,\n segments: [segment], // Only include the target segment (with its background if any)\n ...(Object.keys(minimalSources).length > 0\n ? { sources: minimalSources }\n : {}),\n // Note: global audio is excluded - it's handled in the join phase\n };\n}\n\n/**\n * Returns EffieData for joining pre-rendered segments into a final video.\n * Each segment uses its corresponding pre-rendered video as both background and audio source.\n *\n * @param effieData - The original EffieData with segment metadata (durations, transitions)\n * @param segmentSourceUrls - URLs to pre-rendered segment videos (one per segment)\n */\nexport function effieDataForJoin<\n U extends string = EffieWebUrl,\n V extends string = EffieWebUrl,\n>(\n effieData: EffieData<EffieSources<U>, U>,\n segmentSourceUrls: V[],\n): EffieData<EffieSources<U | V>, U | V> {\n if (segmentSourceUrls.length !== effieData.segments.length) {\n throw new Error(\n `Expected ${effieData.segments.length} segment sources, got ${segmentSourceUrls.length}`,\n );\n }\n\n // Build sources object with segment references and global audio refs\n const sources: EffieSources<U | V> = {};\n\n // Add segment sources as named references (enables caching for background+audio reuse)\n // Using __segment_ prefix to avoid collisions with user-defined sources\n for (let i = 0; i < segmentSourceUrls.length; i++) {\n sources[`__segment_${i}`] = segmentSourceUrls[i];\n }\n\n // Include any source refs used by global audio\n if (effieData.audio) {\n const audioSource = effieData.audio.source;\n if (typeof audioSource === \"string\" && audioSource.startsWith(\"#\")) {\n const ref = audioSource.slice(1);\n if (effieData.sources && ref in effieData.sources) {\n sources[ref] = effieData.sources[ref];\n }\n }\n }\n\n return {\n width: effieData.width,\n height: effieData.height,\n fps: effieData.fps,\n cover: effieData.cover,\n background: { type: \"color\", color: \"black\" }, // Not used - each segment has its own background\n segments: effieData.segments.map((seg, i) => ({\n duration: seg.duration,\n layers: [], // Layers not needed - video is pre-rendered\n transition: seg.transition,\n background: { type: \"video\" as const, source: `#__segment_${i}` },\n audio: { source: `#__segment_${i}` }, // FFmpeg extracts audio from mp4\n })),\n audio: effieData.audio, // Global audio is mixed during render\n sources,\n };\n}\n","import type { EffieData, EffieSources, EffieWebUrl } from \"./types\";\n\n/**\n * Source type for extraction\n */\nexport type EffieSourceType = \"image\" | \"video\" | \"audio\" | \"animation\";\n\n/**\n * A source with its type information\n */\nexport type EffieSourceWithType = {\n url: string;\n type: EffieSourceType;\n};\n\n/**\n * Options for extracting sources from EffieData\n */\nexport type ExtractSourcesOptions = {\n /** Include data URLs in the result (default: false) */\n includeDataUrls?: boolean;\n};\n\n/**\n * Extract all source URLs from an EffieData composition with their types.\n * Resolves #references and deduplicates results.\n *\n * @param effieData - The Effie composition\n * @param options - Extraction options\n * @returns Array of unique source URLs with their types\n *\n * @example\n * ```ts\n * const sources = extractEffieSourcesWithTypes(effieData);\n * // [{ url: \"https://cdn.example.com/bg.jpg\", type: \"image\" }, ...]\n * ```\n */\nexport function extractEffieSourcesWithTypes<U extends string = EffieWebUrl>(\n effieData: EffieData<EffieSources<U>, U>,\n options: ExtractSourcesOptions = {},\n): EffieSourceWithType[] {\n const { includeDataUrls = false } = options;\n // Map from URL to type (first type wins for deduplication)\n const sourceMap = new Map<string, EffieSourceType>();\n\n const addSource = (src: string, type: EffieSourceType) => {\n // Resolve #references\n if (src.startsWith(\"#\")) {\n const name = src.slice(1);\n if (effieData.sources?.[name]) {\n src = effieData.sources[name];\n } else {\n return; // Reference not found, skip\n }\n }\n\n // Filter data URLs unless explicitly asked to include\n if (!includeDataUrls && src.startsWith(\"data:\")) {\n return;\n }\n\n // Only add if not already present (first type wins)\n if (!sourceMap.has(src)) {\n sourceMap.set(src, type);\n }\n };\n\n // Cover image\n addSource(effieData.cover, \"image\");\n\n // Global background\n if (effieData.background.type === \"image\") {\n addSource(effieData.background.source, \"image\");\n } else if (effieData.background.type === \"video\") {\n addSource(effieData.background.source, \"video\");\n }\n\n // Global audio\n if (effieData.audio) {\n addSource(effieData.audio.source, \"audio\");\n }\n\n // Segments\n for (const segment of effieData.segments) {\n // Segment background\n if (segment.background) {\n if (segment.background.type === \"image\") {\n addSource(segment.background.source, \"image\");\n } else if (segment.background.type === \"video\") {\n addSource(segment.background.source, \"video\");\n }\n }\n // Segment audio\n if (segment.audio) {\n addSource(segment.audio.source, \"audio\");\n }\n // Layers\n for (const layer of segment.layers) {\n addSource(layer.source, layer.type);\n }\n }\n\n return Array.from(sourceMap.entries()).map(([url, type]) => ({ url, type }));\n}\n\n/**\n * Extract all source URLs from an EffieData composition.\n * Resolves #references and deduplicates results.\n *\n * @param effieData - The Effie composition\n * @param options - Extraction options\n * @returns Array of unique source URLs\n *\n * @example\n * ```ts\n * const sources = extractEffieSources(effieData);\n * // [\"https://cdn.example.com/bg.jpg\", \"https://api.example.com/annie/hero\", ...]\n * ```\n */\nexport function extractEffieSources<U extends string = EffieWebUrl>(\n effieData: EffieData<EffieSources<U>, U>,\n options: ExtractSourcesOptions = {},\n): string[] {\n return extractEffieSourcesWithTypes(effieData, options).map((s) => s.url);\n}\n","import type { EffieData, EffieSources } from \"./types\";\n\n/**\n * Options for effie Response generation\n */\nexport type EffieResponseOptions = {\n /** Additional headers to include in the response */\n headers?: HeadersInit;\n /** Cache-Control header value (default: \"public, max-age=3600\") */\n cacheControl?: string;\n};\n\n/**\n * Create an HTTP Response containing effie JSON data\n *\n * This is the most convenient way to serve an effie composition from a web server.\n * It handles JSON serialization, content-type, and caching headers automatically.\n *\n * @param data The effie data to serialize\n * @param options Configuration options\n * @returns Response with JSON body\n *\n * @example\n * ```ts\n * // In a route handler:\n * export async function loader({ params }: LoaderFunctionArgs) {\n * const effie = await renderEffie(effieId, props, { width, height });\n * return effieResponse(effie);\n * }\n * ```\n */\nexport function effieResponse<S extends EffieSources>(\n data: EffieData<S>,\n options: EffieResponseOptions = {},\n): Response {\n const { headers: extraHeaders, cacheControl = \"public, max-age=3600\" } =\n options;\n\n const headers = new Headers(extraHeaders);\n if (cacheControl) {\n headers.set(\"Cache-Control\", cacheControl);\n }\n\n return Response.json(data, { status: 200, headers });\n}\n","import { z } from \"zod\";\nimport type {\n EffieHttpUrl,\n EffieDataUrl,\n EffieWebUrl,\n EffieFileUrl,\n EffieSources,\n EffieData,\n EffieBackground,\n EffieAudio,\n EffieSegment,\n EffieLayer,\n EffieTransition,\n EffieEffect,\n EffieMotion,\n} from \"./types\";\n\n// URL schemas using z.custom to enforce exact type matching:\n\nexport const effieHttpUrlSchema = z.custom<EffieHttpUrl>(\n (val): val is EffieHttpUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") || val.startsWith(\"https://\")),\n { message: \"Must be an HTTP or HTTPS URL\" },\n);\n\nexport const effieDataUrlSchema = z.custom<EffieDataUrl>(\n (val): val is EffieDataUrl =>\n typeof val === \"string\" && val.startsWith(\"data:\"),\n { message: \"Must be a data URL\" },\n);\n\nexport const effieWebUrlSchema = z.custom<EffieWebUrl>(\n (val): val is EffieWebUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") ||\n val.startsWith(\"https://\") ||\n val.startsWith(\"data:\")),\n { message: \"Must be an HTTP, HTTPS, or data URL\" },\n) satisfies z.ZodType<EffieWebUrl>;\n\nexport const effieFileUrlSchema = z.custom<EffieFileUrl>(\n (val): val is EffieFileUrl =>\n typeof val === \"string\" && val.startsWith(\"file:\"),\n { message: \"Must be a file URL\" },\n) satisfies z.ZodType<EffieFileUrl>;\n\n// Source reference schema (matches #sourceName pattern)\nconst sourceRefSchema = z.custom<`#${string}`>(\n (val): val is `#${string}` => typeof val === \"string\" && val.startsWith(\"#\"),\n { message: \"Source reference must start with #\" },\n);\n\n// Transition schema\nexport const effieTransitionSchema = z.union([\n // Fade with easing\n z.strictObject({\n type: z.literal(\"fade\"),\n duration: z.number(),\n easing: z.enum([\"linear\", \"ease-in\", \"ease-out\"]).optional(),\n }),\n // Fade through color\n z.strictObject({\n type: z.literal(\"fade\"),\n duration: z.number(),\n through: z.enum([\"black\", \"white\", \"grays\"]),\n }),\n // Barn door wipes\n z.strictObject({\n type: z.literal(\"barn\"),\n duration: z.number(),\n orientation: z.enum([\"horizontal\", \"vertical\"]).optional(),\n mode: z.enum([\"open\", \"close\"]).optional(),\n }),\n // Circle wipes\n z.strictObject({\n type: z.literal(\"circle\"),\n duration: z.number(),\n mode: z.enum([\"open\", \"close\", \"crop\"]).optional(),\n }),\n // Directional transitions (wipe, slide, smooth, slice)\n z.strictObject({\n type: z.enum([\"wipe\", \"slide\", \"smooth\", \"slice\"]),\n duration: z.number(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]).optional(),\n }),\n // Zoom\n z.strictObject({\n type: z.literal(\"zoom\"),\n duration: z.number(),\n }),\n // Standalone transitions\n z.strictObject({\n type: z.enum([\"dissolve\", \"pixelize\", \"radial\"]),\n duration: z.number(),\n }),\n]) satisfies z.ZodType<EffieTransition>;\n\n// Effect schema\nexport const effieEffectSchema = z.union([\n z.strictObject({\n type: z.literal(\"fade-in\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"fade-out\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"saturate-in\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"saturate-out\"),\n duration: z.number(),\n start: z.number(),\n }),\n z.strictObject({\n type: z.literal(\"scroll\"),\n duration: z.number(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]),\n distance: z.number(),\n }),\n]) satisfies z.ZodType<EffieEffect>;\n\n// Motion schema\nexport const effieMotionSchema = z.union([\n z.strictObject({\n type: z.literal(\"bounce\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n amplitude: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"shake\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n intensity: z.number().optional(),\n frequency: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"slide\"),\n start: z.number().optional(),\n duration: z.number().optional(),\n direction: z.enum([\"left\", \"right\", \"up\", \"down\"]),\n distance: z.number().optional(),\n reverse: z.boolean().optional(),\n easing: z.enum([\"linear\", \"ease-in\", \"ease-out\", \"ease-in-out\"]).optional(),\n }),\n]) satisfies z.ZodType<EffieMotion>;\n\n// Schema factories for generic types.\n// Note: These return inferred Zod types. Type checking happens on the concrete\n// exported schemas below via explicit type annotations (which use `satisfies`\n// semantics - assignment to a typed variable fails if types don't match).\n\nexport function createEffieSourcesSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n return z.record(z.string(), urlSchema);\n}\n\nexport function createEffieSourceSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n return z.union([urlSchema, sourceRefSchema]);\n}\n\nexport function createEffieBackgroundSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.union([\n z.strictObject({\n type: z.literal(\"image\"),\n source: sourceSchema,\n }),\n z.strictObject({\n type: z.literal(\"video\"),\n source: sourceSchema,\n seek: z.number().optional(),\n }),\n z.strictObject({\n type: z.literal(\"color\"),\n color: z.string(),\n }),\n ]);\n}\n\nexport function createEffieAudioSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.strictObject({\n source: sourceSchema,\n volume: z.number().min(0).max(1).optional(),\n fadeIn: z.number().optional(),\n fadeOut: z.number().optional(),\n seek: z.number().optional(),\n });\n}\n\nexport function createEffieLayerSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourceSchema = createEffieSourceSchema(urlSchema);\n\n return z.strictObject({\n type: z.enum([\"image\", \"animation\"]),\n source: sourceSchema,\n delay: z.number().optional(),\n from: z.number().optional(),\n until: z.number().optional(),\n effects: z.array(effieEffectSchema).optional(),\n motion: effieMotionSchema.optional(),\n });\n}\n\nexport function createEffieSegmentSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const layerSchema = createEffieLayerSchema(urlSchema);\n const backgroundSchema = createEffieBackgroundSchema(urlSchema);\n const audioSchema = createEffieAudioSchema(urlSchema);\n\n return z.strictObject({\n duration: z.number(),\n layers: z.array(layerSchema),\n background: backgroundSchema.optional(),\n audio: audioSchema.optional(),\n transition: effieTransitionSchema.optional(),\n });\n}\n\n// Type for parsed data shape (matches Zod output, used for source ref collection)\ntype ParsedEffieData = {\n background: { source?: string } | { type: \"color\" };\n audio?: { source: string };\n segments: Array<{\n background?: { source?: string } | { type: \"color\" };\n audio?: { source: string };\n layers: Array<{ source: string }>;\n }>;\n};\n\n// Helper to collect all source references from parsed data\nfunction collectSourceRefs(data: ParsedEffieData): string[] {\n const refs: string[] = [];\n\n const addIfRef = (source: string) => {\n if (source.startsWith(\"#\")) {\n refs.push(source.slice(1));\n }\n };\n\n // Top-level background and audio\n if (\"source\" in data.background && data.background.source) {\n addIfRef(data.background.source);\n }\n if (data.audio) {\n addIfRef(data.audio.source);\n }\n\n // Segments\n for (const segment of data.segments) {\n if (\n segment.background &&\n \"source\" in segment.background &&\n segment.background.source\n ) {\n addIfRef(segment.background.source);\n }\n if (segment.audio) {\n addIfRef(segment.audio.source);\n }\n for (const layer of segment.layers) {\n addIfRef(layer.source);\n }\n }\n\n return refs;\n}\n\nexport function createEffieDataSchema<U extends string>(\n urlSchema: z.ZodType<U>,\n) {\n const sourcesSchema = createEffieSourcesSchema(urlSchema);\n const segmentSchema = createEffieSegmentSchema(urlSchema);\n const backgroundSchema = createEffieBackgroundSchema(urlSchema);\n const audioSchema = createEffieAudioSchema(urlSchema);\n\n return z\n .strictObject({\n width: z.number(),\n height: z.number(),\n fps: z.number(),\n cover: effieWebUrlSchema, // cover must always be a web URL\n sources: sourcesSchema.optional(),\n background: backgroundSchema,\n audio: audioSchema.optional(),\n segments: z.array(segmentSchema),\n })\n .superRefine((data, ctx) => {\n // Validate source references exist\n const definedSources = new Set(Object.keys(data.sources ?? {}));\n // Type assertion: Zod has validated the structure, but its inferred types\n // add spurious `| undefined` to required fields\n const referencedSources = collectSourceRefs(data as ParsedEffieData);\n\n for (const ref of referencedSources) {\n if (!definedSources.has(ref)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Source reference \"#${ref}\" not found in sources`,\n });\n }\n }\n\n // Validate transition durations: both current and previous segment must be\n // at least as long as the transition duration\n for (let i = 1; i < data.segments.length; i++) {\n const segment = data.segments[i];\n const prevSegment = data.segments[i - 1];\n\n if (segment.transition) {\n const transitionDuration = segment.transition.duration;\n\n if (segment.duration < transitionDuration) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Segment ${i} duration (${segment.duration}s) must be at least as long as its transition duration (${transitionDuration}s)`,\n path: [\"segments\", i, \"duration\"],\n });\n }\n\n if (prevSegment.duration < transitionDuration) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n message: `Segment ${i - 1} duration (${prevSegment.duration}s) must be at least as long as the following transition duration (${transitionDuration}s)`,\n path: [\"segments\", i - 1, \"duration\"],\n });\n }\n }\n }\n });\n}\n\n// Default schemas for web URLs (most common use case):\n\nexport const effieSourcesSchema: z.ZodType<EffieSources<EffieWebUrl>> =\n createEffieSourcesSchema(effieWebUrlSchema);\n\nexport const effieSourceSchema = createEffieSourceSchema(effieWebUrlSchema);\n\nexport const effieBackgroundSchema: z.ZodType<\n EffieBackground<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieBackgroundSchema(effieWebUrlSchema);\n\nexport const effieAudioSchema: z.ZodType<\n EffieAudio<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieAudioSchema(effieWebUrlSchema);\n\nexport const effieLayerSchema: z.ZodType<\n EffieLayer<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieLayerSchema(effieWebUrlSchema);\n\nexport const effieSegmentSchema: z.ZodType<\n EffieSegment<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieSegmentSchema(effieWebUrlSchema);\n\nexport const effieDataSchema: z.ZodType<\n EffieData<EffieSources<EffieWebUrl>, EffieWebUrl>\n> = createEffieDataSchema(effieWebUrlSchema);\n\n// Schema for data that allows file URLs (for trusted operations)\ntype WebOrFileUrl = EffieWebUrl | EffieFileUrl;\nconst webOrFileUrlSchema = z.custom<WebOrFileUrl>(\n (val): val is WebOrFileUrl =>\n typeof val === \"string\" &&\n (val.startsWith(\"http://\") ||\n val.startsWith(\"https://\") ||\n val.startsWith(\"data:\") ||\n val.startsWith(\"file:\")),\n { message: \"Must be an HTTP, HTTPS, data, or file URL\" },\n);\n\nexport const effieDataWithFilesSchema: z.ZodType<\n EffieData<EffieSources<WebOrFileUrl>, WebOrFileUrl>\n> = createEffieDataSchema(webOrFileUrlSchema);\n"],"mappings":"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","names":["effieData","effieData"]}
|