@editframe/vite-plugin 0.47.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,148 @@
1
+ # Editframe SDK License Agreement
2
+
3
+ **Effective Date:** January 12, 2026 **Version:** 2.0
4
+
5
+ This License Agreement ("License") governs your use of the Editframe SDK. By downloading, accessing, or using the SDK, you agree to these terms.
6
+
7
+ ---
8
+
9
+ ## 1. Definitions
10
+
11
+ **"Total Employees"** — All full-time employees, part-time employees, and contractor equivalents across your Organization and all affiliated entities under common control. Contractors are counted proportionally by time worked.
12
+
13
+ **"Organization"** — You, your company, and all affiliates, subsidiaries, or related entities under common control.
14
+
15
+ **"Client-Side SDK"** — The source-available browser-based video rendering components, including the custom video tag for local file playback.
16
+
17
+ **"Server-Side Rendering"** — Hosted cloud service for parallel rendering at scale, supporting simultaneous rendering of large volumes of videos including longer and more complex ones.
18
+
19
+ **"Premium Player"** — Cloud-based CDN streaming service with API-authenticated streaming capabilities, optimized for editing workflows.
20
+
21
+ **"Cloud Services"** — Server-Side Rendering and Premium Player collectively.
22
+
23
+ **"Commercial Use"** — Any use in connection with business operations, revenue-generating activities, or professional services, including internal tools, production environments, and client deliverables.
24
+
25
+ **"Evaluation Use"** — Good-faith testing and proof-of-concept development, limited to 30 days. Excludes production deployment and ongoing business use.
26
+
27
+ ---
28
+
29
+ ## 2. License Grant
30
+
31
+ ### 2.1 Free Tier (≤3 Employees)
32
+
33
+ A limited, non-exclusive, non-transferable, revocable license to use the Client-Side SDK.
34
+
35
+ **Eligible:**
36
+
37
+ - Organizations with ≤3 total employees (Commercial Use permitted)
38
+ - Evaluation Use (any size, 30 days, non-production)
39
+ - Registered non-profits (any size)
40
+ - Accredited educational institutions
41
+ - Personal non-commercial projects
42
+
43
+ **Permitted:**
44
+
45
+ - Install and use the Client-Side SDK
46
+ - Use the custom video tag for local file playback (no API key required)
47
+ - Create and distribute video outputs for personal or Commercial Use
48
+
49
+ **Not included:** Cloud Services. Cloud Services require a Cloud Tier subscription regardless of company size.
50
+
51
+ ### 2.2 Team Tier (4–10 Employees)
52
+
53
+ Includes all Free Tier rights. Full Client-Side SDK use for any business purpose including production. Does not include Cloud Services. See [editframe.com/pricing](https://editframe.com/pricing) for pricing.
54
+
55
+ ### 2.3 Cloud Tier (11–20 Employees, or Any Size Requiring Cloud)
56
+
57
+ Required for organizations with 11–20 employees, or any organization using Cloud Services.
58
+
59
+ Includes all Team Tier rights, plus Server-Side Rendering and Premium Player via API. Usage-based billing applies in addition to base subscription. See [editframe.com/pricing](https://editframe.com/pricing) for pricing.
60
+
61
+ ### 2.4 Enterprise (21+ Employees)
62
+
63
+ Contact [hello@editframe.com](mailto:hello@editframe.com). Includes all Cloud Tier features plus priority support and custom SLAs.
64
+
65
+ ---
66
+
67
+ ## 3. Restrictions
68
+
69
+ ### 3.1 Prohibited
70
+
71
+ - Do not offer the Client-Side SDK or CLI itself as a managed rendering API or infrastructure product to third parties
72
+ - Do not fork, redistribute, or sublicense the Client-Side SDK or CLI under different terms
73
+ - Do not use the SDK above your tier threshold without upgrading
74
+ - Do not share credentials or API keys across separate organizations
75
+ - Do not implement workarounds to avoid usage-based billing
76
+ - Do not reverse engineer, decompile, or extract proprietary algorithms from Server-Side Rendering or Premium Player
77
+ - Do not access Cloud Service APIs other than through official client libraries
78
+ - Do not disable, circumvent, or tamper with telemetry
79
+ - Do not remove or alter copyright notices or attribution
80
+ - Do not use the SDK for unlawful purposes or in violation of export control regulations
81
+
82
+ ### 3.2 Permitted
83
+
84
+ - Build any product that creates, processes, or delivers video — editors, workflows, motion design tools, content automation, and more
85
+ - Integrate the Client-Side SDK into platforms, coding environments, vibe coding tools, and AI agents (end users are individually responsible for compliance)
86
+ - Use the Client-Side SDK in CI/CD pipelines and development environments, provided you are not using it to render production video at scale
87
+
88
+ ---
89
+
90
+ ## 4. Intellectual Property
91
+
92
+ Editframe, Inc. retains all rights to the SDK. This License does not transfer ownership. You retain all rights to video outputs you create ("Your Content"). Feedback may be used by us without obligation.
93
+
94
+ ---
95
+
96
+ ## 5. Telemetry
97
+
98
+ The SDK includes always-on telemetry collecting render counts, durations, IP addresses, domains, and feature usage. Telemetry cannot be disabled. Required for usage-based billing and license compliance. No video content is collected. See [editframe.com/privacy](https://editframe.com/privacy).
99
+
100
+ High Client-Side rendering volume does not trigger payment requirements — eligibility is determined by company size only.
101
+
102
+ ---
103
+
104
+ ## 6. Support
105
+
106
+ - **Free:** Community support
107
+ - **Team/Cloud:** Email and Slack, 48-hour response
108
+ - **Enterprise:** Dedicated support, custom SLAs
109
+
110
+ ---
111
+
112
+ ## 7. Warranties
113
+
114
+ THE SDK IS PROVIDED "AS IS" WITHOUT WARRANTIES OF ANY KIND. WE DO NOT WARRANT THAT THE SDK WILL BE ERROR-FREE, SECURE, OR UNINTERRUPTED. YOU ASSUME ALL RISKS.
115
+
116
+ ---
117
+
118
+ ## 8. Limitation of Liability
119
+
120
+ WE SHALL NOT BE LIABLE FOR INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, OR PUNITIVE DAMAGES. TOTAL LIABILITY SHALL NOT EXCEED AMOUNTS PAID IN THE 12 MONTHS PRECEDING THE CLAIM, OR $100 USD, WHICHEVER IS GREATER.
121
+
122
+ ---
123
+
124
+ ## 9. Termination
125
+
126
+ This License is effective upon first use. We may terminate immediately for breach, failure to maintain required subscription tier, or fraudulent conduct (10 days' notice where feasible). Upon termination, all rights cease and you must delete all SDK copies.
127
+
128
+ ---
129
+
130
+ ## 10. Compliance
131
+
132
+ Self-report your employee count accurately. Violations may result in termination, back-payment of owed fees, liquidated damages (3× unpaid fees), and legal action. Voluntary disclosure may result in waived penalties.
133
+
134
+ ---
135
+
136
+ ## 11. General
137
+
138
+ - **Governing Law:** Delaware
139
+ - **Jurisdiction:** New York County, NY
140
+ - **Export Controls:** You must comply with U.S. Export Administration Regulations
141
+ - **Assignment:** You may not assign this License without written consent
142
+ - **Entire Agreement:** This License, Terms of Service, and Privacy Policy constitute the full agreement
143
+
144
+ ---
145
+
146
+ [hello@editframe.com](mailto:hello@editframe.com) · editframe.com
147
+
148
+ **By using the SDK, you agree to these terms.**
package/LICENSE.md ADDED
@@ -0,0 +1,58 @@
1
+ # Editframe SDK License
2
+
3
+ The Editframe SDK is source-available and free for individuals and small teams, including for commercial use. We've kept the bar low intentionally — if you're building something, you should be able to just use it.
4
+
5
+ - [Free Tier](#free-tier)
6
+ - [Paid Tiers](#paid-tiers)
7
+
8
+ ---
9
+
10
+ ## Free Tier
11
+
12
+ Copyright © 2026 [Editframe](https://editframe.com)
13
+
14
+ ### Who Qualifies
15
+
16
+ - Individuals and freelancers
17
+ - Organizations with 3 or fewer total employees
18
+ - Non-profits and not-for-profit organizations (any size)
19
+ - Accredited educational institutions
20
+ - Organizations evaluating Editframe in good faith, prior to commercial deployment (30 days)
21
+
22
+ ### What You Can Build
23
+
24
+ Use and modify the SDK to build any product that creates, processes, or delivers video — editors, workflows, motion design tools, content automation, and more. Platforms, coding environments, vibe coding tools, and AI agents may freely integrate the SDK. End users are each responsible for their own license compliance.
25
+
26
+ ### What Is Not Permitted
27
+
28
+ You may not offer the Client-Side SDK or CLI itself as a managed rendering API or infrastructure product to third parties. You may not sell, sublicense, or redistribute the SDK or modifications to it as a standalone product.
29
+
30
+ ### Warranty
31
+
32
+ The SDK is provided as-is without warranty of any kind. See the [Full License Agreement](./LICENSE-FULL.md) for complete terms.
33
+
34
+ ---
35
+
36
+ ## Paid Tiers
37
+
38
+ Organizations outside the Free Tier must subscribe to a paid plan.
39
+
40
+ | Tier | Employees |
41
+ | :---- | :---- |
42
+ | Team | 4–10 |
43
+ | Cloud | 11–20, or any size needing Cloud Rendering & Player |
44
+ | Enterprise | 21+ |
45
+
46
+ All paid tiers include full SDK rights.
47
+
48
+ Cloud Rendering & Player — parallel rendering and CDN streaming optimized for editing workflows — requires a Cloud Tier subscription regardless of company size.
49
+
50
+ [View pricing →](https://editframe.com/pricing) · Enterprise: [hello@editframe.com](mailto:hello@editframe.com)
51
+
52
+ ---
53
+
54
+ Unsure which tier applies? See the [FAQ](https://editframe.com/faq) or reach out at [hello@editframe.com](mailto:hello@editframe.com).
55
+
56
+ [Full License Agreement](./LICENSE-FULL.md) · [Terms of Service](https://editframe.com/terms)
57
+
58
+ *© 2026 Editframe, Inc.*
@@ -2,7 +2,7 @@
2
2
  const forbidRelativePaths = (req) => {
3
3
  if (req.url?.includes("..")) throw new Error("Relative paths are forbidden");
4
4
  };
5
-
6
5
  //#endregion
7
6
  export { forbidRelativePaths };
7
+
8
8
  //# sourceMappingURL=forbidRelativePaths.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"forbidRelativePaths.js","names":[],"sources":["../src/forbidRelativePaths.ts"],"sourcesContent":["import type { IncomingMessage } from \"connect\";\n\nexport const forbidRelativePaths = (req: IncomingMessage) => {\n if (req.url?.includes(\"..\")) {\n throw new Error(\"Relative paths are forbidden\");\n }\n};\n"],"mappings":";AAEA,MAAa,uBAAuB,QAAyB;AAC3D,KAAI,IAAI,KAAK,SAAS,KAAK,CACzB,OAAM,IAAI,MAAM,+BAA+B"}
1
+ {"version":3,"file":"forbidRelativePaths.js","names":[],"sources":["../src/forbidRelativePaths.ts"],"mappings":";AAEA,MAAa,uBAAuB,QAAyB;AAC3D,KAAI,IAAI,KAAK,SAAS,KAAK,CACzB,OAAM,IAAI,MAAM,+BAA+B"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import * as vite0 from "vite";
1
+ import * as _$vite from "vite";
2
2
 
3
3
  //#region src/index.d.ts
4
4
  interface VitePluginEditframeOptions {
@@ -7,13 +7,13 @@ interface VitePluginEditframeOptions {
7
7
  }
8
8
  declare const vitePluginEditframe: (options: VitePluginEditframeOptions) => {
9
9
  name: string;
10
- configResolved(this: vite0.MinimalPluginContextWithoutEnvironment, resolvedConfig: {
10
+ configResolved(this: _$vite.MinimalPluginContextWithoutEnvironment, resolvedConfig: {
11
11
  define?: Record<string, string>;
12
12
  }): void;
13
- transformIndexHtml(this: vite0.MinimalPluginContextWithoutEnvironment, html: string, ctx: {
13
+ transformIndexHtml(this: _$vite.MinimalPluginContextWithoutEnvironment, html: string, ctx: {
14
14
  server?: unknown;
15
15
  }): string;
16
- configureServer(this: vite0.MinimalPluginContextWithoutEnvironment, server: vite0.ViteDevServer): void;
16
+ configureServer(this: _$vite.MinimalPluginContextWithoutEnvironment, server: _$vite.ViteDevServer): void;
17
17
  };
18
18
  //#endregion
19
19
  export { vitePluginEditframe };
package/dist/index.js CHANGED
@@ -5,7 +5,6 @@ import { createAssetsApiMiddleware, createLocalFilesApiMiddleware, handleClearCa
5
5
  import { Client, createURLToken } from "@editframe/api";
6
6
  import { cacheImage, findOrCreateCaptions, generateScrubTrack, generateTrack, generateTrackFragmentIndex, md5FilePath } from "@editframe/assets";
7
7
  import debug from "debug";
8
-
9
8
  //#region src/index.ts
10
9
  const getEditframeClient = () => {
11
10
  const token = process.env.EF_TOKEN;
@@ -110,7 +109,7 @@ const vitePluginEditframe = (options) => {
110
109
  }
111
110
  };
112
111
  };
113
-
114
112
  //#endregion
115
113
  export { vitePluginEditframe };
114
+
116
115
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["devServerPort: number | undefined"],"sources":["../src/index.ts"],"sourcesContent":["import { Client, createURLToken } from \"@editframe/api\";\nimport {\n cacheImage,\n findOrCreateCaptions,\n generateTrack,\n generateScrubTrack,\n generateTrackFragmentIndex,\n md5FilePath,\n} from \"@editframe/assets\";\nimport debug from \"debug\";\nimport type { Plugin } from \"vite\";\nimport { version } from \"./version.js\";\n\nimport { createJitTranscodeMiddleware } from \"./jitTranscodeMiddleware.js\";\nimport {\n createAssetsApiMiddleware,\n createLocalFilesApiMiddleware,\n handleClearCache,\n} from \"./middleware.js\";\nimport { forbidRelativePaths } from \"./forbidRelativePaths.js\";\n\ninterface VitePluginEditframeOptions {\n root: string;\n cacheRoot: string;\n}\n\nconst getEditframeClient = () => {\n const token = process.env.EF_TOKEN;\n const efHost = process.env.EF_HOST;\n if (!token) {\n throw new Error(\"EF_TOKEN environment variable must be set\");\n }\n return new Client(token, efHost);\n};\n\nexport const vitePluginEditframe = (options: VitePluginEditframeOptions) => {\n let devServerPort: number | undefined;\n\n return {\n name: \"vite-plugin-editframe\",\n\n configResolved(resolvedConfig: { define?: Record<string, string> }) {\n resolvedConfig.define ??= {};\n resolvedConfig.define[\"__EF_VERSION__\"] ??= JSON.stringify(version);\n },\n\n transformIndexHtml(html: string, ctx: { server?: unknown }) {\n if (!ctx.server) return html;\n const script = `<script>window.__EDITFRAME__ = Object.assign({}, window.__EDITFRAME__, { apiHost: \"http://localhost:${devServerPort}\" });</script>`;\n return html.replace(/(<head[^>]*>)/i, `$1${script}`);\n },\n\n configureServer(server) {\n server.httpServer?.on(\"listening\", () => {\n const addr = server.httpServer?.address();\n if (addr && typeof addr === \"object\") {\n devServerPort = addr.port;\n }\n });\n server.middlewares.use(\n createJitTranscodeMiddleware(\n { ...options, handleRemoteUrls: true },\n { generateTrack, generateScrubTrack, generateTrackFragmentIndex },\n ),\n );\n\n server.middlewares.use(\n createAssetsApiMiddleware(options, {\n cacheImage,\n findOrCreateCaptions,\n }),\n );\n\n server.middlewares.use(\n createLocalFilesApiMiddleware(options, {\n generateTrack,\n generateScrubTrack,\n generateTrackFragmentIndex,\n md5FilePath,\n }),\n );\n\n server.middlewares.use(async (req, res, next) => {\n const log = debug(\"ef:vite-plugin\");\n if (req.url?.startsWith(\"/@ef\")) {\n forbidRelativePaths(req);\n } else {\n return next();\n }\n\n log(`Handling ${req.url} at ${new Date().toISOString()}`);\n\n const cacheRoot = options.cacheRoot.replace(\"dist/\", \"src/\");\n const efPrefix = req.url.split(\"/\")[1];\n\n switch (efPrefix) {\n case \"@ef-clear-cache\": {\n await handleClearCache(req, res, cacheRoot);\n break;\n }\n case \"@ef-sign-url\": {\n if (req.method !== \"POST\") {\n res.writeHead(405, { Allow: \"POST\" });\n res.end();\n break;\n }\n\n log(\"Signing URL token\");\n\n let body = \"\";\n req.on(\"data\", (chunk) => {\n body += chunk.toString();\n });\n\n req.on(\"end\", async () => {\n try {\n const payload = JSON.parse(body);\n log(\"Token signing request payload:\", payload);\n\n const { url, params } = payload;\n if (!url) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"URL is required\" }));\n return;\n }\n\n const client = getEditframeClient();\n\n let fullUrl = url;\n if (params) {\n const urlObj = new URL(url);\n Object.entries(params).forEach(([key, value]) => {\n urlObj.searchParams.set(key, String(value));\n });\n fullUrl = urlObj.toString();\n }\n\n log(\"Creating token for full URL:\", fullUrl);\n const token = await createURLToken(client, fullUrl);\n\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ token }));\n } catch (error) {\n log(`Error signing URL token: ${error}`);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Failed to sign URL token\" }));\n }\n });\n\n break;\n }\n default:\n log(`Unknown asset type ${efPrefix}`);\n break;\n }\n });\n },\n } satisfies Plugin;\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"mappings":"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"}
@@ -3,7 +3,6 @@ import debug from "debug";
3
3
  import { createReadStream, statSync } from "node:fs";
4
4
  import path from "node:path";
5
5
  import mime from "mime";
6
-
7
6
  //#region src/jitTranscodeMiddleware.ts
8
7
  /**
9
8
  * Stream a specific byte range from a file.
@@ -302,9 +301,10 @@ function createJitTranscodeMiddleware(options, assetFunctions) {
302
301
  res.end(JSON.stringify({ error: `Track ${trackId} not found (valid tracks: ${validTracks})` }));
303
302
  return;
304
303
  }
304
+ const resolvedInitContentType = trackTaskResult.cachePath.endsWith(".webm") ? "video/webm" : contentType;
305
305
  const { offset, size } = track.initSegment;
306
306
  log(`Init segment: offset=${offset}, size=${size}`);
307
- sendByteRange(res, trackTaskResult.cachePath, offset, size, contentType);
307
+ sendByteRange(res, trackTaskResult.cachePath, offset, size, resolvedInitContentType);
308
308
  } catch (error) {
309
309
  log(`Error serving init segment: ${error}`);
310
310
  if (error.code === "ENOENT") {
@@ -351,7 +351,7 @@ function createJitTranscodeMiddleware(options, assetFunctions) {
351
351
  }));
352
352
  return;
353
353
  }
354
- const contentType = extension === "m4s" ? "video/iso.segment" : "video/mp4";
354
+ const contentType = trackTaskResult.cachePath.endsWith(".webm") ? "video/webm" : extension === "m4s" ? "video/iso.segment" : "video/mp4";
355
355
  if (includeInit) {
356
356
  const initSegment = track.initSegment;
357
357
  log(`Media segment ${segmentId}.mp4: init(offset=${initSegment.offset}, size=${initSegment.size}) + segment(offset=${segment.offset}, size=${segment.size})`);
@@ -394,7 +394,7 @@ function createJitTranscodeMiddleware(options, assetFunctions) {
394
394
  }
395
395
  };
396
396
  }
397
-
398
397
  //#endregion
399
398
  export { createJitTranscodeMiddleware };
399
+
400
400
  //# sourceMappingURL=jitTranscodeMiddleware.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jitTranscodeMiddleware.js","names":["fragmentIndex: Record<number, TrackFragmentIndex>"],"sources":["../src/jitTranscodeMiddleware.ts"],"sourcesContent":["import { createReadStream, statSync } from \"node:fs\";\nimport type { ServerResponse } from \"node:http\";\nimport path from \"node:path\";\n\nimport type { IncomingMessage, NextFunction } from \"connect\";\nimport debug from \"debug\";\nimport mime from \"mime\";\nimport type { TrackFragmentIndex } from \"@editframe/assets\";\n\nimport { forbidRelativePaths } from \"./forbidRelativePaths.js\";\n\nexport type { TrackFragmentIndex };\n\n/**\n * Asset functions required by the JIT middleware.\n * These are injected to support both package imports and direct imports.\n */\nexport interface AssetFunctions {\n generateTrack: (\n cacheRoot: string,\n absolutePath: string,\n trackUrl: string,\n ) => Promise<{ cachePath: string }>;\n generateScrubTrack: (cacheRoot: string, absolutePath: string) => Promise<{ cachePath: string }>;\n generateTrackFragmentIndex: (\n cacheRoot: string,\n absolutePath: string,\n ) => Promise<{ cachePath: string }>;\n}\n\nexport interface JitMiddlewareOptions {\n root: string;\n cacheRoot: string;\n /**\n * When true, remote URLs (http/https) are handled locally via ffprobe/ffmpeg\n * rather than passed to a downstream proxy (e.g. recordReplayProxyPlugin).\n * Set to true in dev-projects; leave false (default) in test environments\n * that use recordReplayProxyPlugin to proxy remote URLs to the cloud API.\n */\n handleRemoteUrls?: boolean;\n}\n\n/**\n * Stream a specific byte range from a file.\n * This is used for JIT segment serving where the server extracts the correct bytes.\n */\nexport function sendByteRange(\n res: ServerResponse,\n filePath: string,\n offset: number,\n size: number,\n contentType?: string,\n) {\n const log = debug(\"ef:sendByteRange\");\n const stats = statSync(filePath);\n const end = offset + size - 1;\n\n if (end >= stats.size) {\n log(`Requested range ${offset}-${end} exceeds file size ${stats.size}`);\n res.writeHead(416, { \"Content-Range\": `bytes */${stats.size}` });\n res.end();\n return;\n }\n\n log(`Streaming bytes ${offset}-${end} (${size} bytes) from ${filePath}`);\n\n res.writeHead(200, {\n \"Content-Type\": contentType || mime.getType(filePath) || \"video/mp4\",\n \"Content-Length\": size,\n \"Cache-Control\": \"public, max-age=3600\",\n });\n\n const readStream = createReadStream(filePath, { start: offset, end });\n readStream.pipe(res);\n}\n\n/**\n * Stream multiple byte ranges from a file concatenated together.\n * Used for creating playable .mp4 files by combining init segment + media segment.\n */\nexport function sendMultipleByteRanges(\n res: ServerResponse,\n filePath: string,\n ranges: Array<{ offset: number; size: number }>,\n contentType?: string,\n) {\n const log = debug(\"ef:sendMultipleByteRanges\");\n const stats = statSync(filePath);\n\n // Validate all ranges\n for (const range of ranges) {\n const end = range.offset + range.size - 1;\n if (end >= stats.size) {\n log(`Requested range ${range.offset}-${end} exceeds file size ${stats.size}`);\n res.writeHead(416, { \"Content-Range\": `bytes */${stats.size}` });\n res.end();\n return;\n }\n }\n\n const totalSize = ranges.reduce((sum, r) => sum + r.size, 0);\n log(`Streaming ${ranges.length} ranges (${totalSize} total bytes) from ${filePath}`);\n\n res.writeHead(200, {\n \"Content-Type\": contentType || \"video/mp4\",\n \"Content-Length\": totalSize,\n \"Cache-Control\": \"public, max-age=3600\",\n });\n\n // Stream ranges sequentially\n let rangeIndex = 0;\n\n const streamNextRange = () => {\n if (rangeIndex >= ranges.length) {\n res.end();\n return;\n }\n\n const range = ranges[rangeIndex]!;\n const end = range.offset + range.size - 1;\n const readStream = createReadStream(filePath, { start: range.offset, end });\n\n readStream.on(\"end\", () => {\n rangeIndex++;\n streamNextRange();\n });\n\n readStream.on(\"error\", (err) => {\n log(`Error streaming range ${rangeIndex}: ${err}`);\n res.destroy();\n });\n\n readStream.pipe(res, { end: false });\n };\n\n streamNextRange();\n}\n\n/**\n * Check if a hostname refers to the local vite server.\n * Handles various local hostname patterns including worktree domains.\n */\nexport function isLocalHost(hostname: string): boolean {\n const localPatterns = [\n \"localhost\",\n \"127.0.0.1\",\n \"0.0.0.0\",\n \".localhost\", // Matches *.localhost (worktree domains like main.localhost)\n ];\n\n const lowerHost = hostname.toLowerCase();\n return localPatterns.some((pattern) =>\n pattern.startsWith(\".\")\n ? lowerHost.endsWith(pattern) || lowerHost === pattern.slice(1)\n : lowerHost === pattern || lowerHost.startsWith(pattern + \":\"),\n );\n}\n\n/**\n * Resolve a URL to either a remote URL (for ffprobe) or a local file path.\n *\n * - Remote URLs (different host): passed directly to ffprobe (it supports http/https)\n * - Local URLs (localhost, *.localhost): resolved to local file path\n *\n * @param urlParam - The URL from the query parameter\n * @param root - The vite plugin root directory\n * @returns The path/URL to pass to ffprobe\n */\nexport function resolveMediaPath(urlParam: string, root: string): string {\n try {\n const url = new URL(urlParam);\n const hostname = url.hostname;\n\n // If NOT a local URL, pass directly to ffprobe - it supports http/https URLs\n if (!isLocalHost(hostname)) {\n return urlParam;\n }\n\n // Local URL - resolve to file path\n let filePath = decodeURIComponent(url.pathname);\n\n // Remove leading slash for path.join\n if (filePath.startsWith(\"/\")) {\n filePath = filePath.slice(1);\n }\n\n // The root is already dev-projects/src, so if the URL path starts with \"src/\",\n // we should remove it to avoid duplication (src/src/assets -> src/assets)\n if (filePath.startsWith(\"src/\")) {\n filePath = filePath.slice(4); // Remove \"src/\"\n }\n\n return path.join(root, filePath);\n } catch {\n // If not a valid URL, treat as relative path\n let filePath = urlParam;\n if (filePath.startsWith(\"src/\")) {\n filePath = filePath.slice(4);\n }\n return path.join(root, filePath);\n }\n}\n\n/**\n * Convert fragment index segments to millisecond durations array.\n */\nexport function getSegmentDurationsMs(track: TrackFragmentIndex): number[] {\n return track.segments.map((segment) => (segment.duration / track.timescale) * 1000);\n}\n\n/**\n * Generate a JIT manifest for a local file.\n * Uses actual fragment index data for accurate segment information.\n */\nexport async function generateLocalJitManifest(\n absolutePath: string,\n sourceUrl: string,\n baseUrl: string,\n cacheRoot: string,\n assetFunctions: AssetFunctions,\n) {\n const log = debug(\"ef:generateLocalJitManifest\");\n\n // Generate the fragment index (this also ensures tracks are generated)\n log(`Generating fragment index for ${absolutePath}`);\n const fragmentIndexResult = await assetFunctions.generateTrackFragmentIndex(\n cacheRoot,\n absolutePath,\n );\n const fragmentIndex: Record<number, TrackFragmentIndex> = JSON.parse(\n await import(\"node:fs/promises\").then((fs) =>\n fs.readFile(fragmentIndexResult.cachePath, \"utf-8\"),\n ),\n );\n\n // Find tracks by type rather than by hardcoded index (audio-only files have audio at index 1)\n const videoTrack = Object.values(fragmentIndex).find((t) => t.type === \"video\");\n const audioTrack = Object.values(fragmentIndex).find((t) => t.type === \"audio\");\n const scrubTrack = fragmentIndex[-1];\n\n const hasVideo = videoTrack?.type === \"video\";\n const hasAudio = audioTrack?.type === \"audio\";\n\n // Get duration from the longest track\n let durationMs = 0;\n if (hasVideo && videoTrack) {\n durationMs = Math.max(durationMs, (videoTrack.duration / videoTrack.timescale) * 1000);\n }\n if (hasAudio && audioTrack) {\n durationMs = Math.max(durationMs, (audioTrack.duration / audioTrack.timescale) * 1000);\n }\n const durationSeconds = durationMs / 1000;\n\n // Get video dimensions from track\n const width = hasVideo && videoTrack && \"width\" in videoTrack ? videoTrack.width : 1920;\n const height = hasVideo && videoTrack && \"height\" in videoTrack ? videoTrack.height : 1080;\n const codec = hasVideo && videoTrack ? videoTrack.codec : \"avc1.640029\";\n\n // Get actual segment durations from fragment index\n const videoSegmentDurationsMs = hasVideo && videoTrack ? getSegmentDurationsMs(videoTrack) : [];\n const scrubSegmentDurationsMs = scrubTrack ? getSegmentDurationsMs(scrubTrack) : [];\n const audioSegmentDurationsMs = hasAudio && audioTrack ? getSegmentDurationsMs(audioTrack) : [];\n\n // Average segment duration for backward compatibility\n const avgVideoSegmentDurationMs =\n videoSegmentDurationsMs.length > 0\n ? videoSegmentDurationsMs.reduce((a, b) => a + b, 0) / videoSegmentDurationsMs.length\n : 2000;\n const avgScrubSegmentDurationMs =\n scrubSegmentDurationsMs.length > 0\n ? scrubSegmentDurationsMs.reduce((a, b) => a + b, 0) / scrubSegmentDurationsMs.length\n : 30000;\n const avgAudioSegmentDurationMs =\n audioSegmentDurationsMs.length > 0\n ? audioSegmentDurationsMs.reduce((a, b) => a + b, 0) / audioSegmentDurationsMs.length\n : 2000;\n\n log(\n `Video: ${videoSegmentDurationsMs.length} segments, Audio: ${audioSegmentDurationsMs.length} segments, Scrub: ${scrubSegmentDurationsMs.length} segments`,\n );\n\n // Construct manifest matching ManifestResponse format\n const manifest = {\n version: \"1.0\",\n type: \"com.editframe/local-jit-manifest\",\n sourceUrl: sourceUrl,\n duration: durationSeconds,\n durationMs: durationMs,\n baseUrl: baseUrl,\n\n videoRenditions: hasVideo\n ? [\n {\n id: \"high\",\n width: width,\n height: height,\n bitrate: 5000000,\n codec: codec,\n container: \"video/mp4\",\n mimeType: `video/mp4; codecs=\"${codec}\"`,\n segmentDuration: avgVideoSegmentDurationMs / 1000,\n segmentDurationMs: avgVideoSegmentDurationMs,\n segmentDurationsMs: videoSegmentDurationsMs,\n startTimeOffsetMs: videoTrack!.startTimeOffsetMs,\n frameRate: 30,\n profile: \"High\",\n level: \"4.1\",\n },\n ...(scrubTrack\n ? [\n {\n id: \"scrub\",\n width: 320,\n height: Math.round((320 * (height ?? 1080)) / (width ?? 1920)),\n bitrate: 100000,\n codec: scrubTrack.codec,\n container: \"video/mp4\",\n mimeType: `video/mp4; codecs=\"${scrubTrack.codec}\"`,\n segmentDuration: avgScrubSegmentDurationMs / 1000,\n segmentDurationMs: avgScrubSegmentDurationMs,\n segmentDurationsMs: scrubSegmentDurationsMs,\n startTimeOffsetMs: scrubTrack.startTimeOffsetMs,\n frameRate: 15,\n profile: \"High\",\n level: \"4.1\",\n },\n ]\n : []),\n ]\n : [],\n\n audioRenditions:\n hasAudio && audioTrack\n ? [\n {\n id: \"audio\",\n channels: \"channel_count\" in audioTrack ? audioTrack.channel_count : 2,\n sampleRate: \"sample_rate\" in audioTrack ? audioTrack.sample_rate : 48000,\n bitrate: 128000,\n codec: audioTrack.codec,\n container: \"audio/mp4\",\n mimeType: `audio/mp4; codecs=\"${audioTrack.codec}\"`,\n segmentDuration: avgAudioSegmentDurationMs / 1000,\n segmentDurationMs: avgAudioSegmentDurationMs,\n segmentDurationsMs: audioSegmentDurationsMs,\n language: \"en\",\n },\n ]\n : [],\n\n endpoints: {\n initSegment: `${baseUrl}/api/v1/transcode/{rendition}/init.m4s?url=${encodeURIComponent(sourceUrl)}`,\n mediaSegment: `${baseUrl}/api/v1/transcode/{rendition}/{segmentId}.m4s?url=${encodeURIComponent(sourceUrl)}`,\n },\n\n jitInfo: {\n parallelTranscodingSupported: true,\n expectedTranscodeLatency: 100, // Local is fast\n segmentCount: videoSegmentDurationsMs.length,\n scrubSegmentCount: scrubSegmentDurationsMs.length,\n },\n };\n\n return manifest;\n}\n\n/**\n * Create the JIT transcode middleware for /api/v1/transcode/* routes.\n *\n * @param options - The middleware options (root, cacheRoot)\n * @param assetFunctions - The asset functions to use (allows dependency injection)\n * @returns Express-compatible middleware function\n */\nexport function createJitTranscodeMiddleware(\n options: JitMiddlewareOptions,\n assetFunctions: AssetFunctions,\n) {\n return async (req: IncomingMessage, res: ServerResponse, next: NextFunction) => {\n const log = debug(\"ef:vite-plugin:jit\");\n\n if (!req.url?.startsWith(\"/api/v1/transcode/\")) {\n return next();\n }\n\n forbidRelativePaths(req);\n log(`Handling JIT transcode request: ${req.url}`);\n\n const url = new URL(req.url, `http://${req.headers.host}`);\n const sourceUrl = url.searchParams.get(\"url\");\n\n if (!sourceUrl) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"url parameter is required\" }));\n return;\n }\n\n // Resolve URL to either local file path or keep as remote URL (ffprobe supports both)\n const mediaPath = resolveMediaPath(sourceUrl, options.root);\n\n // If the source is a remote URL and handleRemoteUrls is not enabled, let the\n // next middleware handle it (e.g. recordReplayProxyPlugin in test environments).\n if (\n !options.handleRemoteUrls &&\n (mediaPath.startsWith(\"http://\") || mediaPath.startsWith(\"https://\"))\n ) {\n return next();\n }\n\n // Handle CORS\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization\");\n\n if (req.method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n try {\n // Parse the path to determine which endpoint\n const pathMatch = url.pathname.match(/^\\/api\\/v1\\/transcode\\/(?:([^/]+)\\/)?(.+)$/);\n\n if (!pathMatch) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Invalid transcode endpoint\" }));\n return;\n }\n\n const [, rendition, endpoint] = pathMatch;\n\n // Handle manifest.json endpoint\n if (endpoint === \"manifest.json\") {\n log(`Generating manifest for ${mediaPath}`);\n const proto =\n (req.headers[\"x-forwarded-proto\"] as string | undefined) || url.protocol.replace(\":\", \"\");\n const baseUrl = `${proto}://${url.host}`;\n\n try {\n const manifest = await generateLocalJitManifest(\n mediaPath,\n sourceUrl,\n baseUrl,\n options.cacheRoot,\n assetFunctions,\n );\n\n res.writeHead(200, {\n \"Content-Type\": \"application/json\",\n \"Cache-Control\": \"public, max-age=300\",\n });\n res.end(JSON.stringify(manifest, null, 2));\n } catch (error) {\n log(`Error generating manifest: ${error}`);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: \"Failed to generate manifest\",\n details: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n return;\n }\n\n // Get fragment index first - we need it to determine track IDs\n const fragmentIndexResult = await assetFunctions.generateTrackFragmentIndex(\n options.cacheRoot,\n mediaPath,\n );\n const fragmentIndex: Record<number, TrackFragmentIndex> = JSON.parse(\n await import(\"node:fs/promises\").then((fs) =>\n fs.readFile(fragmentIndexResult.cachePath, \"utf-8\"),\n ),\n );\n\n // Helper: Map rendition ID to track ID, using fragment index to find correct track\n // For video files: track 1 = video, track 2 = audio\n // For audio-only files: track 1 = audio (no track 2)\n const getTrackId = (renditionId: string): number => {\n if (renditionId === \"scrub\") return -1;\n\n if (renditionId === \"audio\") {\n // Find the audio track - could be track 1 (audio-only) or track 2 (video+audio)\n for (const [trackIdStr, trackInfo] of Object.entries(fragmentIndex)) {\n if (trackInfo.type === \"audio\") {\n return Number.parseInt(trackIdStr, 10);\n }\n }\n // Fallback to track 2 if no audio track found by type\n return 2;\n }\n\n // For video renditions (high, medium, low), find the video track\n for (const [trackIdStr, trackInfo] of Object.entries(fragmentIndex)) {\n if (trackInfo.type === \"video\") {\n return Number.parseInt(trackIdStr, 10);\n }\n }\n // Fallback to track 1\n return 1;\n };\n\n // Handle init segment endpoint (e.g., /api/v1/transcode/high/init.mp4 or init.m4s)\n const initMatch = endpoint?.match(/^init\\.(mp4|m4s)$/);\n if (initMatch && rendition) {\n const extension = initMatch[1];\n const contentType = extension === \"m4s\" ? \"video/iso.segment\" : \"video/mp4\";\n log(`Serving init segment (${extension}) for ${mediaPath}, rendition: ${rendition}`);\n\n try {\n const trackId = getTrackId(rendition);\n\n // Generate/get the track file\n let trackTaskResult;\n if (trackId === -1) {\n trackTaskResult = await assetFunctions.generateScrubTrack(options.cacheRoot, mediaPath);\n } else {\n const trackUrl = `/@ef-track/${mediaPath}?trackId=${trackId}`;\n trackTaskResult = await assetFunctions.generateTrack(\n options.cacheRoot,\n mediaPath,\n trackUrl,\n );\n }\n\n const track = fragmentIndex[trackId];\n if (!track) {\n const validTracks = Object.keys(fragmentIndex).join(\", \");\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Track ${trackId} not found (valid tracks: ${validTracks})`,\n }),\n );\n return;\n }\n\n // Stream only the init segment bytes\n const { offset, size } = track.initSegment;\n log(`Init segment: offset=${offset}, size=${size}`);\n sendByteRange(res, trackTaskResult.cachePath, offset, size, contentType);\n } catch (error) {\n log(`Error serving init segment: ${error}`);\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"File not found\");\n } else {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: \"Failed to generate init segment\",\n details: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n }\n return;\n }\n\n // Handle media segment endpoint\n // - .m4s: moof+mdat only (fragment for streaming)\n // - .mp4: init+moof+mdat (playable standalone file for testing)\n const segmentMatch = endpoint?.match(/^(\\d+)\\.(mp4|m4s)$/);\n if (segmentMatch?.[1] && segmentMatch?.[2] && rendition) {\n const segmentId = Number.parseInt(segmentMatch[1], 10);\n const extension = segmentMatch[2];\n const includeInit = extension === \"mp4\";\n log(\n `Serving media segment ${segmentId}.${extension} for ${mediaPath}, rendition: ${rendition}, includeInit: ${includeInit}`,\n );\n\n try {\n const trackId = getTrackId(rendition);\n\n // Generate/get the track file\n let trackTaskResult;\n if (trackId === -1) {\n trackTaskResult = await assetFunctions.generateScrubTrack(options.cacheRoot, mediaPath);\n } else {\n const trackUrl = `/@ef-track/${mediaPath}?trackId=${trackId}`;\n trackTaskResult = await assetFunctions.generateTrack(\n options.cacheRoot,\n mediaPath,\n trackUrl,\n );\n }\n\n const track = fragmentIndex[trackId];\n if (!track) {\n const validTracks = Object.keys(fragmentIndex).join(\", \");\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Track ${trackId} not found (valid tracks: ${validTracks})`,\n }),\n );\n return;\n }\n\n // JIT uses 1-based segment IDs, fragment index uses 0-based\n const segmentIndex = segmentId - 1;\n const segment = track.segments[segmentIndex];\n if (!segment) {\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: `Segment ${segmentId} not found`,\n availableSegments: track.segments.length,\n }),\n );\n return;\n }\n\n const contentType = extension === \"m4s\" ? \"video/iso.segment\" : \"video/mp4\";\n\n if (includeInit) {\n // .mp4: Stream init segment + media segment (playable file)\n const initSegment = track.initSegment;\n log(\n `Media segment ${segmentId}.mp4: init(offset=${initSegment.offset}, size=${initSegment.size}) + segment(offset=${segment.offset}, size=${segment.size})`,\n );\n sendMultipleByteRanges(\n res,\n trackTaskResult.cachePath,\n [\n { offset: initSegment.offset, size: initSegment.size },\n { offset: segment.offset, size: segment.size },\n ],\n contentType,\n );\n } else {\n // .m4s: Stream only this segment's bytes (moof+mdat)\n const { offset, size } = segment;\n log(`Media segment ${segmentId}.m4s: offset=${offset}, size=${size}`);\n sendByteRange(res, trackTaskResult.cachePath, offset, size, contentType);\n }\n } catch (error) {\n log(`Error serving media segment: ${error}`);\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"File not found\");\n } else {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: \"Failed to generate media segment\",\n details: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n }\n return;\n }\n\n // Unknown endpoint\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Unknown transcode endpoint\" }));\n } catch (error) {\n log(`Unexpected error: ${error}`);\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(\n JSON.stringify({\n error: \"Internal server error\",\n details: error instanceof Error ? error.message : String(error),\n }),\n );\n }\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"jitTranscodeMiddleware.js","names":[],"sources":["../src/jitTranscodeMiddleware.ts"],"mappings":"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"}
@@ -3,7 +3,6 @@ import { sendTaskResult } from "./sendTaskResult.js";
3
3
  import debug from "debug";
4
4
  import path, { join } from "node:path";
5
5
  import { rm } from "node:fs/promises";
6
-
7
6
  //#region src/middleware.ts
8
7
  function createAssetsApiMiddleware(options, deps) {
9
8
  const { cacheImage, findOrCreateCaptions } = deps;
@@ -151,7 +150,7 @@ async function handleClearCache(req, res, cacheRoot) {
151
150
  res.writeHead(200, { "Content-Type": "text/plain" });
152
151
  res.end("Cache cleared");
153
152
  }
154
-
155
153
  //#endregion
156
154
  export { createAssetsApiMiddleware, createLocalFilesApiMiddleware, handleClearCache };
155
+
157
156
  //# sourceMappingURL=middleware.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"middleware.js","names":["error: any"],"sources":["../src/middleware.ts"],"sourcesContent":["import { rm } from \"node:fs/promises\";\nimport path, { join } from \"node:path\";\nimport type { ServerResponse } from \"node:http\";\nimport type { IncomingMessage, NextFunction } from \"connect\";\nimport debug from \"debug\";\n\nimport { forbidRelativePaths } from \"./forbidRelativePaths.js\";\nimport { sendTaskResult } from \"./sendTaskResult.js\";\n\ntype Middleware = (req: IncomingMessage, res: ServerResponse, next: NextFunction) => void;\n\ninterface PluginOptions {\n root: string;\n cacheRoot: string;\n}\n\ninterface AssetsDeps {\n cacheImage: (cacheRoot: string, src: string) => Promise<any>;\n findOrCreateCaptions: (cacheRoot: string, src: string) => Promise<any>;\n}\n\ninterface FilesDeps {\n generateTrack: (cacheRoot: string, src: string, trackUrl: string) => Promise<any>;\n generateScrubTrack: (cacheRoot: string, src: string) => Promise<any>;\n generateTrackFragmentIndex: (cacheRoot: string, src: string) => Promise<any>;\n md5FilePath: (src: string) => Promise<string>;\n}\n\nexport function createAssetsApiMiddleware(options: PluginOptions, deps: AssetsDeps): Middleware {\n const { cacheImage, findOrCreateCaptions } = deps;\n return async (req, res, next) => {\n const log = debug(\"ef:vite-plugin:assets\");\n const reqUrl = req.url || \"\";\n\n if (!reqUrl.startsWith(\"/api/v1/assets/\")) {\n return next();\n }\n\n forbidRelativePaths(req);\n\n const url = new URL(reqUrl, `http://${req.headers.host}`);\n const urlPath = url.pathname;\n const src = url.searchParams.get(\"src\");\n\n if (!src) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"src parameter is required\" }));\n return;\n }\n\n const isRemote = src.startsWith(\"http://\") || src.startsWith(\"https://\");\n const absolutePath = isRemote ? src : path.join(options.root, src).replace(\"dist/\", \"src/\");\n\n log(`Handling assets API: ${urlPath} src=${src}`);\n\n try {\n if (urlPath === \"/api/v1/assets/image\") {\n if (isRemote) {\n const response = await fetch(src);\n if (!response.ok) {\n res.writeHead(response.status);\n res.end();\n return;\n }\n const contentType = response.headers.get(\"content-type\") ?? \"application/octet-stream\";\n const buffer = await response.arrayBuffer();\n res.writeHead(200, { \"Content-Type\": contentType });\n res.end(Buffer.from(buffer));\n } else {\n const taskResult = await cacheImage(options.cacheRoot, absolutePath);\n sendTaskResult(req, res, taskResult);\n }\n return;\n }\n\n if (urlPath === \"/api/v1/assets/captions\") {\n const taskResult = await findOrCreateCaptions(options.cacheRoot, absolutePath);\n sendTaskResult(req, res, taskResult);\n return;\n }\n\n res.writeHead(404, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"Unknown assets endpoint\" }));\n } catch (error) {\n log(`Error handling assets request: ${error}`);\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"File not found\");\n } else {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: (error as Error).message }));\n }\n }\n };\n}\n\nexport function createLocalFilesApiMiddleware(options: PluginOptions, deps: FilesDeps): Middleware {\n const { generateTrack, generateScrubTrack, generateTrackFragmentIndex, md5FilePath } = deps;\n return async (req, res, next) => {\n const log = debug(\"ef:vite-plugin:files\");\n const reqUrl = req.url || \"\";\n\n const url = new URL(reqUrl, `http://${req.headers.host}`);\n const urlPath = url.pathname;\n const src = url.searchParams.get(\"src\");\n\n if (\n !src ||\n (urlPath !== \"/api/v1/files/index\" &&\n urlPath !== \"/api/v1/files/md5\" &&\n urlPath !== \"/api/v1/files/track\")\n ) {\n return next();\n }\n\n forbidRelativePaths(req);\n\n const absolutePath = src.startsWith(\"http\")\n ? src\n : path.join(options.root, src).replace(\"dist/\", \"src/\");\n\n log(`Handling local file API: ${urlPath} for ${absolutePath}`);\n\n try {\n if (urlPath === \"/api/v1/files/index\") {\n log(`Serving track fragment index for ${absolutePath}`);\n const taskResult = await generateTrackFragmentIndex(options.cacheRoot, absolutePath);\n sendTaskResult(req, res, taskResult);\n return;\n }\n\n if (urlPath === \"/api/v1/files/md5\") {\n log(`Getting MD5 for ${absolutePath}`);\n try {\n const md5 = await md5FilePath(absolutePath);\n res.writeHead(200, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ md5 }));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"File not found\");\n } else {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: (error as Error).message }));\n }\n }\n return;\n }\n\n if (urlPath === \"/api/v1/files/track\") {\n const trackIdStr = url.searchParams.get(\"trackId\");\n const segmentIdStr = url.searchParams.get(\"segmentId\");\n\n if (!trackIdStr) {\n res.writeHead(400, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: \"trackId parameter is required\" }));\n return;\n }\n\n const trackId = parseInt(trackIdStr, 10);\n\n if (trackId === -1) {\n log(`Serving scrub track for ${absolutePath}`);\n const taskResult = await generateScrubTrack(options.cacheRoot, absolutePath);\n sendTaskResult(req, res, taskResult);\n return;\n }\n\n log(`Serving track ${trackId} segment ${segmentIdStr || \"all\"} for ${absolutePath}`);\n const trackUrl = `/@ef-track/${src}?trackId=${trackId}${segmentIdStr ? `&segmentId=${segmentIdStr}` : \"\"}`;\n const taskResult = await generateTrack(options.cacheRoot, absolutePath, trackUrl);\n sendTaskResult(req, res, taskResult);\n return;\n }\n } catch (error) {\n log(`Error handling local file request: ${error}`);\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n res.writeHead(404, { \"Content-Type\": \"text/plain\" });\n res.end(\"File not found\");\n } else {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: (error as Error).message }));\n }\n }\n };\n}\n\nexport async function handleClearCache(\n req: IncomingMessage,\n res: ServerResponse,\n cacheRoot: string,\n): Promise<void> {\n const log = debug(\"ef:vite-plugin\");\n if (req.method !== \"DELETE\") {\n res.writeHead(405, { Allow: \"DELETE\" });\n res.end();\n return;\n }\n log(`Clearing cache for ${cacheRoot}`);\n const cachePath = join(cacheRoot, \".cache\");\n const maxRetries = 3;\n for (let attempt = 0; attempt < maxRetries; attempt++) {\n try {\n await rm(cachePath, { recursive: true, force: true });\n break;\n } catch (error: any) {\n if (error.code === \"ENOENT\") {\n break;\n }\n if (error.code === \"ENOTEMPTY\" && attempt < maxRetries - 1) {\n await new Promise((resolve) => setTimeout(resolve, 100 * (attempt + 1)));\n continue;\n }\n log(`Warning: Cache clear attempt ${attempt + 1} failed: ${error.message}`);\n if (attempt === maxRetries - 1) {\n log(`Cache clear failed after ${maxRetries} attempts, continuing anyway`);\n }\n }\n }\n res.writeHead(200, { \"Content-Type\": \"text/plain\" });\n res.end(\"Cache cleared\");\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"middleware.js","names":[],"sources":["../src/middleware.ts"],"mappings":"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"}
@@ -1,7 +1,6 @@
1
1
  import debug from "debug";
2
2
  import { createReadStream, statSync } from "node:fs";
3
3
  import mime from "mime";
4
-
5
4
  //#region src/sendTaskResult.ts
6
5
  const sendTaskResult = (req, res, taskResult) => {
7
6
  const { cachePath, md5Sum } = taskResult;
@@ -62,7 +61,7 @@ const sendTaskResult = (req, res, taskResult) => {
62
61
  }
63
62
  }
64
63
  };
65
-
66
64
  //#endregion
67
65
  export { sendTaskResult };
66
+
68
67
  //# sourceMappingURL=sendTaskResult.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sendTaskResult.js","names":[],"sources":["../src/sendTaskResult.ts"],"sourcesContent":["import { createReadStream, statSync } from \"node:fs\";\nimport type { IncomingMessage, ServerResponse } from \"node:http\";\nimport type { TaskResult } from \"@editframe/assets\";\nimport debug from \"debug\";\nimport mime from \"mime\";\n\nexport const sendTaskResult = (\n req: IncomingMessage,\n res: ServerResponse<IncomingMessage>,\n taskResult: TaskResult,\n) => {\n const { cachePath, md5Sum } = taskResult;\n const filePath = cachePath;\n const headers = {\n etag: md5Sum,\n };\n const log = debug(\"ef:sendfile\");\n const sendStartTime = Date.now();\n try {\n const stats = statSync(filePath);\n log(`Sending file ${filePath} (size: ${stats.size} bytes)`);\n\n if (req.headers.range) {\n const [x, y] = req.headers.range.replace(\"bytes=\", \"\").split(\"-\");\n let end = Number.parseInt(y ?? \"0\", 10) || stats.size - 1;\n const start = Number.parseInt(x ?? \"0\", 10) || 0;\n\n if (end >= stats.size) {\n end = stats.size - 1;\n }\n\n if (start >= stats.size) {\n log(\"Range start is greater than file size\");\n res.setHeader(\"Content-Range\", `bytes */${stats.size}`);\n res.statusCode = 416;\n return res.end();\n }\n\n res.writeHead(206, {\n ...headers,\n \"Content-Type\": mime.getType(filePath) || \"text/plain\",\n \"Cache-Control\": \"max-age=3600\",\n \"Content-Range\": `bytes ${start}-${end}/${stats.size}`,\n \"Content-Length\": end - start + 1,\n \"Accept-Ranges\": \"bytes\",\n });\n log(`Sending ${filePath} range ${start}-${end}/${stats.size}`);\n const readStream = createReadStream(filePath, { start, end });\n readStream.on(\"end\", () => {\n const elapsed = Date.now() - sendStartTime;\n log(`Range request completed in ${elapsed}ms`);\n });\n readStream.pipe(res);\n } else {\n res.writeHead(200, {\n ...headers,\n \"Content-Type\": mime.getType(filePath) || \"text/plain\",\n \"Cache-Control\": \"max-age=3600\",\n \"Content-Length\": stats.size,\n });\n log(`Sending full file ${filePath} (${stats.size} bytes)`);\n const readStream = createReadStream(filePath);\n readStream.on(\"end\", () => {\n const elapsed = Date.now() - sendStartTime;\n log(`File send completed in ${elapsed}ms`);\n });\n readStream.pipe(res);\n }\n } catch (error) {\n const elapsed = Date.now() - sendStartTime;\n log(`Error sending file after ${elapsed}ms:`, error);\n if (!res.headersSent) {\n res.writeHead(500, { \"Content-Type\": \"application/json\" });\n res.end(JSON.stringify({ error: (error as Error).message }));\n }\n }\n};\n"],"mappings":";;;;;AAMA,MAAa,kBACX,KACA,KACA,eACG;CACH,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,WAAW;CACjB,MAAM,UAAU,EACd,MAAM,QACP;CACD,MAAM,MAAM,MAAM,cAAc;CAChC,MAAM,gBAAgB,KAAK,KAAK;AAChC,KAAI;EACF,MAAM,QAAQ,SAAS,SAAS;AAChC,MAAI,gBAAgB,SAAS,UAAU,MAAM,KAAK,SAAS;AAE3D,MAAI,IAAI,QAAQ,OAAO;GACrB,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,MAAM,QAAQ,UAAU,GAAG,CAAC,MAAM,IAAI;GACjE,IAAI,MAAM,OAAO,SAAS,KAAK,KAAK,GAAG,IAAI,MAAM,OAAO;GACxD,MAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,GAAG,IAAI;AAE/C,OAAI,OAAO,MAAM,KACf,OAAM,MAAM,OAAO;AAGrB,OAAI,SAAS,MAAM,MAAM;AACvB,QAAI,wCAAwC;AAC5C,QAAI,UAAU,iBAAiB,WAAW,MAAM,OAAO;AACvD,QAAI,aAAa;AACjB,WAAO,IAAI,KAAK;;AAGlB,OAAI,UAAU,KAAK;IACjB,GAAG;IACH,gBAAgB,KAAK,QAAQ,SAAS,IAAI;IAC1C,iBAAiB;IACjB,iBAAiB,SAAS,MAAM,GAAG,IAAI,GAAG,MAAM;IAChD,kBAAkB,MAAM,QAAQ;IAChC,iBAAiB;IAClB,CAAC;AACF,OAAI,WAAW,SAAS,SAAS,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO;GAC9D,MAAM,aAAa,iBAAiB,UAAU;IAAE;IAAO;IAAK,CAAC;AAC7D,cAAW,GAAG,aAAa;AAEzB,QAAI,8BADY,KAAK,KAAK,GAAG,cACa,IAAI;KAC9C;AACF,cAAW,KAAK,IAAI;SACf;AACL,OAAI,UAAU,KAAK;IACjB,GAAG;IACH,gBAAgB,KAAK,QAAQ,SAAS,IAAI;IAC1C,iBAAiB;IACjB,kBAAkB,MAAM;IACzB,CAAC;AACF,OAAI,qBAAqB,SAAS,IAAI,MAAM,KAAK,SAAS;GAC1D,MAAM,aAAa,iBAAiB,SAAS;AAC7C,cAAW,GAAG,aAAa;AAEzB,QAAI,0BADY,KAAK,KAAK,GAAG,cACS,IAAI;KAC1C;AACF,cAAW,KAAK,IAAI;;UAEf,OAAO;AAEd,MAAI,4BADY,KAAK,KAAK,GAAG,cACW,MAAM,MAAM;AACpD,MAAI,CAAC,IAAI,aAAa;AACpB,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAQ,MAAgB,SAAS,CAAC,CAAC"}
1
+ {"version":3,"file":"sendTaskResult.js","names":[],"sources":["../src/sendTaskResult.ts"],"mappings":";;;;AAMA,MAAa,kBACX,KACA,KACA,eACG;CACH,MAAM,EAAE,WAAW,WAAW;CAC9B,MAAM,WAAW;CACjB,MAAM,UAAU,EACd,MAAM,QACP;CACD,MAAM,MAAM,MAAM,cAAc;CAChC,MAAM,gBAAgB,KAAK,KAAK;AAChC,KAAI;EACF,MAAM,QAAQ,SAAS,SAAS;AAChC,MAAI,gBAAgB,SAAS,UAAU,MAAM,KAAK,SAAS;AAE3D,MAAI,IAAI,QAAQ,OAAO;GACrB,MAAM,CAAC,GAAG,KAAK,IAAI,QAAQ,MAAM,QAAQ,UAAU,GAAG,CAAC,MAAM,IAAI;GACjE,IAAI,MAAM,OAAO,SAAS,KAAK,KAAK,GAAG,IAAI,MAAM,OAAO;GACxD,MAAM,QAAQ,OAAO,SAAS,KAAK,KAAK,GAAG,IAAI;AAE/C,OAAI,OAAO,MAAM,KACf,OAAM,MAAM,OAAO;AAGrB,OAAI,SAAS,MAAM,MAAM;AACvB,QAAI,wCAAwC;AAC5C,QAAI,UAAU,iBAAiB,WAAW,MAAM,OAAO;AACvD,QAAI,aAAa;AACjB,WAAO,IAAI,KAAK;;AAGlB,OAAI,UAAU,KAAK;IACjB,GAAG;IACH,gBAAgB,KAAK,QAAQ,SAAS,IAAI;IAC1C,iBAAiB;IACjB,iBAAiB,SAAS,MAAM,GAAG,IAAI,GAAG,MAAM;IAChD,kBAAkB,MAAM,QAAQ;IAChC,iBAAiB;IAClB,CAAC;AACF,OAAI,WAAW,SAAS,SAAS,MAAM,GAAG,IAAI,GAAG,MAAM,OAAO;GAC9D,MAAM,aAAa,iBAAiB,UAAU;IAAE;IAAO;IAAK,CAAC;AAC7D,cAAW,GAAG,aAAa;AAEzB,QAAI,8BADY,KAAK,KAAK,GAAG,cACa,IAAI;KAC9C;AACF,cAAW,KAAK,IAAI;SACf;AACL,OAAI,UAAU,KAAK;IACjB,GAAG;IACH,gBAAgB,KAAK,QAAQ,SAAS,IAAI;IAC1C,iBAAiB;IACjB,kBAAkB,MAAM;IACzB,CAAC;AACF,OAAI,qBAAqB,SAAS,IAAI,MAAM,KAAK,SAAS;GAC1D,MAAM,aAAa,iBAAiB,SAAS;AAC7C,cAAW,GAAG,aAAa;AAEzB,QAAI,0BADY,KAAK,KAAK,GAAG,cACS,IAAI;KAC1C;AACF,cAAW,KAAK,IAAI;;UAEf,OAAO;AAEd,MAAI,4BADY,KAAK,KAAK,GAAG,cACW,MAAM,MAAM;AACpD,MAAI,CAAC,IAAI,aAAa;AACpB,OAAI,UAAU,KAAK,EAAE,gBAAgB,oBAAoB,CAAC;AAC1D,OAAI,IAAI,KAAK,UAAU,EAAE,OAAQ,MAAgB,SAAS,CAAC,CAAC"}
package/dist/version.js CHANGED
@@ -1,6 +1,6 @@
1
1
  //#region src/version.ts
2
- const version = "0.47.1";
3
-
2
+ const version = "0.48.0";
4
3
  //#endregion
5
4
  export { version };
5
+
6
6
  //# sourceMappingURL=version.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"version.js","names":[],"sources":["../src/version.ts"],"sourcesContent":["export const version = \"0.47.1\";\n"],"mappings":";AAAA,MAAa,UAAU"}
1
+ {"version":3,"file":"version.js","names":[],"sources":["../src/version.ts"],"mappings":";AAAA,MAAa,UAAU"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@editframe/vite-plugin",
3
- "version": "0.47.1",
3
+ "version": "0.48.0",
4
4
  "description": "Editframe vite plugin",
5
5
  "exports": {
6
6
  ".": {
@@ -20,13 +20,13 @@
20
20
  "author": "",
21
21
  "license": "SEE LICENSE IN LICENSE-FULL.md",
22
22
  "dependencies": {
23
- "@editframe/api": "0.47.1",
24
- "@editframe/assets": "0.47.1",
23
+ "@editframe/api": "0.48.0",
24
+ "@editframe/assets": "0.48.0",
25
25
  "connect": "^3.7.0",
26
26
  "debug": "^4.3.5",
27
27
  "mime": "^4.0.3",
28
28
  "odiff-bin": "^4.3.2",
29
- "vite": "npm:rolldown-vite@^7.1.15"
29
+ "vite": "^8.0.0"
30
30
  },
31
31
  "devDependencies": {
32
32
  "@types/connect": "^3.4.38",
@@ -45,7 +45,5 @@
45
45
  },
46
46
  "./package.json": "./package.json"
47
47
  }
48
- },
49
- "main": "./dist/index.js",
50
- "module": "./dist/index.js"
48
+ }
51
49
  }