@editframe/elements 0.26.4-beta.0 → 0.30.0-beta.13
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/elements/EFSourceMixin.js +1 -1
- package/dist/elements/EFSourceMixin.js.map +1 -1
- package/dist/elements/EFSurface.d.ts +4 -4
- package/dist/elements/EFText.d.ts +52 -0
- package/dist/elements/EFText.js +319 -0
- package/dist/elements/EFText.js.map +1 -0
- package/dist/elements/EFTextSegment.d.ts +30 -0
- package/dist/elements/EFTextSegment.js +94 -0
- package/dist/elements/EFTextSegment.js.map +1 -0
- package/dist/elements/EFThumbnailStrip.d.ts +4 -4
- package/dist/elements/EFWaveform.d.ts +4 -4
- package/dist/elements/FetchMixin.js +22 -7
- package/dist/elements/FetchMixin.js.map +1 -1
- package/dist/elements/easingUtils.js +62 -0
- package/dist/elements/easingUtils.js.map +1 -0
- package/dist/elements/updateAnimations.js +57 -10
- package/dist/elements/updateAnimations.js.map +1 -1
- package/dist/gui/ContextMixin.js +11 -2
- package/dist/gui/ContextMixin.js.map +1 -1
- package/dist/gui/EFConfiguration.d.ts +4 -4
- package/dist/gui/EFControls.d.ts +2 -2
- package/dist/gui/EFDial.d.ts +4 -4
- package/dist/gui/EFDial.js +4 -2
- package/dist/gui/EFDial.js.map +1 -1
- package/dist/gui/EFFilmstrip.d.ts +32 -6
- package/dist/gui/EFFilmstrip.js +314 -50
- package/dist/gui/EFFilmstrip.js.map +1 -1
- package/dist/gui/EFFitScale.js +39 -15
- package/dist/gui/EFFitScale.js.map +1 -1
- package/dist/gui/EFFocusOverlay.d.ts +4 -4
- package/dist/gui/EFPause.d.ts +4 -4
- package/dist/gui/EFPlay.d.ts +4 -4
- package/dist/gui/EFPreview.d.ts +4 -4
- package/dist/gui/EFPreview.js +2 -2
- package/dist/gui/EFPreview.js.map +1 -1
- package/dist/gui/EFResizableBox.d.ts +4 -4
- package/dist/gui/EFResizableBox.js +6 -3
- package/dist/gui/EFResizableBox.js.map +1 -1
- package/dist/gui/EFScrubber.d.ts +8 -5
- package/dist/gui/EFScrubber.js +64 -12
- package/dist/gui/EFScrubber.js.map +1 -1
- package/dist/gui/EFTimeDisplay.d.ts +4 -4
- package/dist/gui/EFToggleLoop.d.ts +4 -4
- package/dist/gui/EFTogglePlay.d.ts +4 -4
- package/dist/gui/EFWorkbench.d.ts +4 -4
- package/dist/gui/EFWorkbench.js +16 -3
- package/dist/gui/EFWorkbench.js.map +1 -1
- package/dist/gui/TWMixin.js +1 -1
- package/dist/gui/TWMixin.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/index.js.map +1 -1
- package/dist/style.css +7 -120
- package/package.json +3 -3
- package/scripts/build-css.js +2 -6
- package/test/constants.ts +8 -0
- package/test/recordReplayProxyPlugin.js +76 -10
- package/test/setup.ts +32 -0
- package/test/useMSW.ts +3 -0
- package/test/useTranscodeMSW.ts +191 -0
- package/tsdown.config.ts +6 -4
- package/types.json +1 -1
package/test/setup.ts
CHANGED
|
@@ -9,6 +9,38 @@ import {
|
|
|
9
9
|
mediaCache,
|
|
10
10
|
} from "../src/elements/EFMedia/BaseMediaEngine.js";
|
|
11
11
|
import { globalURLTokenDeduplicator } from "../src/transcoding/cache/URLTokenDeduplicator.js";
|
|
12
|
+
import { TEST_SERVER_PORT } from "./constants.js";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Get the correct API host for the current environment.
|
|
16
|
+
* In local dev with Traefik, returns the Traefik URL (e.g., http://main.localhost:4322).
|
|
17
|
+
* In CI or direct access, returns the current location (e.g., http://localhost:63315).
|
|
18
|
+
*/
|
|
19
|
+
export function getApiHost(): string {
|
|
20
|
+
const host = window.location.host;
|
|
21
|
+
const protocol = window.location.protocol;
|
|
22
|
+
|
|
23
|
+
// Check if CI mode was injected by server
|
|
24
|
+
const isCI = (window as any).__CI_MODE__ === true;
|
|
25
|
+
|
|
26
|
+
if (isCI) {
|
|
27
|
+
// CI mode: always use localhost directly
|
|
28
|
+
return `${protocol}//${host}`;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (host === `localhost:${TEST_SERVER_PORT}`) {
|
|
32
|
+
// Check if we have a Traefik referrer (local dev)
|
|
33
|
+
const traefikReferrer = document.referrer.match(/\/\/([^:]+):4322/)?.[1];
|
|
34
|
+
if (traefikReferrer) {
|
|
35
|
+
// Local dev: use Traefik URL
|
|
36
|
+
return `${protocol}//${traefikReferrer}:4322`;
|
|
37
|
+
}
|
|
38
|
+
// No Traefik referrer but not explicitly CI: use localhost directly
|
|
39
|
+
return `${protocol}//${host}`;
|
|
40
|
+
}
|
|
41
|
+
// Already on Traefik URL or other configuration
|
|
42
|
+
return `${protocol}//${host}`;
|
|
43
|
+
}
|
|
12
44
|
|
|
13
45
|
// Clear global caches before each test to ensure isolation
|
|
14
46
|
beforeEach(() => {
|
package/test/useMSW.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
import { setupWorker } from "msw/browser";
|
|
7
7
|
import { test as testBase } from "vitest";
|
|
8
|
+
import { transcodeMSWHandlers } from "./useTranscodeMSW.js";
|
|
8
9
|
|
|
9
10
|
// Create the worker instance that will be shared across tests
|
|
10
11
|
const worker = setupWorker();
|
|
@@ -26,6 +27,8 @@ export const test = testBase.extend<{
|
|
|
26
27
|
await worker.start({
|
|
27
28
|
onUnhandledRequest: "bypass", // Allow unhandled requests to pass through
|
|
28
29
|
});
|
|
30
|
+
// Set up default handlers for transcode API endpoints
|
|
31
|
+
worker.use(...transcodeMSWHandlers);
|
|
29
32
|
workerStarted = true;
|
|
30
33
|
}
|
|
31
34
|
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transcode API MSW handlers for testing
|
|
3
|
+
* Provides handlers for transcode API endpoints including URL signing
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { HttpResponse, http } from "msw";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* MSW handlers for transcode API endpoints
|
|
10
|
+
* These handlers mock the API responses needed for tests
|
|
11
|
+
*/
|
|
12
|
+
export const transcodeMSWHandlers = [
|
|
13
|
+
// URL signing endpoint handler
|
|
14
|
+
// This mocks the /@ef-sign-url endpoint used by the Vite plugin
|
|
15
|
+
http.post("/@ef-sign-url", async () => {
|
|
16
|
+
// Return a mock JWT token
|
|
17
|
+
// The token format is: header.payload.signature
|
|
18
|
+
// We create a simple mock token that will pass basic validation
|
|
19
|
+
const mockToken =
|
|
20
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwOi8vd2ViOjMwMDAvaGVhZC1tb292LTQ4MHAubXA0IiwiZXhwIjo5OTk5OTk5OTk5fQ.mock-signature";
|
|
21
|
+
|
|
22
|
+
return HttpResponse.json(
|
|
23
|
+
{ token: mockToken },
|
|
24
|
+
{
|
|
25
|
+
status: 200,
|
|
26
|
+
headers: {
|
|
27
|
+
"Content-Type": "application/json",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
);
|
|
31
|
+
}),
|
|
32
|
+
|
|
33
|
+
// URL token endpoint handler (for proxied requests from vite plugin)
|
|
34
|
+
// The vite plugin proxies /@ef-sign-url to /api/v1/url-token
|
|
35
|
+
http.post("/api/v1/url-token", async () => {
|
|
36
|
+
// Return the same mock JWT token as /@ef-sign-url
|
|
37
|
+
const mockToken =
|
|
38
|
+
"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1cmwiOiJodHRwOi8vd2ViOjMwMDAvaGVhZC1tb292LTQ4MHAubXA0IiwiZXhwIjo5OTk5OTk5OTk5fQ.mock-signature";
|
|
39
|
+
|
|
40
|
+
return HttpResponse.json(
|
|
41
|
+
{ token: mockToken },
|
|
42
|
+
{
|
|
43
|
+
status: 200,
|
|
44
|
+
headers: {
|
|
45
|
+
"Content-Type": "application/json",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
);
|
|
49
|
+
}),
|
|
50
|
+
|
|
51
|
+
// Transcode manifest endpoint handler
|
|
52
|
+
// This mocks the manifest.json endpoint used by JitMediaEngine
|
|
53
|
+
http.get("/api/v1/transcode/manifest.json", async ({ request }) => {
|
|
54
|
+
const url = new URL(request.url);
|
|
55
|
+
const sourceUrl = url.searchParams.get("url");
|
|
56
|
+
|
|
57
|
+
if (!sourceUrl) {
|
|
58
|
+
return HttpResponse.json(
|
|
59
|
+
{ error: "url parameter is required" },
|
|
60
|
+
{ status: 400 },
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Return a mock manifest response
|
|
65
|
+
const manifest = {
|
|
66
|
+
version: "1.0",
|
|
67
|
+
type: "cmaf",
|
|
68
|
+
duration: 10,
|
|
69
|
+
durationMs: 10000,
|
|
70
|
+
segmentDuration: 2000,
|
|
71
|
+
baseUrl: `${url.origin}/api/v1/transcode`,
|
|
72
|
+
sourceUrl: sourceUrl,
|
|
73
|
+
audioRenditions: [
|
|
74
|
+
{
|
|
75
|
+
id: "audio",
|
|
76
|
+
src: sourceUrl,
|
|
77
|
+
segmentDurationMs: 2000,
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
videoRenditions: [
|
|
81
|
+
{
|
|
82
|
+
id: "high",
|
|
83
|
+
src: sourceUrl,
|
|
84
|
+
segmentDurationMs: 2000,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
endpoints: {
|
|
88
|
+
initSegment: `${url.origin}/api/v1/transcode/{rendition}/init.m4s?url=${encodeURIComponent(sourceUrl)}`,
|
|
89
|
+
mediaSegment: `${url.origin}/api/v1/transcode/{rendition}/{segmentId}.m4s?url=${encodeURIComponent(sourceUrl)}`,
|
|
90
|
+
},
|
|
91
|
+
jitInfo: {
|
|
92
|
+
parallelTranscodingSupported: true,
|
|
93
|
+
expectedTranscodeLatency: 1000,
|
|
94
|
+
segmentCount: 5,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
return HttpResponse.json(manifest, {
|
|
99
|
+
status: 200,
|
|
100
|
+
headers: {
|
|
101
|
+
"Content-Type": "application/json",
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
}),
|
|
105
|
+
|
|
106
|
+
// Transcode init segment endpoint handler
|
|
107
|
+
http.get("/api/v1/transcode/:rendition/init.m4s", async () => {
|
|
108
|
+
// Return a minimal valid MP4 init segment
|
|
109
|
+
// This is a very basic ftyp + moov box structure
|
|
110
|
+
const initSegment = new Uint8Array([
|
|
111
|
+
// ftyp box
|
|
112
|
+
0x00,
|
|
113
|
+
0x00,
|
|
114
|
+
0x00,
|
|
115
|
+
0x20, // box size
|
|
116
|
+
0x66,
|
|
117
|
+
0x74,
|
|
118
|
+
0x79,
|
|
119
|
+
0x70, // 'ftyp'
|
|
120
|
+
0x69,
|
|
121
|
+
0x73,
|
|
122
|
+
0x6f,
|
|
123
|
+
0x6d, // major brand 'isom'
|
|
124
|
+
0x00,
|
|
125
|
+
0x00,
|
|
126
|
+
0x02,
|
|
127
|
+
0x00, // minor version
|
|
128
|
+
0x69,
|
|
129
|
+
0x73,
|
|
130
|
+
0x6f,
|
|
131
|
+
0x6d, // compatible brand 'isom'
|
|
132
|
+
0x69,
|
|
133
|
+
0x73,
|
|
134
|
+
0x6f,
|
|
135
|
+
0x32, // compatible brand 'iso2'
|
|
136
|
+
0x6d,
|
|
137
|
+
0x70,
|
|
138
|
+
0x34,
|
|
139
|
+
0x31, // compatible brand 'mp41'
|
|
140
|
+
// moov box (minimal)
|
|
141
|
+
0x00,
|
|
142
|
+
0x00,
|
|
143
|
+
0x00,
|
|
144
|
+
0x08, // box size
|
|
145
|
+
0x6d,
|
|
146
|
+
0x6f,
|
|
147
|
+
0x6f,
|
|
148
|
+
0x76, // 'moov'
|
|
149
|
+
]);
|
|
150
|
+
|
|
151
|
+
return HttpResponse.arrayBuffer(initSegment.buffer, {
|
|
152
|
+
status: 200,
|
|
153
|
+
headers: {
|
|
154
|
+
"Content-Type": "video/mp4",
|
|
155
|
+
},
|
|
156
|
+
});
|
|
157
|
+
}),
|
|
158
|
+
|
|
159
|
+
// Transcode media segment endpoint handler
|
|
160
|
+
http.get("/api/v1/transcode/:rendition/:segmentId.m4s", async () => {
|
|
161
|
+
// Return a minimal valid MP4 media segment
|
|
162
|
+
// This is a very basic moof + mdat box structure
|
|
163
|
+
const mediaSegment = new Uint8Array([
|
|
164
|
+
// moof box (minimal)
|
|
165
|
+
0x00,
|
|
166
|
+
0x00,
|
|
167
|
+
0x00,
|
|
168
|
+
0x08, // box size
|
|
169
|
+
0x6d,
|
|
170
|
+
0x6f,
|
|
171
|
+
0x6f,
|
|
172
|
+
0x66, // 'moof'
|
|
173
|
+
// mdat box (minimal)
|
|
174
|
+
0x00,
|
|
175
|
+
0x00,
|
|
176
|
+
0x00,
|
|
177
|
+
0x08, // box size
|
|
178
|
+
0x6d,
|
|
179
|
+
0x64,
|
|
180
|
+
0x61,
|
|
181
|
+
0x74, // 'mdat'
|
|
182
|
+
]);
|
|
183
|
+
|
|
184
|
+
return HttpResponse.arrayBuffer(mediaSegment.buffer, {
|
|
185
|
+
status: 200,
|
|
186
|
+
headers: {
|
|
187
|
+
"Content-Type": "video/mp4",
|
|
188
|
+
},
|
|
189
|
+
});
|
|
190
|
+
}),
|
|
191
|
+
];
|
package/tsdown.config.ts
CHANGED
|
@@ -27,11 +27,13 @@ const inlineCssPlugin = (): Plugin => ({
|
|
|
27
27
|
|
|
28
28
|
// Process through Tailwind if it contains @tailwind directives
|
|
29
29
|
if (css.includes("@tailwind")) {
|
|
30
|
-
const
|
|
30
|
+
const _srcDir = path.resolve(path.dirname(filePath));
|
|
31
|
+
const configPath = path.resolve(
|
|
32
|
+
path.dirname(filePath),
|
|
33
|
+
"../../tailwind.config.ts",
|
|
34
|
+
);
|
|
31
35
|
const result = await postcss([
|
|
32
|
-
tailwindcss({
|
|
33
|
-
content: [path.join(srcDir, "**/*.ts")],
|
|
34
|
-
}),
|
|
36
|
+
tailwindcss({ config: configPath }),
|
|
35
37
|
autoprefixer(),
|
|
36
38
|
]).process(css, { from: filePath });
|
|
37
39
|
|