@editframe/create 0.44.0 → 0.45.1
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.js +16 -28
- package/dist/index.js.map +1 -1
- package/dist/skills/editframe-brand-video-generator/README.md +155 -0
- package/dist/skills/editframe-brand-video-generator/SKILL.md +207 -0
- package/dist/skills/editframe-brand-video-generator/references/brand-examples.md +178 -0
- package/dist/skills/editframe-brand-video-generator/references/color-psychology.md +227 -0
- package/dist/skills/editframe-brand-video-generator/references/composition-patterns.md +383 -0
- package/dist/skills/editframe-brand-video-generator/references/editing.md +66 -0
- package/dist/skills/editframe-brand-video-generator/references/emotional-arcs.md +496 -0
- package/dist/skills/editframe-brand-video-generator/references/genre-selection.md +135 -0
- package/dist/skills/editframe-brand-video-generator/references/transition-styles.md +611 -0
- package/dist/skills/editframe-brand-video-generator/references/typography-personalities.md +326 -0
- package/dist/skills/editframe-brand-video-generator/references/video-archetypes.md +86 -0
- package/dist/skills/editframe-brand-video-generator/references/video-fundamentals.md +169 -0
- package/dist/skills/editframe-brand-video-generator/references/visual-metaphors.md +50 -0
- package/dist/skills/editframe-composition/SKILL.md +169 -0
- package/dist/skills/editframe-composition/references/audio.md +483 -0
- package/dist/skills/editframe-composition/references/captions.md +844 -0
- package/dist/skills/editframe-composition/references/composition-model.md +73 -0
- package/dist/skills/editframe-composition/references/configuration.md +403 -0
- package/dist/skills/editframe-composition/references/css-parts.md +105 -0
- package/dist/skills/editframe-composition/references/css-variables.md +640 -0
- package/dist/skills/editframe-composition/references/entry-points.md +810 -0
- package/dist/skills/editframe-composition/references/events.md +499 -0
- package/dist/skills/editframe-composition/references/getting-started.md +259 -0
- package/dist/skills/editframe-composition/references/hooks.md +234 -0
- package/dist/skills/editframe-composition/references/image.md +241 -0
- package/dist/skills/editframe-composition/references/r3f.md +580 -0
- package/dist/skills/editframe-composition/references/render-api.md +484 -0
- package/dist/skills/editframe-composition/references/render-strategies.md +119 -0
- package/dist/skills/editframe-composition/references/render-to-video.md +1101 -0
- package/dist/skills/editframe-composition/references/scripting.md +606 -0
- package/dist/skills/editframe-composition/references/sequencing.md +116 -0
- package/dist/skills/editframe-composition/references/server-rendering.md +753 -0
- package/dist/skills/editframe-composition/references/surface.md +329 -0
- package/dist/skills/editframe-composition/references/text.md +627 -0
- package/dist/skills/editframe-composition/references/time-model.md +99 -0
- package/dist/skills/editframe-composition/references/timegroup-modes.md +102 -0
- package/dist/skills/editframe-composition/references/timegroup.md +457 -0
- package/dist/skills/editframe-composition/references/timeline-root.md +398 -0
- package/dist/skills/editframe-composition/references/transcription.md +47 -0
- package/dist/skills/editframe-composition/references/transitions.md +608 -0
- package/dist/skills/editframe-composition/references/use-media-info.md +357 -0
- package/dist/skills/editframe-composition/references/video.md +506 -0
- package/dist/skills/editframe-composition/references/waveform.md +327 -0
- package/dist/skills/editframe-editor-gui/SKILL.md +152 -0
- package/dist/skills/editframe-editor-gui/references/active-root-temporal.md +657 -0
- package/dist/skills/editframe-editor-gui/references/canvas.md +947 -0
- package/dist/skills/editframe-editor-gui/references/controls.md +366 -0
- package/dist/skills/editframe-editor-gui/references/dial.md +756 -0
- package/dist/skills/editframe-editor-gui/references/editor-toolkit.md +587 -0
- package/dist/skills/editframe-editor-gui/references/filmstrip.md +460 -0
- package/dist/skills/editframe-editor-gui/references/fit-scale.md +772 -0
- package/dist/skills/editframe-editor-gui/references/focus-overlay.md +561 -0
- package/dist/skills/editframe-editor-gui/references/hierarchy.md +544 -0
- package/dist/skills/editframe-editor-gui/references/overlay-item.md +634 -0
- package/dist/skills/editframe-editor-gui/references/overlay-layer.md +429 -0
- package/dist/skills/editframe-editor-gui/references/pan-zoom.md +568 -0
- package/dist/skills/editframe-editor-gui/references/pause.md +397 -0
- package/dist/skills/editframe-editor-gui/references/play.md +370 -0
- package/dist/skills/editframe-editor-gui/references/preview.md +391 -0
- package/dist/skills/editframe-editor-gui/references/resizable-box.md +749 -0
- package/dist/skills/editframe-editor-gui/references/scrubber.md +588 -0
- package/dist/skills/editframe-editor-gui/references/thumbnail-strip.md +566 -0
- package/dist/skills/editframe-editor-gui/references/time-display.md +492 -0
- package/dist/skills/editframe-editor-gui/references/timeline-ruler.md +489 -0
- package/dist/skills/editframe-editor-gui/references/timeline.md +604 -0
- package/dist/skills/editframe-editor-gui/references/toggle-loop.md +618 -0
- package/dist/skills/editframe-editor-gui/references/toggle-play.md +526 -0
- package/dist/skills/editframe-editor-gui/references/transform-handles.md +924 -0
- package/dist/skills/editframe-editor-gui/references/trim-handles.md +725 -0
- package/dist/skills/editframe-editor-gui/references/workbench.md +453 -0
- package/dist/skills/editframe-motion-design/SKILL.md +101 -0
- package/dist/skills/editframe-motion-design/references/0-editframe.md +299 -0
- package/dist/skills/editframe-motion-design/references/1-intent.md +201 -0
- package/dist/skills/editframe-motion-design/references/2-physics-model.md +405 -0
- package/dist/skills/editframe-motion-design/references/3-attention.md +350 -0
- package/dist/skills/editframe-motion-design/references/4-process.md +418 -0
- package/dist/skills/editframe-vite-plugin/SKILL.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/file-api.md +111 -0
- package/dist/skills/editframe-vite-plugin/references/getting-started.md +96 -0
- package/dist/skills/editframe-vite-plugin/references/jit-transcoding.md +91 -0
- package/dist/skills/editframe-vite-plugin/references/local-assets.md +75 -0
- package/dist/skills/editframe-vite-plugin/references/visual-testing.md +136 -0
- package/dist/skills/editframe-webhooks/SKILL.md +126 -0
- package/dist/skills/editframe-webhooks/references/events.md +382 -0
- package/dist/skills/editframe-webhooks/references/getting-started.md +232 -0
- package/dist/skills/editframe-webhooks/references/security.md +418 -0
- package/dist/skills/editframe-webhooks/references/testing.md +409 -0
- package/dist/skills/editframe-webhooks/references/troubleshooting.md +457 -0
- package/dist/templates/html/AGENTS.md +13 -0
- package/dist/templates/react/AGENTS.md +13 -0
- package/dist/utils.js +15 -16
- package/dist/utils.js.map +1 -1
- package/package.json +1 -1
- package/tsdown.config.ts +4 -0
- package/dist/detectAgent.js +0 -89
- package/dist/detectAgent.js.map +0 -1
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: JIT Transcoding
|
|
3
|
+
description: On-demand video transcoding during local development for instant browser-compatible playback of any input video format.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Features"
|
|
7
|
+
priority: 20
|
|
8
|
+
api:
|
|
9
|
+
endpoints:
|
|
10
|
+
- path: /api/v1/transcode/manifest.json
|
|
11
|
+
method: GET
|
|
12
|
+
description: Returns a JIT manifest describing available renditions and segments
|
|
13
|
+
- path: /api/v1/transcode/{rendition}/init.mp4
|
|
14
|
+
method: GET
|
|
15
|
+
description: Returns the initialization segment for a rendition
|
|
16
|
+
- path: /api/v1/transcode/{rendition}/{segmentId}.mp4
|
|
17
|
+
method: GET
|
|
18
|
+
description: Returns a media segment as a standalone playable file
|
|
19
|
+
- path: /api/v1/transcode/{rendition}/{segmentId}.m4s
|
|
20
|
+
method: GET
|
|
21
|
+
description: Returns a media segment fragment for streaming
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
# JIT Transcoding
|
|
25
|
+
|
|
26
|
+
The Vite plugin transcodes video files on-demand during development. When a composition references a local video, the plugin splits it into streamable ISOBMFF segments and serves them through a local transcode API that mirrors the production endpoint structure.
|
|
27
|
+
|
|
28
|
+
## How It Works
|
|
29
|
+
|
|
30
|
+
When a video is first requested, the plugin:
|
|
31
|
+
|
|
32
|
+
1. Generates a **fragment index** describing every track (video, audio, scrub) with byte offsets and durations
|
|
33
|
+
2. Creates separated track files cached in the `cacheRoot` directory
|
|
34
|
+
3. Serves individual segments by streaming the correct byte ranges from cached track files
|
|
35
|
+
|
|
36
|
+
Subsequent requests for the same video skip transcoding entirely and serve directly from cache.
|
|
37
|
+
|
|
38
|
+
## Manifest Endpoint
|
|
39
|
+
|
|
40
|
+
The manifest describes available renditions and their segments:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
GET /api/v1/transcode/manifest.json?url=http://localhost:5173/src/assets/clip.mp4
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The response includes video renditions (`high`, `scrub`), audio renditions, per-segment duration arrays, codec strings, and endpoint templates for fetching init and media segments.
|
|
47
|
+
|
|
48
|
+
## Segment Serving
|
|
49
|
+
|
|
50
|
+
Init segments and media segments are served by extracting byte ranges from the cached track file:
|
|
51
|
+
|
|
52
|
+
```
|
|
53
|
+
GET /api/v1/transcode/high/init.mp4?url=... # Initialization segment
|
|
54
|
+
GET /api/v1/transcode/high/1.m4s?url=... # Fragment (moof+mdat only)
|
|
55
|
+
GET /api/v1/transcode/high/1.mp4?url=... # Standalone playable (init+moof+mdat)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `.m4s` extension returns raw fragments for streaming playback. The `.mp4` extension prepends the init segment so the file is independently playable, which is useful for testing.
|
|
59
|
+
|
|
60
|
+
## Renditions
|
|
61
|
+
|
|
62
|
+
The plugin creates three rendition types from each video:
|
|
63
|
+
|
|
64
|
+
- **high** -- Full resolution video track (track ID 1)
|
|
65
|
+
- **scrub** -- Low-resolution 320px-wide video for timeline scrubbing (track ID -1)
|
|
66
|
+
- **audio** -- Audio track extracted separately (track ID 2, or track ID 1 for audio-only files)
|
|
67
|
+
|
|
68
|
+
## Cache Management
|
|
69
|
+
|
|
70
|
+
Transcoded assets are stored under `{cacheRoot}/.cache/`. To clear the cache programmatically:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
DELETE /@ef-clear-cache/
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The cache clear uses retry logic with backoff to handle race conditions during concurrent test runs. ENOENT errors are treated as success (cache already cleared), and ENOTEMPTY errors trigger retries.
|
|
77
|
+
|
|
78
|
+
## Remote URL Support
|
|
79
|
+
|
|
80
|
+
The `url` parameter can reference either local or remote files. The plugin resolves the URL by checking the hostname:
|
|
81
|
+
|
|
82
|
+
- **Local URLs** (localhost, 127.0.0.1, *.localhost) are resolved to file paths relative to `root`
|
|
83
|
+
- **Remote URLs** are passed directly to ffprobe, which supports HTTP/HTTPS natively
|
|
84
|
+
|
|
85
|
+
## Debug Logging
|
|
86
|
+
|
|
87
|
+
Enable debug output for the transcode middleware:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
DEBUG=ef:vite-plugin:jit npm run dev
|
|
91
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Local Assets API
|
|
3
|
+
description: Local development endpoints for asset management, image thumbnail caching, and automatic caption file generation.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Features"
|
|
7
|
+
priority: 30
|
|
8
|
+
api:
|
|
9
|
+
endpoints:
|
|
10
|
+
- path: /api/v1/assets/image
|
|
11
|
+
method: GET
|
|
12
|
+
description: Caches and serves a local or remote image file
|
|
13
|
+
- path: /api/v1/assets/captions
|
|
14
|
+
method: GET
|
|
15
|
+
description: Generates or retrieves cached captions for an audio/video file
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
# Local Assets API
|
|
19
|
+
|
|
20
|
+
The plugin serves local images and captions through endpoints that mirror the production asset API. This allows compositions to use the same asset-fetching logic in both development and production without conditional paths.
|
|
21
|
+
|
|
22
|
+
## Image Caching
|
|
23
|
+
|
|
24
|
+
The image endpoint caches and serves image files with proper MIME types and ETags:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
GET /api/v1/assets/image?src=assets/background.png
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The `src` parameter accepts both local paths (resolved relative to the plugin `root` directory) and remote `http`/`https` URLs. Remote images are fetched server-side and returned as same-origin responses, preventing canvas CORS taint when compositions serialize to image. Local files are processed through `cacheImage(cacheRoot, absolutePath)` and served with an MD5-based ETag.
|
|
31
|
+
|
|
32
|
+
## Caption Generation
|
|
33
|
+
|
|
34
|
+
The captions endpoint generates or retrieves cached transcription data for audio and video files:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
GET /api/v1/assets/captions?src=assets/interview.mp4
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
This calls `findOrCreateCaptions(cacheRoot, absolutePath)` which either returns existing cached captions or generates new ones using the assets package transcription pipeline. The result is served as JSON with cache headers.
|
|
41
|
+
|
|
42
|
+
## Path Resolution
|
|
43
|
+
|
|
44
|
+
All `src` parameters follow the same resolution logic:
|
|
45
|
+
|
|
46
|
+
1. If `src` starts with `http://` or `https://`, it is fetched server-side and proxied to the browser as same-origin
|
|
47
|
+
2. Otherwise, `src` is joined with the plugin `root` option
|
|
48
|
+
3. Any `dist/` prefix in the resolved path is replaced with `src/` to support source-mapped development
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
// Example: root = "./dev-projects/src"
|
|
52
|
+
// src = "assets/photo.jpg"
|
|
53
|
+
// Resolved: ./dev-projects/src/assets/photo.jpg
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Response Format
|
|
57
|
+
|
|
58
|
+
All asset responses are streamed from the cache with:
|
|
59
|
+
|
|
60
|
+
- **Content-Type** determined by file extension via the `mime` package
|
|
61
|
+
- **ETag** set to the MD5 hash of the cached file
|
|
62
|
+
- **Cache-Control** set to `max-age=3600`
|
|
63
|
+
- **Range request** support for partial content (HTTP 206)
|
|
64
|
+
|
|
65
|
+
## Error Handling
|
|
66
|
+
|
|
67
|
+
- Missing `src` parameter returns `400` with `{ error: "src parameter is required" }`
|
|
68
|
+
- File not found returns `404` with plain text body
|
|
69
|
+
- Other errors return `500` with `{ error: "..." }` JSON
|
|
70
|
+
|
|
71
|
+
## Debug Logging
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
DEBUG=ef:vite-plugin:assets npm run dev
|
|
75
|
+
```
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Visual Testing
|
|
3
|
+
description: Automated visual regression testing for Editframe compositions, comparing rendered frames against stored baseline images.
|
|
4
|
+
type: reference
|
|
5
|
+
nav:
|
|
6
|
+
parent: "Features"
|
|
7
|
+
priority: 50
|
|
8
|
+
api:
|
|
9
|
+
endpoints:
|
|
10
|
+
- path: "/@ef-write-snapshot"
|
|
11
|
+
method: POST
|
|
12
|
+
description: Writes a snapshot image (baseline or actual) to disk
|
|
13
|
+
- path: "/@ef-compare-snapshot"
|
|
14
|
+
method: POST
|
|
15
|
+
description: Compares a screenshot against a stored baseline using odiff
|
|
16
|
+
- path: "/@ef-compare-two-images"
|
|
17
|
+
method: POST
|
|
18
|
+
description: Compares two arbitrary images using odiff
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# Visual Testing
|
|
22
|
+
|
|
23
|
+
The Vitest entry point (`@editframe/vite-plugin/src/index.vitest.js`) adds server-side image comparison endpoints powered by [odiff-bin](https://github.com/nicolo-ribaudo/odiff-bin). Tests running in the browser capture screenshots and POST them to the Vite server, which performs pixel-level comparison on the server where native binaries are available.
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
Use the Vitest-specific import in your `vitest.config.ts`:
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { defineConfig } from "vitest/config";
|
|
31
|
+
|
|
32
|
+
export default defineConfig(async () => {
|
|
33
|
+
const { vitePluginEditframe } = await import(
|
|
34
|
+
"@editframe/vite-plugin/src/index.vitest.js"
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return {
|
|
38
|
+
plugins: [
|
|
39
|
+
vitePluginEditframe({
|
|
40
|
+
root: "./test-assets",
|
|
41
|
+
cacheRoot: "./test-assets",
|
|
42
|
+
}),
|
|
43
|
+
],
|
|
44
|
+
test: {
|
|
45
|
+
browser: {
|
|
46
|
+
enabled: true,
|
|
47
|
+
provider: "playwright",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
});
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Snapshot Comparison
|
|
55
|
+
|
|
56
|
+
The `/@ef-compare-snapshot` endpoint compares a screenshot against a stored baseline:
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
const response = await fetch("/@ef-compare-snapshot", {
|
|
60
|
+
method: "POST",
|
|
61
|
+
body: JSON.stringify({
|
|
62
|
+
testName: "my-component",
|
|
63
|
+
snapshotName: "default-state",
|
|
64
|
+
dataUrl: canvas.toDataURL("image/png"),
|
|
65
|
+
threshold: 0.1,
|
|
66
|
+
antialiasing: true,
|
|
67
|
+
acceptableDiffPercentage: 1.0,
|
|
68
|
+
}),
|
|
69
|
+
});
|
|
70
|
+
const result = await response.json();
|
|
71
|
+
// { match: true, diffCount: 0, diffPercentage: 0 }
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### First Run Behavior
|
|
75
|
+
|
|
76
|
+
When no baseline exists, the actual image is automatically saved as the baseline and the comparison returns `{ match: true, baselineCreated: true }`. Subsequent runs compare against this stored baseline.
|
|
77
|
+
|
|
78
|
+
### Comparison Parameters
|
|
79
|
+
|
|
80
|
+
- **threshold** (default `0.1`) -- Color distance threshold passed to odiff. Lower values are stricter.
|
|
81
|
+
- **antialiasing** (default `true`) -- When true, odiff ignores antialiasing differences between images.
|
|
82
|
+
- **acceptableDiffPercentage** (default `1.0`) -- Maximum percentage of differing pixels before the comparison is considered a failure.
|
|
83
|
+
|
|
84
|
+
## Two-Image Comparison
|
|
85
|
+
|
|
86
|
+
The `/@ef-compare-two-images` endpoint compares any two images without baseline management:
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
const response = await fetch("/@ef-compare-two-images", {
|
|
90
|
+
method: "POST",
|
|
91
|
+
body: JSON.stringify({
|
|
92
|
+
testName: "animation-test",
|
|
93
|
+
comparisonName: "frame-1-vs-frame-2",
|
|
94
|
+
dataUrl1: frame1Canvas.toDataURL("image/png"),
|
|
95
|
+
dataUrl2: frame2Canvas.toDataURL("image/png"),
|
|
96
|
+
threshold: 0.1,
|
|
97
|
+
acceptableDiffPercentage: 5.0,
|
|
98
|
+
}),
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Both images are written to the snapshot directory and compared with odiff. This is useful for verifying that two frames of an animation are visually distinct or within tolerance.
|
|
103
|
+
|
|
104
|
+
## Snapshot Storage
|
|
105
|
+
|
|
106
|
+
Snapshots are stored under `{root}/test/__snapshots__/{testName}/`:
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
test/__snapshots__/my-component/
|
|
110
|
+
default-state.baseline.png # Reference image
|
|
111
|
+
default-state.actual.png # Latest capture
|
|
112
|
+
default-state.diff.png # Pixel diff (generated on mismatch)
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
The `/@ef-write-snapshot` endpoint can write a baseline or actual image directly:
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
await fetch("/@ef-write-snapshot", {
|
|
119
|
+
method: "POST",
|
|
120
|
+
body: JSON.stringify({
|
|
121
|
+
testName: "my-component",
|
|
122
|
+
snapshotName: "default-state",
|
|
123
|
+
dataUrl: canvas.toDataURL("image/png"),
|
|
124
|
+
isBaseline: true,
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Diff Output
|
|
130
|
+
|
|
131
|
+
When images differ beyond the acceptable threshold, odiff generates a diff image highlighting changed pixels. The response includes:
|
|
132
|
+
|
|
133
|
+
- **match** -- `false` when the diff exceeds the threshold
|
|
134
|
+
- **diffCount** -- Total number of differing pixels
|
|
135
|
+
- **diffPercentage** -- Percentage of the image area that differs
|
|
136
|
+
- **error** -- Set to `"Images have different dimensions"` when a layout diff is detected
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: editframe-webhooks
|
|
3
|
+
title: Webhooks
|
|
4
|
+
description: Webhook notifications for render completion and file processing events. Configure endpoints, verify HMAC signatures, and handle real-time status payloads.
|
|
5
|
+
order: 35
|
|
6
|
+
license: MIT
|
|
7
|
+
metadata:
|
|
8
|
+
author: editframe
|
|
9
|
+
version: "2.0"
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# Webhooks
|
|
13
|
+
|
|
14
|
+
Receive real-time HTTP notifications when renders complete, files finish processing, or other asynchronous events occur in your Editframe account.
|
|
15
|
+
|
|
16
|
+
## Setup
|
|
17
|
+
|
|
18
|
+
Webhooks are configured on an API key, not separately. The webhook URL and events you want to receive are set at API key creation time.
|
|
19
|
+
|
|
20
|
+
**Step 1**: Create an API key with webhook configuration via the Editframe dashboard (editframe.com → API Keys → Create), or via your application's API key management endpoint. The dashboard returns a webhook secret — store it securely.
|
|
21
|
+
|
|
22
|
+
**Step 2**: Handle webhook requests:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
// 3. Handle webhook requests
|
|
26
|
+
app.post("/webhooks/editframe", async (req, res) => {
|
|
27
|
+
const signature = req.headers["x-webhook-signature"];
|
|
28
|
+
const payload = JSON.stringify(req.body);
|
|
29
|
+
const webhookSecret = process.env.EDITFRAME_WEBHOOK_SECRET;
|
|
30
|
+
|
|
31
|
+
// Verify signature — always verify before processing
|
|
32
|
+
const expectedSignature = crypto
|
|
33
|
+
.createHmac("sha256", webhookSecret)
|
|
34
|
+
.update(payload)
|
|
35
|
+
.digest("hex");
|
|
36
|
+
|
|
37
|
+
if (!crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expectedSignature))) {
|
|
38
|
+
return res.status(401).send("Invalid signature");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Respond quickly, process asynchronously
|
|
42
|
+
res.status(200).send("OK");
|
|
43
|
+
|
|
44
|
+
const { topic, data } = req.body;
|
|
45
|
+
if (topic === "render.completed") {
|
|
46
|
+
console.log(`Render ${data.id} completed. Download: ${data.download_url}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Critical:** Hash the raw request body string (`JSON.stringify(req.body)`), not the parsed object. Use `timingSafeEqual` to prevent timing attacks.
|
|
52
|
+
|
|
53
|
+
## Event Topics
|
|
54
|
+
|
|
55
|
+
Webhooks are triggered for specific event topics:
|
|
56
|
+
|
|
57
|
+
### Render Events
|
|
58
|
+
- `render.created` — Render job created
|
|
59
|
+
- `render.pending` — Render queued for processing
|
|
60
|
+
- `render.rendering` — Render is actively processing
|
|
61
|
+
- `render.completed` — Render successfully finished
|
|
62
|
+
- `render.failed` — Render encountered an error
|
|
63
|
+
|
|
64
|
+
### File Events
|
|
65
|
+
- `file.created` — File record created
|
|
66
|
+
- `file.uploading` — File is being uploaded
|
|
67
|
+
- `file.processing` — File is being processed (video only)
|
|
68
|
+
- `file.ready` — File is ready for use
|
|
69
|
+
- `file.failed` — File processing failed
|
|
70
|
+
|
|
71
|
+
### Legacy Events
|
|
72
|
+
- `unprocessed_file.created` — Unprocessed file created (deprecated)
|
|
73
|
+
|
|
74
|
+
## Configuration
|
|
75
|
+
|
|
76
|
+
Configure webhooks when creating or updating an API key:
|
|
77
|
+
|
|
78
|
+
**Webhook URL**: The HTTPS endpoint where Editframe will send POST requests
|
|
79
|
+
**Webhook Events**: Array of event topics you want to receive
|
|
80
|
+
**Webhook Secret**: Auto-generated HMAC secret for signature verification
|
|
81
|
+
|
|
82
|
+
See [references/getting-started.md](references/getting-started.md) for detailed setup instructions.
|
|
83
|
+
|
|
84
|
+
## Security
|
|
85
|
+
|
|
86
|
+
All webhook requests include an `X-Webhook-Signature` header containing an HMAC-SHA256 signature. Always verify this signature before processing webhook payloads.
|
|
87
|
+
|
|
88
|
+
See [references/security.md](references/security.md) for signature verification implementation.
|
|
89
|
+
|
|
90
|
+
## Delivery Guarantees
|
|
91
|
+
|
|
92
|
+
- Webhooks are delivered via HTTP POST with JSON payload
|
|
93
|
+
- Automatic retry with exponential backoff (3 attempts)
|
|
94
|
+
- 30-second timeout per attempt
|
|
95
|
+
- Events marked as failed after retry exhaustion
|
|
96
|
+
- Delivery history tracked for debugging
|
|
97
|
+
|
|
98
|
+
## Testing
|
|
99
|
+
|
|
100
|
+
Test your webhook endpoint before going live:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# Use the Editframe dashboard to send test webhooks
|
|
104
|
+
# Or trigger test events via the API
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
See [references/testing.md](references/testing.md) for testing strategies including local development with ngrok.
|
|
108
|
+
|
|
109
|
+
## Troubleshooting
|
|
110
|
+
|
|
111
|
+
Common issues and solutions:
|
|
112
|
+
|
|
113
|
+
- **Signature verification fails**: Ensure you're hashing the raw request body, not parsed JSON
|
|
114
|
+
- **Timeout errors**: Respond with 200 OK quickly, process events asynchronously
|
|
115
|
+
- **Missed webhooks**: Check delivery logs in the Editframe dashboard
|
|
116
|
+
- **Duplicate events**: Implement idempotency using event IDs
|
|
117
|
+
|
|
118
|
+
See [references/troubleshooting.md](references/troubleshooting.md) for detailed debugging guidance.
|
|
119
|
+
|
|
120
|
+
## Reference Documentation
|
|
121
|
+
|
|
122
|
+
- [references/getting-started.md](references/getting-started.md) — Set up your first webhook
|
|
123
|
+
- [references/events.md](references/events.md) — Event types and payload structures
|
|
124
|
+
- [references/security.md](references/security.md) — HMAC signature verification
|
|
125
|
+
- [references/testing.md](references/testing.md) — Test webhooks locally and in production
|
|
126
|
+
- [references/troubleshooting.md](references/troubleshooting.md) — Debug common issues
|