@bozonx/fastcat-embed 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ivan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,213 @@
1
+ # @bozonx/fastcat-embed
2
+
3
+ Official JavaScript / TypeScript SDK for embedding the **FastCat Video Editor** into any web application through an isolated cross-origin iframe.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@bozonx/fastcat-embed.svg)](https://www.npmjs.com/package/@bozonx/fastcat-embed)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
7
+
8
+ ---
9
+
10
+ ## Overview
11
+
12
+ `@bozonx/fastcat-embed` is a zero-dependency, lightweight host-side library that manages the lifecycle of the FastCat editor iframe, handles cryptographic origin and nonce verification, and provides a strictly typed message boundary between your host application and the editor.
13
+
14
+ The editor itself runs in an isolated iframe (hosted on your domain or FastCat Cloud), while your host page controls initial configuration, media feeding, export triggers, and event listening.
15
+
16
+ ---
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ # npm
22
+ npm install @bozonx/fastcat-embed
23
+
24
+ # pnpm
25
+ pnpm add @bozonx/fastcat-embed
26
+
27
+ # yarn
28
+ yarn add @bozonx/fastcat-embed
29
+ ```
30
+
31
+ ---
32
+
33
+ ## Quick Start
34
+
35
+ ```typescript
36
+ import { createFastcatEmbed, type FastcatEmbed } from '@bozonx/fastcat-embed';
37
+
38
+ const container = document.getElementById('editor-container')!;
39
+
40
+ const embed: FastcatEmbed = createFastcatEmbed({
41
+ container,
42
+ editorUrl: 'https://embed.fastcat.video/embed',
43
+ locale: 'en',
44
+ layout: 'desktop', // 'auto' | 'desktop' | 'mobile'
45
+ features: ['export', 'files', 'sound'],
46
+ assets: [
47
+ {
48
+ id: 'clip-1',
49
+ kind: 'video',
50
+ url: 'https://cdn.example.com/videos/intro.mp4',
51
+ filename: 'intro.mp4',
52
+ },
53
+ ],
54
+ onReady: (capabilities) => {
55
+ console.log('Editor ready with capabilities:', capabilities);
56
+ },
57
+ onChange: ({ dirty, otio }) => {
58
+ console.log('Timeline changed (unsaved draft):', { dirty, otio });
59
+ },
60
+ onExportProgress: ({ phase, progress }) => {
61
+ console.log(`Export progress (${phase}): ${Math.round(progress * 100)}%`);
62
+ },
63
+ onExportDone: async (result) => {
64
+ console.log('Export finished:', result.meta);
65
+ if (result.file) {
66
+ // Stream or upload the resulting File
67
+ const downloadUrl = URL.createObjectURL(result.file);
68
+ window.open(downloadUrl);
69
+ }
70
+ },
71
+ onError: (err) => {
72
+ console.error('Editor error:', err);
73
+ },
74
+ });
75
+
76
+ // Programmatic actions
77
+ await embed.ready;
78
+ await embed.initialized;
79
+ // embed.startExport({ filename: 'my-video.mp4' });
80
+ // embed.addAssets([{ url: 'https://cdn.example.com/audio.mp3', kind: 'audio' }]);
81
+ // await embed.dispose();
82
+ ```
83
+
84
+ ---
85
+
86
+ ## API Reference
87
+
88
+ ### `createFastcatEmbed(options: FastcatEmbedOptions): FastcatEmbed`
89
+
90
+ Mounts the editor iframe into `options.container`, initiates the secure handshake, and returns a controller handle.
91
+
92
+ #### `FastcatEmbedOptions`
93
+
94
+ | Option | Type | Default | Description |
95
+ | :---------------- | :-------------------------------- | :-------------------- | :--------------------------------------------------------------------------------------- |
96
+ | `container` | `HTMLElement` | _required_ | The DOM element where the iframe is appended. |
97
+ | `editorUrl` | `string` | _required_ | Absolute URL of the editor embed route (e.g. `https://embed.fastcat.video/embed`). |
98
+ | `assets` | `EmbedAsset[]` | `[]` | Initial media assets loaded into the editor session. |
99
+ | `locale` | `string` | `'en'` | Interface language code (e.g. `'en'`, `'ru'`). |
100
+ | `layout` | `'auto' \| 'desktop' \| 'mobile'` | `'auto'` | Preferred editor layout. `'auto'` selects automatically on first render. |
101
+ | `features` | `EmbedFeatureName[]` | `['export']` | Enabled feature panels: `'files'`, `'sound'`, `'export'`, `'settings'`. |
102
+ | `projectDefaults` | `EmbedProjectDefaults` | `undefined` | Composition dimensions, FPS, and sample rate overrides. |
103
+ | `assetTransport` | `'url' \| 'host'` | `'url'` | `'url'` streams assets via HTTP range requests; `'host'` uses in-memory transfers. |
104
+ | `output` | `'blob' \| 'upload'` | `'blob'` | `'blob'` returns `File` in `onExportDone`; `'upload'` streams directly to presigned URL. |
105
+ | `initialProject` | `{ otio: string }` | `undefined` | Optional previous OTIO document restored before initial assets. |
106
+ | `preferences` | `unknown` | `undefined` | Opaque state from a previous session (`onPreferencesChanged`). |
107
+ | `readyTimeoutMs` | `number` | `20000` | Timeout in milliseconds before `onUnavailable` is called. |
108
+ | `sandbox` | `string` | `undefined` | Custom iframe `sandbox` attribute value if needed. |
109
+ | `allow` | `string` | `DEFAULT_EMBED_ALLOW` | Iframe feature policy (`fullscreen; clipboard-write; autoplay; ...`). |
110
+
111
+ #### Event Callbacks
112
+
113
+ | Callback | Signature | Description |
114
+ | :--------------------- | :----------------------------------------------------------------------------------------- | :----------------------------------------------------------------------------- |
115
+ | `onReady` | `(capabilities: EmbedCapabilities) => void` | Called after handshake confirms hardware capabilities (WebGPU, OPFS, etc.). |
116
+ | `onInitialized` | `(info: EmbedInitializedInfo) => void` | Called once initial assets and timeline are loaded. |
117
+ | `onChange` | `(change: { dirty: boolean; otio: string }) => void` | Emitted when timeline edits occur. Save `otio` to preserve user draft. |
118
+ | `onExportProgress` | `(progress: { phase: string \| null; progress: number }) => void` | Real-time rendering progress updates. |
119
+ | `onExportDone` | `(result: FastcatEmbedExportResult) => void \| Promise<void>` | Export completed. Contains output `file`, `poster`, `otio`, and `meta`. |
120
+ | `onAssetProgress` | `(progress: { assetId: string; loadedBytes: number; totalBytes: number \| null }) => void` | Asset buffering and fetch progress. |
121
+ | `onAssetUrlExpired` | `(assetId: string) => Promise<string> \| string` | Invoked when signed asset URL expires mid-session. Return fresh URL to resume. |
122
+ | `onPreferencesChanged` | `(preferences: unknown) => void` | Opaque user settings to store in host database. |
123
+ | `onSttRequest` | `(payload: unknown) => Promise<unknown>` | Handle speech-to-text proxy requests using host credentials. |
124
+ | `onLlmRequest` | `(payload: unknown) => Promise<unknown>` | Handle LLM/AI requests using host credentials. |
125
+ | `onError` | `(error: { code: string; message: string }) => void` | Error notification from editor. |
126
+ | `onRequestClose` | `() => void` | User clicked the close/exit button inside the editor. |
127
+ | `onResizeRequest` | `(request: { minHeightPx: number }) => void` | Advisory request for more vertical viewport space. |
128
+ | `onUnavailable` | `(reason: string) => void` | Handshake timed out or protocol version mismatch. |
129
+ | `onDebug` | `(direction: 'in' \| 'out', type: string, payload: unknown) => void` | Low-level message logger for debugging. |
130
+
131
+ ---
132
+
133
+ ### Instance Methods (`FastcatEmbed`)
134
+
135
+ ```typescript
136
+ export interface FastcatEmbed {
137
+ /** The created HTMLIFrameElement mounted in container. */
138
+ readonly iframe: HTMLIFrameElement;
139
+ /** Triggers video rendering. */
140
+ startExport: (options?: { filename?: string; uploadUrl?: string }) => void;
141
+ /** Cancels an ongoing render. */
142
+ cancelExport: () => void;
143
+ /** Adds new assets into an active session. */
144
+ addAssets: (assets: EmbedAsset[]) => void;
145
+ /** Requests the editor to emit current timeline immediately (bypassing debounce). */
146
+ requestSave: () => void;
147
+ /** Gracefully tears down iframe and cleans up storage. */
148
+ dispose: () => Promise<void>;
149
+ }
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Direct Protocol Import
155
+
156
+ If you are building custom host adapters and only need types and message envelope utilities:
157
+
158
+ ```typescript
159
+ import {
160
+ EMBED_PROTOCOL_VERSION,
161
+ buildEmbedUrl,
162
+ createEmbedNonce,
163
+ isEmbedEnvelope,
164
+ type EmbedAsset,
165
+ type EmbedCapabilities,
166
+ type HostToEditorMessages,
167
+ type EditorToHostMessages,
168
+ } from '@bozonx/fastcat-embed/protocol';
169
+ ```
170
+
171
+ ---
172
+
173
+ ## Security & Architecture
174
+
175
+ 1. **Origin Verification & Cryptographic Nonce**:
176
+ During initialization, `@bozonx/fastcat-embed` generates a 128-bit cryptographic nonce and supplies the host origin via URL hash parameters. Both the host and the editor verify each other's origins and nonce on every `postMessage` envelope.
177
+ 2. **Iframe Isolation**:
178
+ The host application does not require cross-origin isolation (COOP/COEP headers), making integration safe for host sites that load third-party scripts.
179
+ 3. **Hardware Acceleration**:
180
+ The editor utilizes WebGPU, WebCodecs, and OPFS for real-time timeline compositing and zero-lag rendering.
181
+
182
+ The lifecycle is `creating → ready → initialized → active/exporting → disposing → disposed`.
183
+ Handshake and initialization failures move to `unavailable`; commands before `active` reject
184
+ with a stable `protocol-invalid-state` error. `dispose()` is idempotent and cancels outstanding
185
+ session work. Invalid payloads, unknown messages, and protocol version mismatches are reported
186
+ as stable `protocol-*` errors rather than silently becoming a timeout.
187
+
188
+ Asset URLs and upload URLs must use HTTP(S), filenames must be plain basenames, and initial and
189
+ added assets are limited in count and size. Asset servers need CORS; `Range` support is strongly
190
+ recommended, while a range-blind HTTP 200 response is consumed once as a fallback. Use short-lived
191
+ signed URLs and refresh them through `onAssetUrlExpired`; upload endpoints must accept `PUT`.
192
+
193
+ The SDK does not enable `sandbox` by default: an opaque sandbox origin breaks OPFS. If a host
194
+ requires it, test `allow-scripts allow-same-origin` plus the configured permissions in target
195
+ browsers. The editor deployment must set its own `frame-ancestors`, `connect-src`, and
196
+ `Permissions-Policy`; a client SDK cannot enforce response headers for another origin.
197
+
198
+ ---
199
+
200
+ ## Browser Support
201
+
202
+ | Browser | Supported Versions | Notes |
203
+ | :--------------------------- | :----------------- | :-------------------------------------------------- |
204
+ | **Google Chrome / Chromium** | 113+ | Full WebGPU + WebCodecs hardware acceleration |
205
+ | **Microsoft Edge** | 113+ | Full WebGPU + WebCodecs hardware acceleration |
206
+ | **Apple Safari** | 17+ | WebCodecs + WebGPU support |
207
+ | **Mozilla Firefox** | 120+ | WebCodecs enabled; WebGPU subject to platform flags |
208
+
209
+ ---
210
+
211
+ ## License
212
+
213
+ [MIT](LICENSE) © FastCat Team
@@ -0,0 +1,66 @@
1
+ import { type EditorToHostMessages, type EmbedAsset, type EmbedCapabilities, type EmbedExportMeta, type EmbedAssetTransportKind, type EmbedFeatureName, type EmbedLayoutPreference, type EmbedOutputMode, type EmbedProjectDefaults } from './protocol.js';
2
+ export * from './protocol.js';
3
+ export interface FastcatEmbedExportResult {
4
+ file?: File;
5
+ poster: Blob | null;
6
+ otio: string;
7
+ meta: EmbedExportMeta;
8
+ }
9
+ export type FastcatEmbedState = 'creating' | 'ready' | 'initialized' | 'active' | 'exporting' | 'disposing' | 'disposed' | 'unavailable' | 'error';
10
+ export declare const DEFAULT_EMBED_ALLOW = "fullscreen; clipboard-read; clipboard-write; autoplay; cross-origin-isolated";
11
+ export interface FastcatEmbedOptions {
12
+ container: HTMLElement;
13
+ editorUrl: string;
14
+ allow?: string;
15
+ /** Sandboxing with an opaque origin is incompatible with OPFS. */
16
+ sandbox?: string;
17
+ assets?: EmbedAsset[];
18
+ locale?: string;
19
+ preferences?: unknown;
20
+ layout?: EmbedLayoutPreference;
21
+ features?: EmbedFeatureName[];
22
+ projectDefaults?: EmbedProjectDefaults;
23
+ initialProject?: {
24
+ otio: string;
25
+ };
26
+ assetTransport?: EmbedAssetTransportKind;
27
+ output?: EmbedOutputMode;
28
+ readyTimeoutMs?: number;
29
+ initializedTimeoutMs?: number;
30
+ rpcTimeoutMs?: number;
31
+ exportAckTimeoutMs?: number;
32
+ onReady?: (capabilities: EmbedCapabilities) => void;
33
+ onInitialized?: (info: EditorToHostMessages['initialized']) => void;
34
+ onExportProgress?: (progress: EditorToHostMessages['export:progress']) => void;
35
+ onAssetProgress?: (progress: EditorToHostMessages['asset:progress']) => void;
36
+ onAssetUrlExpired?: (assetId: string) => Promise<string> | string;
37
+ onChange?: (change: EditorToHostMessages['change']) => void;
38
+ onPreferencesChanged?: (preferences: unknown) => void;
39
+ onSttRequest?: (payload: unknown) => Promise<unknown>;
40
+ onLlmRequest?: (payload: unknown) => Promise<unknown>;
41
+ onExportDone?: (result: FastcatEmbedExportResult) => void | Promise<void>;
42
+ onError?: (error: {
43
+ code: string;
44
+ message: string;
45
+ }) => void;
46
+ onRequestClose?: () => void;
47
+ onResizeRequest?: (request: EditorToHostMessages['resize-request']) => void;
48
+ onUnavailable?: (reason: string) => void;
49
+ onDebug?: (direction: 'in' | 'out', type: string, payload: unknown) => void;
50
+ }
51
+ export interface FastcatEmbed {
52
+ readonly iframe: HTMLIFrameElement;
53
+ readonly state: FastcatEmbedState;
54
+ readonly ready: Promise<EmbedCapabilities>;
55
+ readonly initialized: Promise<EditorToHostMessages['initialized']>;
56
+ startExport: (options?: {
57
+ filename?: string;
58
+ uploadUrl?: string;
59
+ }) => void;
60
+ cancelExport: () => void;
61
+ addAssets: (assets: EmbedAsset[]) => void;
62
+ requestSave: () => void;
63
+ dispose: () => Promise<void>;
64
+ }
65
+ export declare function createFastcatEmbed(options: FastcatEmbedOptions): FastcatEmbed;
66
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,254 @@
1
+ import { buildEmbedUrl, createEmbedNonce, createEnvelope, hasEmbedProtocolVersion, isEmbedEnvelope, isSafeEmbedFilename, validateEmbedMessage, EMBED_PROTOCOL_VERSION, } from './protocol.js';
2
+ export * from './protocol.js';
3
+ export const DEFAULT_EMBED_ALLOW = 'fullscreen; clipboard-read; clipboard-write; autoplay; cross-origin-isolated';
4
+ const DEFAULT_READY_TIMEOUT_MS = 20_000;
5
+ const DEFAULT_INITIALIZED_TIMEOUT_MS = 60_000;
6
+ const DEFAULT_EXPORT_ACK_TIMEOUT_MS = 30_000;
7
+ const DISPOSE_TIMEOUT_MS = 5_000;
8
+ function deferred() {
9
+ let resolve;
10
+ let reject;
11
+ const promise = new Promise((resolvePromise, rejectPromise) => {
12
+ resolve = resolvePromise;
13
+ reject = rejectPromise;
14
+ });
15
+ // Consumers can still await/reject this promise; this internal observer only
16
+ // prevents an optional lifecycle promise from becoming an unhandled rejection.
17
+ void promise.catch(() => undefined);
18
+ return { promise, resolve, reject };
19
+ }
20
+ export function createFastcatEmbed(options) {
21
+ const nonce = createEmbedNonce();
22
+ const editorOrigin = new URL(options.editorUrl, window.location.href).origin;
23
+ const iframe = document.createElement('iframe');
24
+ iframe.src = buildEmbedUrl(options.editorUrl, { nonce, hostOrigin: window.location.origin });
25
+ iframe.allow = options.allow ?? DEFAULT_EMBED_ALLOW;
26
+ if (options.sandbox)
27
+ iframe.setAttribute('sandbox', options.sandbox);
28
+ iframe.style.cssText = 'width:100%;height:100%;border:0';
29
+ iframe.setAttribute('title', 'FastCat editor');
30
+ let state = 'creating';
31
+ let disposePromise = null;
32
+ let onDisposed = null;
33
+ let exportAckTimer = null;
34
+ const readyDeferred = deferred();
35
+ const initializedDeferred = deferred();
36
+ const readyTimer = window.setTimeout(() => unavailable('Handshake timed out.'), options.readyTimeoutMs ?? DEFAULT_READY_TIMEOUT_MS);
37
+ let initializedTimer = null;
38
+ function report(code, message) {
39
+ safeCallback('onError', () => options.onError?.({ code, message }));
40
+ }
41
+ function safeCallback(name, callback) {
42
+ try {
43
+ const result = callback();
44
+ if (result && typeof result.catch === 'function') {
45
+ void result.catch((error) => report('protocol-callback-failed', `${name}: ${String(error)}`));
46
+ }
47
+ }
48
+ catch (error) {
49
+ // Do not allow host code to escape the message handler.
50
+ if (name !== 'onError')
51
+ report('protocol-callback-failed', `${name}: ${String(error)}`);
52
+ }
53
+ }
54
+ function unavailable(reason) {
55
+ if (state === 'disposed' || state === 'disposing' || state === 'unavailable')
56
+ return;
57
+ state = 'unavailable';
58
+ window.clearTimeout(readyTimer);
59
+ if (initializedTimer)
60
+ window.clearTimeout(initializedTimer);
61
+ readyDeferred.reject(new Error(reason));
62
+ initializedDeferred.reject(new Error(reason));
63
+ safeCallback('onUnavailable', () => options.onUnavailable?.(reason));
64
+ }
65
+ function ensureState(action, allowed) {
66
+ if (!allowed.includes(state)) {
67
+ throw new Error(`protocol-invalid-state: Cannot ${action} while SDK is ${state}.`);
68
+ }
69
+ }
70
+ function send(type, payload) {
71
+ const validation = validateEmbedMessage('host', type, payload);
72
+ if (!validation.ok)
73
+ throw new Error(`${validation.code}: ${validation.message}`);
74
+ safeCallback('onDebug', () => options.onDebug?.('out', type, payload));
75
+ iframe.contentWindow?.postMessage(createEnvelope(nonce, type, payload), editorOrigin);
76
+ }
77
+ async function handle(type, payload) {
78
+ const validation = validateEmbedMessage('editor', type, payload);
79
+ if (!validation.ok) {
80
+ report(validation.code, validation.message);
81
+ return;
82
+ }
83
+ switch (type) {
84
+ case 'ready': {
85
+ const ready = payload;
86
+ window.clearTimeout(readyTimer);
87
+ state = 'ready';
88
+ readyDeferred.resolve(ready.capabilities);
89
+ safeCallback('onReady', () => options.onReady?.(ready.capabilities));
90
+ send('init', {
91
+ locale: options.locale,
92
+ assets: options.assets,
93
+ layout: options.layout,
94
+ features: options.features,
95
+ preferences: options.preferences,
96
+ projectDefaults: options.projectDefaults,
97
+ initialProject: options.initialProject,
98
+ assetTransport: options.assetTransport,
99
+ output: options.output,
100
+ });
101
+ initializedTimer = window.setTimeout(() => unavailable('Editor initialization timed out.'), options.initializedTimeoutMs ?? DEFAULT_INITIALIZED_TIMEOUT_MS);
102
+ return;
103
+ }
104
+ case 'initialized':
105
+ if (initializedTimer)
106
+ window.clearTimeout(initializedTimer);
107
+ state = 'initialized';
108
+ initializedDeferred.resolve(payload);
109
+ safeCallback('onInitialized', () => options.onInitialized?.(payload));
110
+ state = 'active';
111
+ return;
112
+ case 'asset:progress':
113
+ return safeCallback('onAssetProgress', () => options.onAssetProgress?.(payload));
114
+ case 'export:progress':
115
+ return safeCallback('onExportProgress', () => options.onExportProgress?.(payload));
116
+ case 'change':
117
+ return safeCallback('onChange', () => options.onChange?.(payload));
118
+ case 'preferences:changed':
119
+ return safeCallback('onPreferencesChanged', () => options.onPreferencesChanged?.(payload));
120
+ case 'requestClose':
121
+ return safeCallback('onRequestClose', () => options.onRequestClose?.());
122
+ case 'resize-request':
123
+ return safeCallback('onResizeRequest', () => options.onResizeRequest?.(payload));
124
+ case 'error':
125
+ return report(payload.code, payload.message);
126
+ case 'export:error':
127
+ state = 'active';
128
+ return report('export-failed', payload.message);
129
+ case 'asset:url-expired': {
130
+ if (!options.onAssetUrlExpired)
131
+ return report('asset-url-expired', `No URL refresh handler for ${payload.assetId}`);
132
+ try {
133
+ const url = await options.onAssetUrlExpired(payload.assetId);
134
+ send('asset:url', { assetId: payload.assetId, url });
135
+ }
136
+ catch (error) {
137
+ report('protocol-callback-failed', `onAssetUrlExpired: ${String(error)}`);
138
+ }
139
+ return;
140
+ }
141
+ case 'stt:request':
142
+ case 'llm:request': {
143
+ const request = payload;
144
+ const handler = type === 'stt:request' ? options.onSttRequest : options.onLlmRequest;
145
+ if (!handler)
146
+ return send('rpc:result', {
147
+ requestId: request.requestId,
148
+ error: `The host does not handle ${type}`,
149
+ });
150
+ try {
151
+ send('rpc:result', {
152
+ requestId: request.requestId,
153
+ result: await handler(request.payload),
154
+ });
155
+ }
156
+ catch (error) {
157
+ send('rpc:result', { requestId: request.requestId, error: String(error) });
158
+ }
159
+ return;
160
+ }
161
+ case 'export:done': {
162
+ const result = payload;
163
+ state = 'exporting';
164
+ try {
165
+ await options.onExportDone?.(result);
166
+ }
167
+ catch (error) {
168
+ report('protocol-callback-failed', `onExportDone: ${String(error)}`);
169
+ }
170
+ // Ack is independent from dispose: calling dispose from onExportDone cannot await itself.
171
+ if (!['disposing', 'disposed'].includes(state)) {
172
+ send('export:ack', undefined);
173
+ exportAckTimer = window.setTimeout(() => report('protocol-timeout', 'Export acknowledgement timed out.'), options.exportAckTimeoutMs ?? DEFAULT_EXPORT_ACK_TIMEOUT_MS);
174
+ state = 'active';
175
+ }
176
+ return;
177
+ }
178
+ case 'disposed':
179
+ onDisposed?.();
180
+ return;
181
+ }
182
+ }
183
+ function onMessage(event) {
184
+ if (event.source !== iframe.contentWindow ||
185
+ event.origin !== editorOrigin ||
186
+ !isEmbedEnvelope(event.data, nonce))
187
+ return;
188
+ if (!hasEmbedProtocolVersion(event.data)) {
189
+ unavailable(`This editor speaks protocol v${event.data.version}; this SDK speaks v${EMBED_PROTOCOL_VERSION}.`);
190
+ return;
191
+ }
192
+ safeCallback('onDebug', () => options.onDebug?.('in', event.data.type, event.data.payload));
193
+ void handle(event.data.type, event.data.payload);
194
+ }
195
+ window.addEventListener('message', onMessage);
196
+ options.container.appendChild(iframe);
197
+ return {
198
+ iframe,
199
+ get state() {
200
+ return state;
201
+ },
202
+ ready: readyDeferred.promise,
203
+ initialized: initializedDeferred.promise,
204
+ startExport(exportOptions) {
205
+ ensureState('start an export', ['active']);
206
+ if (exportOptions?.filename && !isSafeEmbedFilename(exportOptions.filename))
207
+ throw new Error('protocol-invalid-payload: Invalid export filename.');
208
+ send('export:start', exportOptions);
209
+ state = 'exporting';
210
+ },
211
+ cancelExport() {
212
+ ensureState('cancel an export', ['exporting']);
213
+ send('export:cancel', undefined);
214
+ },
215
+ addAssets(assets) {
216
+ ensureState('add assets', ['active']);
217
+ send('asset:add', { assets });
218
+ },
219
+ requestSave() {
220
+ ensureState('request a save', ['initialized', 'active', 'exporting']);
221
+ send('save:request', undefined);
222
+ },
223
+ dispose() {
224
+ if (disposePromise)
225
+ return disposePromise;
226
+ disposePromise = (async () => {
227
+ state = 'disposing';
228
+ window.clearTimeout(readyTimer);
229
+ if (initializedTimer)
230
+ window.clearTimeout(initializedTimer);
231
+ if (exportAckTimer)
232
+ window.clearTimeout(exportAckTimer);
233
+ readyDeferred.reject(new Error('The embed was disposed before ready.'));
234
+ initializedDeferred.reject(new Error('The embed was disposed before initialization completed.'));
235
+ const farewell = new Promise((resolve) => {
236
+ onDisposed = resolve;
237
+ window.setTimeout(resolve, DISPOSE_TIMEOUT_MS);
238
+ });
239
+ try {
240
+ send('dispose', undefined);
241
+ await farewell;
242
+ }
243
+ finally {
244
+ onDisposed = null;
245
+ window.removeEventListener('message', onMessage);
246
+ iframe.remove();
247
+ state = 'disposed';
248
+ }
249
+ })();
250
+ return disposePromise;
251
+ },
252
+ };
253
+ }
254
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,256 @@
1
+ /**
2
+ * Wire contract between an embedding host page and the FastCat editor iframe.
3
+ *
4
+ * This module is published as part of `@bozonx/fastcat-embed` and is imported by the
5
+ * editor through the `~embed` alias, so both sides of the boundary always
6
+ * compile against the same definitions and can never drift apart.
7
+ */
8
+ export declare const EMBED_CHANNEL = "fastcat-embed";
9
+ export declare const EMBED_PROTOCOL_VERSION = 1;
10
+ export declare const MAX_EMBED_ASSETS = 100;
11
+ export declare const MAX_EMBED_ASSET_BYTES: number;
12
+ export declare const MAX_EMBED_EXPORT_BYTES: number;
13
+ /** Stable errors that may cross the host/editor boundary. */
14
+ export type EmbedProtocolErrorCode = 'protocol-invalid-envelope' | 'protocol-version-mismatch' | 'protocol-unknown-message' | 'protocol-invalid-payload' | 'protocol-invalid-state' | 'protocol-timeout' | 'protocol-cancelled' | 'protocol-callback-failed';
15
+ export interface EmbedCapabilities {
16
+ webgpu: boolean;
17
+ webcodecs: boolean;
18
+ opfs: boolean;
19
+ sharedArrayBuffer: boolean;
20
+ /** Storage the browser is willing to grant, when it will say. */
21
+ storageQuotaBytes: number | null;
22
+ }
23
+ export type EmbedAssetKind = 'video' | 'audio' | 'image';
24
+ export interface EmbedAsset {
25
+ id?: string;
26
+ /** Required for the `url` transport; ignored for `host`. */
27
+ url?: string;
28
+ /**
29
+ * The asset's bytes, when the host already holds them — a file the user just
30
+ * picked, or a source it cannot expose over CORS.
31
+ */
32
+ file?: File;
33
+ kind?: EmbedAssetKind;
34
+ filename?: string;
35
+ /** Existing timeline track id to place the asset on. */
36
+ track?: string;
37
+ /** Explicit insertion time in seconds. */
38
+ startAt?: number;
39
+ }
40
+ /** Optional capabilities a host switches on for the session. */
41
+ export type EmbedFeatureName = 'files' | 'sound' | 'export' | 'settings';
42
+ export type EmbedLayoutPreference = 'auto' | 'desktop' | 'mobile';
43
+ export interface EmbedInitPayload {
44
+ locale?: string;
45
+ assets?: EmbedAsset[];
46
+ /**
47
+ * `auto` (the default) decides once from the iframe's first measured size and
48
+ * never re-decides on its own: a shell that flipped mid-session would discard
49
+ * the user's arrangement every time the host resized its container.
50
+ */
51
+ layout?: EmbedLayoutPreference;
52
+ /**
53
+ * Anything beyond the timeline and an export must be asked for. Unknown names
54
+ * are ignored rather than rejected, so a newer host still talks to an older
55
+ * editor.
56
+ */
57
+ features?: EmbedFeatureName[];
58
+ /**
59
+ * Preferences this host stored from an earlier session, exactly as the editor
60
+ * emitted them. Opaque to the host: it keeps the blob, it does not read it.
61
+ */
62
+ preferences?: unknown;
63
+ /**
64
+ * Composition to start from — a host that knows it is producing a 9:16 story
65
+ * should say so, rather than letting the first clip decide.
66
+ */
67
+ projectDefaults?: EmbedProjectDefaults;
68
+ assetTransport?: EmbedAssetTransportKind;
69
+ output?: EmbedOutputMode;
70
+ /** A previously emitted OTIO document, restored before any new assets land. */
71
+ initialProject?: {
72
+ otio: string;
73
+ };
74
+ }
75
+ export interface EmbedExportMeta {
76
+ filename: string;
77
+ mimeType: string;
78
+ sizeBytes: number;
79
+ /** Read back off the finished file, so it always matches the actual bytes. */
80
+ width: number | null;
81
+ height: number | null;
82
+ durationMs: number | null;
83
+ fps: number | null;
84
+ }
85
+ /** Composition settings the host wants the session to start from. */
86
+ export interface EmbedProjectDefaults {
87
+ width?: number;
88
+ height?: number;
89
+ fps?: number;
90
+ sampleRate?: number;
91
+ }
92
+ /**
93
+ * How the editor gets at an asset's bytes. `url` reads directly over range
94
+ * requests and is what you want; `host` is for sources that cannot be exposed
95
+ * over CORS, or files the host already holds.
96
+ */
97
+ export type EmbedAssetTransportKind = 'url' | 'host';
98
+ /**
99
+ * Where a finished render goes. `blob` hands the file back over the channel;
100
+ * `upload` streams it to a presigned URL the host supplies, which keeps very
101
+ * large renders out of the message path entirely.
102
+ */
103
+ export type EmbedOutputMode = 'blob' | 'upload';
104
+ /** Messages the host is allowed to send to the editor. */
105
+ export interface HostToEditorMessages {
106
+ init: EmbedInitPayload;
107
+ /** Adds an asset to a session that is already running. */
108
+ 'asset:add': {
109
+ assets: EmbedAsset[];
110
+ };
111
+ /** A replacement URL for an asset whose signed URL expired. */
112
+ 'asset:url': {
113
+ assetId: string;
114
+ url: string;
115
+ };
116
+ /** Answer to a `stt:request` or `llm:request`, matched by `requestId`. */
117
+ 'rpc:result': {
118
+ requestId: string;
119
+ result?: unknown;
120
+ error?: string;
121
+ };
122
+ /** Asks the editor to emit the current timeline without waiting for a debounce. */
123
+ 'save:request': undefined;
124
+ 'export:start': {
125
+ filename?: string;
126
+ uploadUrl?: string;
127
+ } | undefined;
128
+ 'export:cancel': undefined;
129
+ 'export:ack': undefined;
130
+ dispose: undefined;
131
+ }
132
+ /** Messages the editor is allowed to send to the host. */
133
+ export interface EditorToHostMessages {
134
+ ready: {
135
+ version: number;
136
+ capabilities: EmbedCapabilities;
137
+ };
138
+ initialized: {
139
+ assetCount: number;
140
+ durationMs: number;
141
+ layout: 'desktop' | 'mobile';
142
+ /**
143
+ * Storage belonging to earlier sessions that this one reclaimed on the way
144
+ * in. Non-zero means previous sessions ended without a `dispose` — useful
145
+ * for spotting hosts that tear the iframe down abruptly.
146
+ */
147
+ reclaimedSessions: number;
148
+ };
149
+ /**
150
+ * The current URL for this asset stopped authorising. The host is expected to
151
+ * answer with `asset:url`; reads resume from where they stopped.
152
+ */
153
+ 'asset:url-expired': {
154
+ assetId: string;
155
+ };
156
+ 'asset:progress': {
157
+ assetId: string;
158
+ loadedBytes: number;
159
+ totalBytes: number | null;
160
+ };
161
+ /**
162
+ * Work the host must run on the editor's behalf, because the host owns the
163
+ * credentials. Answer with `rpc:result` carrying the same `requestId`.
164
+ */
165
+ 'stt:request': {
166
+ requestId: string;
167
+ payload: unknown;
168
+ };
169
+ 'llm:request': {
170
+ requestId: string;
171
+ payload: unknown;
172
+ };
173
+ /**
174
+ * The timeline changed. `otio` is the full document, so a host can keep a
175
+ * draft and reopen it later; `dirty` says whether it differs from the last
176
+ * state the host acknowledged.
177
+ */
178
+ change: {
179
+ dirty: boolean;
180
+ otio: string;
181
+ };
182
+ /** Preferences worth storing against the user's profile. Treat as opaque. */
183
+ 'preferences:changed': unknown;
184
+ 'export:progress': {
185
+ phase: string | null;
186
+ progress: number;
187
+ };
188
+ /**
189
+ * `file` is omitted in `upload` mode, where the editor streamed the render to
190
+ * the host's presigned URL instead. `otio` is the timeline that produced it,
191
+ * so the host can offer "edit again" rather than starting over.
192
+ */
193
+ 'export:done': {
194
+ file?: File;
195
+ poster: Blob | null;
196
+ otio: string;
197
+ meta: EmbedExportMeta;
198
+ };
199
+ 'export:error': {
200
+ message: string;
201
+ };
202
+ /**
203
+ * Cleanup finished. Sent last, after the final `change` and
204
+ * `preferences:changed`, so a host that waits for it is guaranteed to have
205
+ * heard everything worth keeping before the iframe goes away.
206
+ */
207
+ disposed: undefined;
208
+ error: {
209
+ code: string;
210
+ message: string;
211
+ };
212
+ /** The user asked to close the editor from inside it. */
213
+ requestClose: undefined;
214
+ /**
215
+ * The editor would like a different height — the touch shell in particular
216
+ * needs vertical room for a monitor, a timeline and its drawers. Advisory:
217
+ * the host owns its own layout and may ignore it.
218
+ */
219
+ 'resize-request': {
220
+ minHeightPx: number;
221
+ };
222
+ }
223
+ export type HostToEditorType = keyof HostToEditorMessages;
224
+ export type EditorToHostType = keyof EditorToHostMessages;
225
+ export interface EmbedEnvelope<T extends string = string> {
226
+ channel: typeof EMBED_CHANNEL;
227
+ version: number;
228
+ nonce: string;
229
+ type: T;
230
+ payload: unknown;
231
+ }
232
+ export interface EmbedProtocolValidationResult {
233
+ ok: boolean;
234
+ code?: EmbedProtocolErrorCode;
235
+ message?: string;
236
+ }
237
+ export interface EmbedHandshakeParams {
238
+ nonce: string;
239
+ hostOrigin: string;
240
+ }
241
+ /**
242
+ * Both sides pin every `postMessage` to a single expected origin, so a page
243
+ * that merely guesses the iframe URL still cannot talk to the editor. The nonce
244
+ * additionally scopes the channel to one embed instance on pages hosting more
245
+ * than one.
246
+ */
247
+ export declare function createEmbedNonce(): string;
248
+ export declare function buildEmbedUrl(editorUrl: string, params: EmbedHandshakeParams): string;
249
+ export declare function parseEmbedHandshakeParams(hash: string): EmbedHandshakeParams | null;
250
+ export declare function isEmbedEnvelope(data: unknown, nonce: string): data is EmbedEnvelope;
251
+ /** Envelope identity and protocol-version checks are deliberately separate. */
252
+ export declare function hasEmbedProtocolVersion(envelope: EmbedEnvelope): boolean;
253
+ export declare function isSafeEmbedFilename(value: unknown): value is string;
254
+ export declare function validateEmbedMessage(direction: 'host' | 'editor', type: string, payload: unknown): EmbedProtocolValidationResult;
255
+ export declare function createEnvelope(nonce: string, type: string, payload: unknown): EmbedEnvelope;
256
+ //# sourceMappingURL=protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.d.ts","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,287 @@
1
+ /**
2
+ * Wire contract between an embedding host page and the FastCat editor iframe.
3
+ *
4
+ * This module is published as part of `@bozonx/fastcat-embed` and is imported by the
5
+ * editor through the `~embed` alias, so both sides of the boundary always
6
+ * compile against the same definitions and can never drift apart.
7
+ */
8
+ export const EMBED_CHANNEL = 'fastcat-embed';
9
+ export const EMBED_PROTOCOL_VERSION = 1;
10
+ export const MAX_EMBED_ASSETS = 100;
11
+ export const MAX_EMBED_ASSET_BYTES = 10 * 1024 * 1024 * 1024;
12
+ export const MAX_EMBED_EXPORT_BYTES = 10 * 1024 * 1024 * 1024;
13
+ /** Hash keys carrying the handshake parameters into the iframe document. */
14
+ const NONCE_KEY = 'fcNonce';
15
+ const ORIGIN_KEY = 'fcOrigin';
16
+ /**
17
+ * Both sides pin every `postMessage` to a single expected origin, so a page
18
+ * that merely guesses the iframe URL still cannot talk to the editor. The nonce
19
+ * additionally scopes the channel to one embed instance on pages hosting more
20
+ * than one.
21
+ */
22
+ export function createEmbedNonce() {
23
+ const bytes = new Uint8Array(16);
24
+ globalThis.crypto.getRandomValues(bytes);
25
+ return Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
26
+ }
27
+ export function buildEmbedUrl(editorUrl, params) {
28
+ const url = new URL(editorUrl, globalThis.location?.href);
29
+ const hash = new URLSearchParams();
30
+ hash.set(NONCE_KEY, params.nonce);
31
+ hash.set(ORIGIN_KEY, params.hostOrigin);
32
+ url.hash = hash.toString();
33
+ return url.toString();
34
+ }
35
+ export function parseEmbedHandshakeParams(hash) {
36
+ const raw = hash.startsWith('#') ? hash.slice(1) : hash;
37
+ if (!raw)
38
+ return null;
39
+ const parsed = new URLSearchParams(raw);
40
+ const nonce = parsed.get(NONCE_KEY);
41
+ const hostOrigin = parsed.get(ORIGIN_KEY);
42
+ if (!nonce || !hostOrigin)
43
+ return null;
44
+ // A malformed origin would otherwise become a `postMessage` target we cannot
45
+ // reason about; reject it rather than falling back to a wildcard.
46
+ try {
47
+ if (new URL(hostOrigin).origin !== hostOrigin)
48
+ return null;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ return { nonce, hostOrigin };
54
+ }
55
+ export function isEmbedEnvelope(data, nonce) {
56
+ if (typeof data !== 'object' || data === null)
57
+ return false;
58
+ const candidate = data;
59
+ return (candidate.channel === EMBED_CHANNEL &&
60
+ typeof candidate.version === 'number' &&
61
+ candidate.nonce === nonce &&
62
+ typeof candidate.type === 'string');
63
+ }
64
+ /** Envelope identity and protocol-version checks are deliberately separate. */
65
+ export function hasEmbedProtocolVersion(envelope) {
66
+ return envelope.version === EMBED_PROTOCOL_VERSION;
67
+ }
68
+ function isRecord(value) {
69
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
70
+ }
71
+ function isFiniteNumber(value, min = -Number.MAX_VALUE, max = Number.MAX_VALUE) {
72
+ return typeof value === 'number' && Number.isFinite(value) && value >= min && value <= max;
73
+ }
74
+ function isSafeHttpUrl(value) {
75
+ if (typeof value !== 'string' || value.length > 4_096)
76
+ return false;
77
+ try {
78
+ const url = new URL(value);
79
+ return url.protocol === 'https:' || url.protocol === 'http:';
80
+ }
81
+ catch {
82
+ return false;
83
+ }
84
+ }
85
+ export function isSafeEmbedFilename(value) {
86
+ return (typeof value === 'string' &&
87
+ value.length > 0 &&
88
+ value.length <= 255 &&
89
+ !value.includes('/') &&
90
+ !value.includes('\\') &&
91
+ !value.includes('..') &&
92
+ /^[a-zA-Z0-9][a-zA-Z0-9._ -]*$/.test(value));
93
+ }
94
+ function isAsset(value) {
95
+ if (!isRecord(value))
96
+ return false;
97
+ if (value.id !== undefined && (typeof value.id !== 'string' || value.id.length > 128))
98
+ return false;
99
+ if (value.url !== undefined && !isSafeHttpUrl(value.url))
100
+ return false;
101
+ if (value.filename !== undefined && !isSafeEmbedFilename(value.filename))
102
+ return false;
103
+ if (value.kind !== undefined && !['video', 'audio', 'image'].includes(value.kind))
104
+ return false;
105
+ if (value.track !== undefined && (typeof value.track !== 'string' || value.track.length > 128))
106
+ return false;
107
+ if (value.startAt !== undefined && !isFiniteNumber(value.startAt, 0, 86_400))
108
+ return false;
109
+ if (value.file !== undefined &&
110
+ (!(value.file instanceof Blob) || value.file.size > MAX_EMBED_ASSET_BYTES))
111
+ return false;
112
+ return (value.url !== undefined) !== (value.file !== undefined);
113
+ }
114
+ function isProjectDefaults(value) {
115
+ if (value === undefined)
116
+ return true;
117
+ if (!isRecord(value))
118
+ return false;
119
+ return ((value.width === undefined || isFiniteNumber(value.width, 16, 16_384)) &&
120
+ (value.height === undefined || isFiniteNumber(value.height, 16, 16_384)) &&
121
+ (value.fps === undefined || isFiniteNumber(value.fps, 1, 240)) &&
122
+ (value.sampleRate === undefined || isFiniteNumber(value.sampleRate, 8_000, 192_000)));
123
+ }
124
+ function isInitPayload(value) {
125
+ if (!isRecord(value))
126
+ return false;
127
+ const assets = value.assets;
128
+ return ((value.locale === undefined ||
129
+ (typeof value.locale === 'string' && value.locale.length <= 32)) &&
130
+ (assets === undefined ||
131
+ (Array.isArray(assets) && assets.length <= MAX_EMBED_ASSETS && assets.every(isAsset))) &&
132
+ (value.layout === undefined ||
133
+ ['auto', 'desktop', 'mobile'].includes(value.layout)) &&
134
+ (value.features === undefined ||
135
+ (Array.isArray(value.features) &&
136
+ value.features.every((item) => ['files', 'sound', 'export', 'settings'].includes(item)))) &&
137
+ isProjectDefaults(value.projectDefaults) &&
138
+ (value.assetTransport === undefined ||
139
+ value.assetTransport === 'url' ||
140
+ value.assetTransport === 'host') &&
141
+ (value.output === undefined || value.output === 'blob' || value.output === 'upload') &&
142
+ (value.initialProject === undefined ||
143
+ (isRecord(value.initialProject) && isInitialOtio(value.initialProject.otio))));
144
+ }
145
+ function isInitialOtio(value) {
146
+ if (typeof value !== 'string' || value.length === 0 || value.length > 10_000_000)
147
+ return false;
148
+ try {
149
+ const document = JSON.parse(value);
150
+ return document.OTIO_SCHEMA === 'Timeline.1' && isRecord(document.tracks);
151
+ }
152
+ catch {
153
+ return false;
154
+ }
155
+ }
156
+ const HOST_TYPES = new Set([
157
+ 'init',
158
+ 'asset:add',
159
+ 'asset:url',
160
+ 'rpc:result',
161
+ 'save:request',
162
+ 'export:start',
163
+ 'export:cancel',
164
+ 'export:ack',
165
+ 'dispose',
166
+ ]);
167
+ const EDITOR_TYPES = new Set([
168
+ 'ready',
169
+ 'initialized',
170
+ 'asset:url-expired',
171
+ 'asset:progress',
172
+ 'stt:request',
173
+ 'llm:request',
174
+ 'change',
175
+ 'preferences:changed',
176
+ 'export:progress',
177
+ 'export:done',
178
+ 'export:error',
179
+ 'disposed',
180
+ 'error',
181
+ 'requestClose',
182
+ 'resize-request',
183
+ ]);
184
+ function validPayload(type, payload, direction) {
185
+ if (payload === undefined)
186
+ return [
187
+ 'save:request',
188
+ 'export:start',
189
+ 'export:cancel',
190
+ 'export:ack',
191
+ 'dispose',
192
+ 'disposed',
193
+ 'requestClose',
194
+ ].includes(type);
195
+ if (type === 'init')
196
+ return isInitPayload(payload);
197
+ if (type === 'asset:add')
198
+ return (isRecord(payload) &&
199
+ Array.isArray(payload.assets) &&
200
+ payload.assets.length <= MAX_EMBED_ASSETS &&
201
+ payload.assets.every(isAsset));
202
+ if (type === 'asset:url')
203
+ return isRecord(payload) && typeof payload.assetId === 'string' && isSafeHttpUrl(payload.url);
204
+ if (type === 'export:start')
205
+ return (payload === undefined ||
206
+ (isRecord(payload) &&
207
+ (payload.filename === undefined || isSafeEmbedFilename(payload.filename)) &&
208
+ (payload.uploadUrl === undefined || isSafeHttpUrl(payload.uploadUrl))));
209
+ if (type === 'rpc:result')
210
+ return (isRecord(payload) &&
211
+ typeof payload.requestId === 'string' &&
212
+ payload.requestId.length <= 128 &&
213
+ (payload.error === undefined || typeof payload.error === 'string'));
214
+ if (type === 'ready')
215
+ return (isRecord(payload) &&
216
+ typeof payload.version === 'number' &&
217
+ isRecord(payload.capabilities) &&
218
+ typeof payload.capabilities.webgpu === 'boolean' &&
219
+ typeof payload.capabilities.webcodecs === 'boolean' &&
220
+ typeof payload.capabilities.opfs === 'boolean' &&
221
+ typeof payload.capabilities.sharedArrayBuffer === 'boolean' &&
222
+ (payload.capabilities.storageQuotaBytes === null ||
223
+ isFiniteNumber(payload.capabilities.storageQuotaBytes, 0)));
224
+ if (type === 'initialized')
225
+ return (isRecord(payload) &&
226
+ isFiniteNumber(payload.assetCount, 0, MAX_EMBED_ASSETS) &&
227
+ isFiniteNumber(payload.durationMs, 0) &&
228
+ ['desktop', 'mobile'].includes(payload.layout) &&
229
+ isFiniteNumber(payload.reclaimedSessions, 0));
230
+ if (type === 'asset:url-expired')
231
+ return isRecord(payload) && typeof payload.assetId === 'string';
232
+ if (type === 'asset:progress')
233
+ return (isRecord(payload) &&
234
+ typeof payload.assetId === 'string' &&
235
+ isFiniteNumber(payload.loadedBytes, 0) &&
236
+ (payload.totalBytes === null || isFiniteNumber(payload.totalBytes, 0)));
237
+ if (type === 'stt:request' || type === 'llm:request')
238
+ return isRecord(payload) && typeof payload.requestId === 'string';
239
+ if (type === 'change')
240
+ return (isRecord(payload) &&
241
+ typeof payload.dirty === 'boolean' &&
242
+ typeof payload.otio === 'string' &&
243
+ payload.otio.length <= 10_000_000);
244
+ if (type === 'export:progress')
245
+ return (isRecord(payload) &&
246
+ (payload.phase === null || typeof payload.phase === 'string') &&
247
+ isFiniteNumber(payload.progress, 0, 1));
248
+ if (type === 'export:error')
249
+ return isRecord(payload) && typeof payload.message === 'string';
250
+ if (type === 'error')
251
+ return (isRecord(payload) && typeof payload.code === 'string' && typeof payload.message === 'string');
252
+ if (type === 'resize-request')
253
+ return isRecord(payload) && isFiniteNumber(payload.minHeightPx, 100, 10_000);
254
+ if (type === 'export:done')
255
+ return (isRecord(payload) &&
256
+ typeof payload.otio === 'string' &&
257
+ payload.otio.length <= 10_000_000 &&
258
+ (payload.file === undefined || payload.file instanceof Blob) &&
259
+ (payload.poster === null || payload.poster instanceof Blob) &&
260
+ isRecord(payload.meta) &&
261
+ isSafeEmbedFilename(payload.meta.filename) &&
262
+ typeof payload.meta.mimeType === 'string' &&
263
+ isFiniteNumber(payload.meta.sizeBytes, 0, MAX_EMBED_EXPORT_BYTES) &&
264
+ (payload.meta.width === null || isFiniteNumber(payload.meta.width, 1, 16_384)) &&
265
+ (payload.meta.height === null || isFiniteNumber(payload.meta.height, 1, 16_384)) &&
266
+ (payload.meta.durationMs === null || isFiniteNumber(payload.meta.durationMs, 0)) &&
267
+ (payload.meta.fps === null || isFiniteNumber(payload.meta.fps, 1, 240)));
268
+ return direction === 'editor' && type === 'preferences:changed';
269
+ }
270
+ export function validateEmbedMessage(direction, type, payload) {
271
+ const known = direction === 'host'
272
+ ? HOST_TYPES.has(type)
273
+ : EDITOR_TYPES.has(type);
274
+ if (!known)
275
+ return {
276
+ ok: false,
277
+ code: 'protocol-unknown-message',
278
+ message: `Unknown ${direction} message: ${type}`,
279
+ };
280
+ if (!validPayload(type, payload, direction))
281
+ return { ok: false, code: 'protocol-invalid-payload', message: `Invalid payload for ${type}` };
282
+ return { ok: true };
283
+ }
284
+ export function createEnvelope(nonce, type, payload) {
285
+ return { channel: EMBED_CHANNEL, version: EMBED_PROTOCOL_VERSION, nonce, type, payload };
286
+ }
287
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../src/protocol.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@bozonx/fastcat-embed",
3
+ "version": "0.1.0",
4
+ "description": "SDK for embedding the FastCat video editor into any web page through an isolated iframe.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "author": "FastCat Team",
8
+ "homepage": "https://github.com/bozonx/fastcat#readme",
9
+ "bugs": {
10
+ "url": "https://github.com/bozonx/fastcat/issues"
11
+ },
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "https://github.com/bozonx/fastcat.git",
15
+ "directory": "packages/embed"
16
+ },
17
+ "main": "./dist/index.js",
18
+ "module": "./dist/index.js",
19
+ "types": "./dist/index.d.ts",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "import": "./dist/index.js",
24
+ "default": "./dist/index.js"
25
+ },
26
+ "./protocol": {
27
+ "types": "./dist/protocol.d.ts",
28
+ "import": "./dist/protocol.js",
29
+ "default": "./dist/protocol.js"
30
+ },
31
+ "./package.json": "./package.json"
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "devDependencies": {
42
+ "eslint": "^10.7.0",
43
+ "typescript": "~5.9.0",
44
+ "@fastcat/eslint-config": "0.1.0",
45
+ "@fastcat/typescript-config": "0.1.0"
46
+ },
47
+ "engines": {
48
+ "node": ">=18.0.0"
49
+ },
50
+ "keywords": [
51
+ "fastcat",
52
+ "video-editor",
53
+ "embed",
54
+ "iframe",
55
+ "sdk",
56
+ "postmessage",
57
+ "webgpu"
58
+ ],
59
+ "sideEffects": false,
60
+ "scripts": {
61
+ "build": "tsc -p tsconfig.json",
62
+ "lint": "eslint --max-warnings 0 .",
63
+ "lint:fix": "eslint --fix .",
64
+ "format": "prettier --write .",
65
+ "format:check": "prettier --check .",
66
+ "typecheck": "tsc -p tsconfig.json --noEmit",
67
+ "check": "pnpm typecheck && pnpm lint && pnpm format:check",
68
+ "validate": "pnpm check",
69
+ "clean": "rm -rf dist"
70
+ }
71
+ }