@elah/cli 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 +201 -0
- package/README.md +144 -0
- package/dist/bin.js +40389 -0
- package/dist/index.js +39638 -0
- package/dist/types/bin.d.ts +1 -0
- package/dist/types/commands/build.d.ts +14 -0
- package/dist/types/commands/export.d.ts +15 -0
- package/dist/types/commands/serve.d.ts +14 -0
- package/dist/types/commands/split.d.ts +10 -0
- package/dist/types/commands/trim.d.ts +8 -0
- package/dist/types/index.d.ts +15 -0
- package/dist/types/lib/browser.d.ts +15 -0
- package/dist/types/lib/build-project.d.ts +18 -0
- package/dist/types/lib/errors.d.ts +9 -0
- package/dist/types/lib/export-project.d.ts +22 -0
- package/dist/types/lib/flags.d.ts +1 -0
- package/dist/types/lib/harness.d.ts +12 -0
- package/dist/types/lib/probe.d.ts +11 -0
- package/dist/types/lib/project-io.d.ts +19 -0
- package/dist/types/lib/render-session.d.ts +40 -0
- package/dist/types/lib/serve.d.ts +39 -0
- package/dist/types/lib/server.d.ts +48 -0
- package/dist/types/lib/spec.d.ts +63 -0
- package/dist/types/lib/timecode.d.ts +6 -0
- package/package.json +64 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface BuildArgs {
|
|
2
|
+
spec: string;
|
|
3
|
+
out?: string;
|
|
4
|
+
export?: string;
|
|
5
|
+
codec?: string;
|
|
6
|
+
height?: string;
|
|
7
|
+
videoBitrate?: string;
|
|
8
|
+
audioBitrate?: string;
|
|
9
|
+
browser?: string;
|
|
10
|
+
headed: boolean;
|
|
11
|
+
timeoutSec?: string;
|
|
12
|
+
verbose: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function runBuild(args: BuildArgs): Promise<void>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Project } from '@elah/core';
|
|
2
|
+
export interface ExportArgs {
|
|
3
|
+
project: string;
|
|
4
|
+
out: string;
|
|
5
|
+
codec?: string;
|
|
6
|
+
height?: string;
|
|
7
|
+
videoBitrate?: string;
|
|
8
|
+
audioBitrate?: string;
|
|
9
|
+
browser?: string;
|
|
10
|
+
headed: boolean;
|
|
11
|
+
timeoutSec?: string;
|
|
12
|
+
verbose: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function runExport(args: ExportArgs): Promise<void>;
|
|
15
|
+
export declare function runExportForProject(project: Project, projectDir: string, args: Omit<ExportArgs, 'project'>): Promise<void>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface ServeArgs {
|
|
2
|
+
port?: string;
|
|
3
|
+
host?: string;
|
|
4
|
+
concurrency?: string;
|
|
5
|
+
mediaRoot?: string;
|
|
6
|
+
codec?: string;
|
|
7
|
+
height?: string;
|
|
8
|
+
videoBitrate?: string;
|
|
9
|
+
audioBitrate?: string;
|
|
10
|
+
browser?: string;
|
|
11
|
+
timeoutSec?: string;
|
|
12
|
+
verbose: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function runServe(args: ServeArgs): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type Project } from '@elah/core';
|
|
2
|
+
/** The engine silently ignores edits on locked tracks — fail with the real reason instead. */
|
|
3
|
+
export declare function requireUnlockedTrack(project: Project, trackId: string): void;
|
|
4
|
+
export interface SplitArgs {
|
|
5
|
+
project: string;
|
|
6
|
+
clip: string;
|
|
7
|
+
at: string;
|
|
8
|
+
out?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function runSplit(args: SplitArgs): void;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export { buildProject as build } from './lib/build-project';
|
|
2
|
+
export type { BuildProjectArgs, BuildProjectResult, BuildSummary } from './lib/build-project';
|
|
3
|
+
export { exportProject } from './lib/export-project';
|
|
4
|
+
export type { ExportProjectArgs, ExportProjectResult } from './lib/export-project';
|
|
5
|
+
export { createRenderSession, CODECS } from './lib/render-session';
|
|
6
|
+
export type { RenderSession, RenderSessionArgs, RenderJobOptions, RenderCallbacks, VideoCodec, } from './lib/render-session';
|
|
7
|
+
export { CliError, CliError as ElahError } from './lib/errors';
|
|
8
|
+
export { validateSpec, specToProject } from './lib/spec';
|
|
9
|
+
export type { BuildSpec, SpecClip, SpecMediaClip, SpecTextClip, ProbedAsset } from './lib/spec';
|
|
10
|
+
export { probeMedia } from './lib/probe';
|
|
11
|
+
export type { MediaInfo } from './lib/probe';
|
|
12
|
+
export type { ProgressPayload } from './lib/server';
|
|
13
|
+
export { startServe, Semaphore } from './lib/serve';
|
|
14
|
+
export type { ServeOptions, ServeHandle } from './lib/serve';
|
|
15
|
+
export type { Project } from '@elah/core';
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Browser } from 'playwright-core';
|
|
2
|
+
export interface LaunchArgs {
|
|
3
|
+
/** Explicit executable path (--browser); wins over discovery. */
|
|
4
|
+
browserPath?: string;
|
|
5
|
+
headed?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Launch a Chromium-based browser for the export harness. Discovery order:
|
|
9
|
+
* --browser flag → ELAH_BROWSER env → system Chrome → Chrome Beta → Edge.
|
|
10
|
+
* Branded Chrome is preferred because Playwright's bundled Chromium lacks
|
|
11
|
+
* the proprietary codecs (H.264/AAC) that the default export uses.
|
|
12
|
+
*
|
|
13
|
+
* playwright-core is imported lazily so split/trim never load it.
|
|
14
|
+
*/
|
|
15
|
+
export declare function launchBrowser(args: LaunchArgs): Promise<Browser>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { Project } from '@elah/core';
|
|
2
|
+
export interface BuildProjectArgs {
|
|
3
|
+
/** Raw parsed spec JSON — validated internally with path-addressed errors. */
|
|
4
|
+
spec: unknown;
|
|
5
|
+
/** Absolute dir that relative asset paths in the spec resolve against. */
|
|
6
|
+
baseDir: string;
|
|
7
|
+
}
|
|
8
|
+
export interface BuildSummary {
|
|
9
|
+
tracks: number;
|
|
10
|
+
clips: number;
|
|
11
|
+
totalFrames: number;
|
|
12
|
+
fps: number;
|
|
13
|
+
}
|
|
14
|
+
export interface BuildProjectResult {
|
|
15
|
+
project: Project;
|
|
16
|
+
summary: BuildSummary;
|
|
17
|
+
}
|
|
18
|
+
export declare function buildProject(args: BuildProjectArgs): Promise<BuildProjectResult>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit-code contract: 0 success, 1 validation/runtime failure, 2 usage error.
|
|
3
|
+
* Thrown CliErrors are caught once in bin.ts; everything else is a bug.
|
|
4
|
+
*/
|
|
5
|
+
export declare class CliError extends Error {
|
|
6
|
+
readonly exitCode: 1 | 2;
|
|
7
|
+
constructor(message: string, exitCode?: 1 | 2);
|
|
8
|
+
}
|
|
9
|
+
export declare function usageError(message: string): CliError;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Project } from '@elah/core';
|
|
2
|
+
import { type RenderCallbacks, type VideoCodec } from './render-session';
|
|
3
|
+
export interface ExportProjectArgs {
|
|
4
|
+
project: Project;
|
|
5
|
+
/** Base directory for relative clip srcs. Default process.cwd(). */
|
|
6
|
+
projectDir?: string;
|
|
7
|
+
/** When set, the MP4 is also written to disk (absolute or cwd-relative). */
|
|
8
|
+
outPath?: string;
|
|
9
|
+
videoCodec?: VideoCodec;
|
|
10
|
+
outputHeight?: number;
|
|
11
|
+
videoBitrate?: number;
|
|
12
|
+
audioBitrate?: number;
|
|
13
|
+
browserPath?: string;
|
|
14
|
+
headed?: boolean;
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface ExportProjectResult {
|
|
18
|
+
bytes: Buffer;
|
|
19
|
+
sizeBytes: number;
|
|
20
|
+
outPath?: string;
|
|
21
|
+
}
|
|
22
|
+
export declare function exportProject(args: ExportProjectArgs, callbacks?: RenderCallbacks): Promise<ExportProjectResult>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function parsePositiveInt(value: string, flag: string): number;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-browser side of `elah export`, embedded as strings so the CLI ships
|
|
3
|
+
* a single bundled file. The page deep-imports core's real exportVideo from
|
|
4
|
+
* the harness server (bypassing core's index.js and everything browser-page
|
|
5
|
+
* irrelevant) and streams progress + the MP4 bytes back over HTTP.
|
|
6
|
+
*/
|
|
7
|
+
export declare const HARNESS_HTML = "<!doctype html>\n<html>\n <head><meta charset=\"utf-8\"><title>elah export harness</title></head>\n <body><script type=\"module\" src=\"/harness.js\"></script></body>\n</html>\n";
|
|
8
|
+
/**
|
|
9
|
+
* The callback routes carry a per-run random token so no other local process
|
|
10
|
+
* can post a forged /result into the output file or read the media routes.
|
|
11
|
+
*/
|
|
12
|
+
export declare function harnessJs(token: string): string;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface MediaInfo {
|
|
2
|
+
durationSec: number;
|
|
3
|
+
width?: number;
|
|
4
|
+
height?: number;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Probe a media file's duration (and dimensions for video) with mediabunny —
|
|
8
|
+
* already a core dependency, pure-JS demuxing, no WebCodecs needed in Node.
|
|
9
|
+
* Remote URLs use ranged reads (UrlSource) instead of buffering the file.
|
|
10
|
+
*/
|
|
11
|
+
export declare function probeMedia(source: string): Promise<MediaInfo>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Project, Clip } from '@elah/core';
|
|
2
|
+
/** True for http(s) sources, which are proxied rather than read from disk. */
|
|
3
|
+
export declare function isRemoteUrl(src: string): boolean;
|
|
4
|
+
export interface LoadedProject {
|
|
5
|
+
project: Project;
|
|
6
|
+
/** Directory of the project JSON — relative clip srcs resolve against it. */
|
|
7
|
+
dir: string;
|
|
8
|
+
}
|
|
9
|
+
/** Read + parse + structurally validate a Project JSON file. */
|
|
10
|
+
export declare function readProject(path: string): LoadedProject;
|
|
11
|
+
/** Write project JSON to a file, or stdout when no path is given. */
|
|
12
|
+
export declare function writeProject(project: Project, outPath?: string): void;
|
|
13
|
+
/** Locate a clip by id across all tracks. Clip ids are unique by construction. */
|
|
14
|
+
export declare function findClipTrack(project: Project, clipId: string): {
|
|
15
|
+
clip: Clip;
|
|
16
|
+
trackId: string;
|
|
17
|
+
};
|
|
18
|
+
/** Resolve a clip src against the project directory. Remote URLs pass through. */
|
|
19
|
+
export declare function resolveMediaSource(src: string, projectDir: string): string;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Project } from '@elah/core';
|
|
2
|
+
import { type ProgressPayload } from './server';
|
|
3
|
+
export type VideoCodec = 'avc' | 'vp9' | 'vp8';
|
|
4
|
+
export declare const CODECS: readonly VideoCodec[];
|
|
5
|
+
export interface RenderSessionArgs {
|
|
6
|
+
browserPath?: string;
|
|
7
|
+
headed?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface RenderJobOptions {
|
|
10
|
+
videoCodec?: VideoCodec;
|
|
11
|
+
outputHeight?: number;
|
|
12
|
+
videoBitrate?: number;
|
|
13
|
+
audioBitrate?: number;
|
|
14
|
+
/** Default 600_000 (10 minutes). */
|
|
15
|
+
timeoutMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface RenderCallbacks {
|
|
18
|
+
onProgress?: (p: ProgressPayload) => void;
|
|
19
|
+
/** Audio-clip-skipped warnings and in-page errors. */
|
|
20
|
+
onWarning?: (message: string) => void;
|
|
21
|
+
/** Verbose [server]/[browser] log lines. */
|
|
22
|
+
onLog?: (line: string) => void;
|
|
23
|
+
}
|
|
24
|
+
export interface RenderSession {
|
|
25
|
+
/** Launch the browser now (idempotent). */
|
|
26
|
+
warmup(): Promise<void>;
|
|
27
|
+
browserConnected(): boolean;
|
|
28
|
+
render(project: Project, projectDir: string, options?: RenderJobOptions, callbacks?: RenderCallbacks): Promise<Buffer>;
|
|
29
|
+
close(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
export declare function createRenderSession(args?: RenderSessionArgs): RenderSession;
|
|
32
|
+
/**
|
|
33
|
+
* Clone the project with every media clip src rewritten to a token-guarded
|
|
34
|
+
* local-server route; the map feeds the harness server. Missing local files
|
|
35
|
+
* fail here, before a browser ever launches.
|
|
36
|
+
*/
|
|
37
|
+
export declare function prepareMedia(project: Project, projectDir: string, token: string): {
|
|
38
|
+
exportProject: Project;
|
|
39
|
+
media: Map<string, string>;
|
|
40
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { type IncomingMessage, type ServerResponse } from 'node:http';
|
|
2
|
+
import type { Project } from '@elah/core';
|
|
3
|
+
import type { RenderJobOptions, RenderSession } from './render-session';
|
|
4
|
+
export declare class Semaphore {
|
|
5
|
+
readonly max: number;
|
|
6
|
+
private activeCount;
|
|
7
|
+
constructor(max: number);
|
|
8
|
+
get active(): number;
|
|
9
|
+
tryAcquire(): boolean;
|
|
10
|
+
release(): void;
|
|
11
|
+
}
|
|
12
|
+
export interface ServeHandlerDeps {
|
|
13
|
+
buildSpec(spec: unknown): Promise<Project>;
|
|
14
|
+
renderProject(project: Project, jobId: string): Promise<Buffer>;
|
|
15
|
+
browserConnected(): boolean;
|
|
16
|
+
semaphore: Semaphore;
|
|
17
|
+
maxBodyBytes: number;
|
|
18
|
+
log(line: string): void;
|
|
19
|
+
}
|
|
20
|
+
export declare function createServeHandler(deps: ServeHandlerDeps): (req: IncomingMessage, res: ServerResponse) => void;
|
|
21
|
+
export interface ServeOptions {
|
|
22
|
+
host: string;
|
|
23
|
+
/** 0 = ephemeral port (tests). */
|
|
24
|
+
port: number;
|
|
25
|
+
concurrency: number;
|
|
26
|
+
/** Absolute dir that relative spec asset paths resolve against. */
|
|
27
|
+
mediaRoot: string;
|
|
28
|
+
/** Server-level codec/height/bitrate/timeout applied to every render. */
|
|
29
|
+
render: RenderJobOptions;
|
|
30
|
+
session: RenderSession;
|
|
31
|
+
maxBodyBytes?: number;
|
|
32
|
+
log?: (line: string) => void;
|
|
33
|
+
verbose?: boolean;
|
|
34
|
+
}
|
|
35
|
+
export interface ServeHandle {
|
|
36
|
+
port: number;
|
|
37
|
+
close(): Promise<void>;
|
|
38
|
+
}
|
|
39
|
+
export declare function startServe(options: ServeOptions): Promise<ServeHandle>;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export interface ProgressPayload {
|
|
2
|
+
frame: number;
|
|
3
|
+
totalFrames: number;
|
|
4
|
+
}
|
|
5
|
+
export interface HarnessServerArgs {
|
|
6
|
+
/** Per-run random secret protecting the callback and media routes. */
|
|
7
|
+
token: string;
|
|
8
|
+
/** Route path (e.g. '/media/<token>/0') → absolute file path or http(s) URL to proxy. */
|
|
9
|
+
media: Map<string, string>;
|
|
10
|
+
onProgress?: (p: ProgressPayload) => void;
|
|
11
|
+
onAudioIssue?: (message: string, src?: string) => void;
|
|
12
|
+
log?: (line: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface HarnessServer {
|
|
15
|
+
origin: string;
|
|
16
|
+
/** Resolves with the exported MP4 bytes; rejects when the page reports an error. */
|
|
17
|
+
result: Promise<Buffer>;
|
|
18
|
+
/** Reject the result from the outside (tab crash, browser disconnect). */
|
|
19
|
+
fail(err: Error): void;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
interface VendorEntry {
|
|
23
|
+
root: string;
|
|
24
|
+
/** Path of the package's browser entry, relative to root (posix). */
|
|
25
|
+
entry: string;
|
|
26
|
+
/**
|
|
27
|
+
* Package-relative paths the package.json `browser` field maps to `false`
|
|
28
|
+
* (Node-only modules). Bundlers replace these with empty modules; serving
|
|
29
|
+
* raw files over HTTP must do the same or the browser hits `node:` imports.
|
|
30
|
+
*/
|
|
31
|
+
browserFalse: Set<string>;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Resolve a bare specifier to its entry file. Uses import.meta.resolve when
|
|
35
|
+
* available (bundled Node runtime); falls back to createRequire under tooling
|
|
36
|
+
* that doesn't expose it (vitest's SSR transform).
|
|
37
|
+
*/
|
|
38
|
+
export declare function resolveModuleFile(spec: string): string;
|
|
39
|
+
/** Replace bare vendor specifiers in served core modules with /vendor/ URLs. */
|
|
40
|
+
export declare function rewriteSpecifiers(source: string, vendors: Map<string, VendorEntry>): string;
|
|
41
|
+
/**
|
|
42
|
+
* Resolve a /core/* request against core's dist, tolerating the module-URL
|
|
43
|
+
* quirks of tsc's bundler-resolution output: extensionless relative imports
|
|
44
|
+
* and the literal `./ExportWorker.ts` worker URL that ships in dist.
|
|
45
|
+
*/
|
|
46
|
+
export declare function resolveDistFile(distRoot: string, urlPath: string): string | undefined;
|
|
47
|
+
export declare function startHarnessServer(args: HarnessServerArgs): Promise<HarnessServer>;
|
|
48
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { type Project } from '@elah/core';
|
|
2
|
+
/**
|
|
3
|
+
* The AI-friendly build spec: times in seconds, assets by name, no engine
|
|
4
|
+
* bookkeeping. `elah build` turns this into a full Project via TimelineEngine —
|
|
5
|
+
* overlaps and track caps are enforced by core; source bounds are enforced
|
|
6
|
+
* here in frame space (the engine does not validate source windows on update).
|
|
7
|
+
*/
|
|
8
|
+
export interface BuildSpec {
|
|
9
|
+
/** Frames per second — integer. Default 30. */
|
|
10
|
+
fps?: number;
|
|
11
|
+
/** Output canvas in pixels. Default 1920x1080. */
|
|
12
|
+
stage?: {
|
|
13
|
+
width: number;
|
|
14
|
+
height: number;
|
|
15
|
+
};
|
|
16
|
+
/** Asset name → file path (relative to the spec file) or http(s) URL. */
|
|
17
|
+
assets?: Record<string, string>;
|
|
18
|
+
clips: SpecClip[];
|
|
19
|
+
}
|
|
20
|
+
export interface SpecClipBase {
|
|
21
|
+
track: 'video' | 'audio' | 'text' | 'image';
|
|
22
|
+
/** Timeline position in seconds. */
|
|
23
|
+
start: number;
|
|
24
|
+
/** Length in seconds. Optional for video/audio (defaults to the rest of the media). */
|
|
25
|
+
duration?: number;
|
|
26
|
+
/** Normalized 0..1 position of the clip center on the stage. */
|
|
27
|
+
x?: number;
|
|
28
|
+
y?: number;
|
|
29
|
+
scale?: number;
|
|
30
|
+
opacity?: number;
|
|
31
|
+
}
|
|
32
|
+
export interface SpecMediaClip extends SpecClipBase {
|
|
33
|
+
track: 'video' | 'audio' | 'image';
|
|
34
|
+
/** Name from the spec's assets map. */
|
|
35
|
+
asset: string;
|
|
36
|
+
/** Seconds into the source media to start from (video/audio). */
|
|
37
|
+
sourceStart?: number;
|
|
38
|
+
volume?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface SpecTextClip extends SpecClipBase {
|
|
41
|
+
track: 'text';
|
|
42
|
+
text: string;
|
|
43
|
+
duration: number;
|
|
44
|
+
fontSize?: number;
|
|
45
|
+
color?: string;
|
|
46
|
+
fontFamily?: string;
|
|
47
|
+
fontWeight?: 'normal' | 'bold';
|
|
48
|
+
align?: 'left' | 'center' | 'right';
|
|
49
|
+
}
|
|
50
|
+
export type SpecClip = SpecMediaClip | SpecTextClip;
|
|
51
|
+
export interface ProbedAsset {
|
|
52
|
+
/** Resolved absolute path or URL, used as the clip src. */
|
|
53
|
+
src: string;
|
|
54
|
+
/** Media duration in seconds (video/audio only; images pass undefined). */
|
|
55
|
+
durationSec?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Convert a validated spec into a Project through a real TimelineEngine.
|
|
59
|
+
* `assets` maps asset names to their resolved+probed sources.
|
|
60
|
+
*/
|
|
61
|
+
export declare function specToProject(spec: BuildSpec, assets: Map<string, ProbedAsset>): Project;
|
|
62
|
+
/** Structural validation with clear, path-addressed messages. */
|
|
63
|
+
export declare function validateSpec(value: unknown): BuildSpec;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Parse a frame position: either a plain integer frame count or a timecode.
|
|
3
|
+
* Accepted timecode forms (matching core's HH:MM:SS:FF formatter):
|
|
4
|
+
* SS:FF · MM:SS:FF · HH:MM:SS:FF
|
|
5
|
+
*/
|
|
6
|
+
export declare function parseFramePosition(value: string, fps: number): number;
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@elah/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Headless command-line runtime for the Elah video engine — split, trim, and export projects using @elah/core",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"elah": "./dist/bin.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/types/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/types/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./package.json": "./package.json"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist",
|
|
21
|
+
"README.md",
|
|
22
|
+
"LICENSE"
|
|
23
|
+
],
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.17"
|
|
26
|
+
},
|
|
27
|
+
"scripts": {
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"build": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\" && tsc --noEmit && tsc -p tsconfig.build.json && node scripts/build.mjs"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"video-editor",
|
|
35
|
+
"cli",
|
|
36
|
+
"headless",
|
|
37
|
+
"timeline",
|
|
38
|
+
"video-engine",
|
|
39
|
+
"export",
|
|
40
|
+
"mp4",
|
|
41
|
+
"automation",
|
|
42
|
+
"typescript"
|
|
43
|
+
],
|
|
44
|
+
"homepage": "https://www.elah.dev",
|
|
45
|
+
"repository": {
|
|
46
|
+
"type": "git",
|
|
47
|
+
"url": "https://github.com/elahlabs/elah.git"
|
|
48
|
+
},
|
|
49
|
+
"bugs": {
|
|
50
|
+
"url": "https://github.com/elahlabs/elah/issues"
|
|
51
|
+
},
|
|
52
|
+
"license": "Apache-2.0",
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@elah/core": "^0.3.0",
|
|
55
|
+
"mediabunny": "^1.45.3",
|
|
56
|
+
"playwright-core": "^1.50.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^22.10.0",
|
|
60
|
+
"esbuild": "^0.25.0",
|
|
61
|
+
"typescript": "^5.7.3",
|
|
62
|
+
"vitest": "^3.0.6"
|
|
63
|
+
}
|
|
64
|
+
}
|