videodraft 0.0.0 → 0.1.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/README.md +118 -2
- package/dist/client.d.ts +363 -0
- package/dist/client.js +933 -0
- package/dist/index.js +2816 -0
- package/package.json +64 -4
- package/skills/videodraft/SKILL.md +95 -0
- package/skills/videodraft/references/examples.md +84 -0
- package/skills/videodraft/references/models.md +43 -0
- package/skills/videodraft/references/pipeline.md +59 -0
package/README.md
CHANGED
|
@@ -1,5 +1,121 @@
|
|
|
1
1
|
# videodraft
|
|
2
2
|
|
|
3
|
-
The official
|
|
3
|
+
The official [VideoDraft](https://videodraft.ai) CLI — create AI videos, images, voiceovers and music from your terminal. Built for humans **and** coding agents: every command supports `--json`, exit codes are stable, async jobs are first-class.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
```bash
|
|
6
|
+
npx videodraft login
|
|
7
|
+
npx videodraft generate image "a red fox in snow, cinematic" --download ./out/
|
|
8
|
+
npx videodraft create "30s launch video for our espresso machine" --ar 9:16
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install -g videodraft # or: npx videodraft <command>
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Requires Node ≥ 20.18.1.
|
|
18
|
+
|
|
19
|
+
## Authenticate
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
videodraft login # opens your browser (OAuth)
|
|
23
|
+
videodraft login --token vd_mcp_… # personal access token from https://app.videodraft.ai/mcp-keys
|
|
24
|
+
export VIDEODRAFT_API_KEY=vd_mcp_… # headless / CI — no login command needed
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Credentials are stored in `~/.config/videodraft/config.json` (0600). `videodraft logout` revokes and clears them.
|
|
28
|
+
|
|
29
|
+
## The pipeline
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
videodraft credits # know your budget
|
|
33
|
+
videodraft create "<idea>" --ar 9:16 # idea → script → visual assets → storyboard
|
|
34
|
+
videodraft shots <project> --grid --estimate # preview the cost…
|
|
35
|
+
videodraft shots <project> --grid # …then batch-generate every shot image
|
|
36
|
+
videodraft produce <project> # voiceovers + captions + production timeline
|
|
37
|
+
videodraft export <project> --download final.mp4
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Single assets don't need a project:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
videodraft generate image "isometric workspace, warm light" --num 4 --download "./out/{job_id}_{index}.{ext}"
|
|
44
|
+
videodraft generate video "slow dolly over a misty lake" --model google-veo3.1 --duration 6 --estimate
|
|
45
|
+
videodraft generate voiceover "Welcome to VideoDraft" --download welcome.mp3
|
|
46
|
+
videodraft generate music "minimal ambient, 60 BPM" --download bgm.mp3
|
|
47
|
+
videodraft upscale image ./photo.png --scale 4x --download ./photo-4x.png
|
|
48
|
+
videodraft avatar create ./founder.jpg --script "$(videodraft avatar script 'our launch' --json | jq -r .script)"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Commands
|
|
52
|
+
|
|
53
|
+
| Group | Commands |
|
|
54
|
+
|---|---|
|
|
55
|
+
| Auth | `login` `logout` `whoami` |
|
|
56
|
+
| Account | `credits` `costs [model]` `models [image\|video\|voices\|styles]` `workspaces` `sessions list/create` |
|
|
57
|
+
| Projects | `projects list/get/delete/favorite/open` `checkpoint create/list/restore` |
|
|
58
|
+
| Pipeline | `create` `shots` `produce` (`--mode full_video`) `attach` `finalize` `export` `export-status` `video-prompts` |
|
|
59
|
+
| Generate | `generate image/video/voiceover/music` `upscale image/video` `avatar script/create/render/get/list` |
|
|
60
|
+
| Jobs | `status <job>` `wait <job>` `generations` |
|
|
61
|
+
| Media | `upload <file>` `media list` `describe <url\|file>` `download <url>` |
|
|
62
|
+
| Everything else | `tools list` `tools schema <name>` `call <tool> --args '<json>'` |
|
|
63
|
+
| Agents | `skills install [--agent claude\|codex\|cursor]` `skills path` |
|
|
64
|
+
| Utility | `config get/set/path` `completion bash\|zsh` `docs` `--version` |
|
|
65
|
+
|
|
66
|
+
`call` reaches **every** VideoDraft API tool (the full MCP catalog), including ones without a curated command — new platform features work in the CLI the day they ship.
|
|
67
|
+
|
|
68
|
+
## For agents and scripts
|
|
69
|
+
|
|
70
|
+
- `--json` on any command prints a single JSON document on stdout.
|
|
71
|
+
- Exit codes: `0` ok · `1` error · `2` usage · `3` auth required · `4` insufficient credits.
|
|
72
|
+
- Async generations wait by default; `--no-wait` returns `{job_id}` immediately, `videodraft wait <job...>` resumes, `--wait-timeout 30m --wait-interval 5s` tune polling.
|
|
73
|
+
- **Many jobs at once?** Submit them all with `--no-wait`, then `videodraft wait <id1> <id2> ...` — one process polls every job with ONE batched request per tick (don't spawn N parallel `wait` processes). Polling backs off adaptively (3s → 15s with jitter) on long jobs unless you pin `--wait-interval`.
|
|
74
|
+
- `--download` templates: `{job_id}`, `{index}`, `{ext}`, `{name}`. Downloads are echoed as `downloaded_files[]` in `--json` output.
|
|
75
|
+
- Local file → public URL anywhere a URL is expected (`--ref photo.jpg`), or explicitly via `videodraft upload`.
|
|
76
|
+
- `NO_COLOR` and `--no-color` are respected; output is uncolored when piped.
|
|
77
|
+
|
|
78
|
+
Install the VideoDraft skill so your agent knows the workflow:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
npx videodraft skills install # zero-install: npx fetches the CLI and installs the skill
|
|
82
|
+
videodraft skills install # if the CLI is on PATH — auto-detects your installed agents
|
|
83
|
+
videodraft skills install --agent claude,codex # target specific agents (repeatable/comma; --all for every agent)
|
|
84
|
+
npx skills add videodraft-ai/cli # via the vercel-labs skills tool (discovery / 69-agent multiselect)
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Environment variables
|
|
88
|
+
|
|
89
|
+
| Variable | Purpose |
|
|
90
|
+
|---|---|
|
|
91
|
+
| `VIDEODRAFT_API_KEY` | Bearer token (`vd_mcp_…`) — skips the login flow |
|
|
92
|
+
| `VIDEODRAFT_BASE_URL` | Target server (default `https://app.videodraft.ai`) |
|
|
93
|
+
| `VIDEODRAFT_CONFIG_DIR` | Config location (default `~/.config/videodraft`) |
|
|
94
|
+
| `VIDEODRAFT_TELEMETRY=0` | Disable telemetry |
|
|
95
|
+
| `DO_NOT_TRACK=1` | Disable telemetry (and the update check) |
|
|
96
|
+
| `VIDEODRAFT_NO_UPDATE_CHECK=1` | Disable the update notice |
|
|
97
|
+
| `HTTPS_PROXY` / `HTTP_PROXY` / `NO_PROXY` | Proxy support |
|
|
98
|
+
|
|
99
|
+
## Telemetry
|
|
100
|
+
|
|
101
|
+
The CLI sends anonymous usage events (command name, CLI version, OS, duration, success/error class — **never prompts, file contents, or arguments**) to help us improve it. Opt out any time:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
videodraft config set telemetry false # or VIDEODRAFT_TELEMETRY=0 / DO_NOT_TRACK=1
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Embedding (`videodraft/client`)
|
|
108
|
+
|
|
109
|
+
The CLI's core is exported for programmatic use (Node ≥ 20 and Bun):
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { VideoDraftClient, resolveAuth } from "videodraft/client";
|
|
113
|
+
|
|
114
|
+
const { tokenProvider, baseUrl } = resolveAuth({}); // flag/env/config-store resolution
|
|
115
|
+
const client = new VideoDraftClient({ tokenProvider, baseUrl });
|
|
116
|
+
const me = await client.callTool("whoami");
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT © VideoDraft
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-RPC 2.0 client for the VideoDraft MCP endpoint (POST {base}/api/mcp).
|
|
3
|
+
*
|
|
4
|
+
* Runtime-agnostic by design: no commander, no prompts, no process.exit, no
|
|
5
|
+
* console — this file is part of the `videodraft/client` subpath export the
|
|
6
|
+
* macOS app's sidecar consumes. Errors are thrown, never printed.
|
|
7
|
+
*/
|
|
8
|
+
interface TokenProvider {
|
|
9
|
+
/** Return a bearer token (vd_mcp_...). Throw AuthError when none is available. */
|
|
10
|
+
getAccessToken(): Promise<string>;
|
|
11
|
+
/**
|
|
12
|
+
* Called once after a 401. Return a fresh token to retry with, or null to
|
|
13
|
+
* give up (the 401 then surfaces as AuthError).
|
|
14
|
+
*/
|
|
15
|
+
onUnauthorized?(): Promise<string | null>;
|
|
16
|
+
}
|
|
17
|
+
interface VideoDraftClientOptions {
|
|
18
|
+
tokenProvider: TokenProvider;
|
|
19
|
+
baseUrl?: string;
|
|
20
|
+
fetchImpl?: typeof fetch;
|
|
21
|
+
userAgent?: string;
|
|
22
|
+
/** Per-request timeout in ms. Generation submits can be slow; default 300s (server maxDuration). */
|
|
23
|
+
requestTimeoutMs?: number;
|
|
24
|
+
}
|
|
25
|
+
interface McpToolInfo {
|
|
26
|
+
name: string;
|
|
27
|
+
description: string;
|
|
28
|
+
inputSchema: unknown;
|
|
29
|
+
}
|
|
30
|
+
declare class VideoDraftClient {
|
|
31
|
+
readonly baseUrl: string;
|
|
32
|
+
private readonly tokenProvider;
|
|
33
|
+
private readonly fetchImpl;
|
|
34
|
+
private readonly userAgent;
|
|
35
|
+
private readonly requestTimeoutMs;
|
|
36
|
+
private nextId;
|
|
37
|
+
constructor(options: VideoDraftClientOptions);
|
|
38
|
+
get endpoint(): string;
|
|
39
|
+
rpc<T = any>(method: string, params?: unknown): Promise<T>;
|
|
40
|
+
private post;
|
|
41
|
+
/**
|
|
42
|
+
* Batch several JSON-RPC requests into ONE HTTP round trip (the server
|
|
43
|
+
* implements JSON-RPC 2.0 batching). With N concurrent jobs this turns N
|
|
44
|
+
* polling requests per tick into 1 — the difference between 50 waiting CLIs
|
|
45
|
+
* generating ~17 req/s and ~0.3 req/s against /api/mcp.
|
|
46
|
+
* Results are matched by id (order-independent per spec).
|
|
47
|
+
*/
|
|
48
|
+
rpcBatch(calls: Array<{
|
|
49
|
+
method: string;
|
|
50
|
+
params?: unknown;
|
|
51
|
+
}>): Promise<any[]>;
|
|
52
|
+
/**
|
|
53
|
+
* Call several tools in one batched HTTP request. Per-item failures come
|
|
54
|
+
* back as { ok:false, error } instead of throwing, so one failed job can't
|
|
55
|
+
* abort polling of its siblings.
|
|
56
|
+
*/
|
|
57
|
+
callToolBatch(calls: Array<{
|
|
58
|
+
name: string;
|
|
59
|
+
args?: Record<string, unknown>;
|
|
60
|
+
}>): Promise<Array<{
|
|
61
|
+
ok: boolean;
|
|
62
|
+
result?: any;
|
|
63
|
+
error?: string;
|
|
64
|
+
}>>;
|
|
65
|
+
/**
|
|
66
|
+
* Call an MCP tool and return its parsed result.
|
|
67
|
+
* The server wraps results as { content: [{type:"text", text}], isError } —
|
|
68
|
+
* text is JSON for successes and "Error: ..." for tool failures.
|
|
69
|
+
*/
|
|
70
|
+
callTool<T = any>(name: string, args?: Record<string, unknown>): Promise<T>;
|
|
71
|
+
listTools(): Promise<McpToolInfo[]>;
|
|
72
|
+
ping(): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
/** Static token provider — for PATs and pre-resolved tokens. */
|
|
75
|
+
declare function staticTokenProvider(token: string): TokenProvider;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Token resolution + the multi-process-safe OAuth refresh provider.
|
|
79
|
+
*
|
|
80
|
+
* Resolution order (first hit wins):
|
|
81
|
+
* 1. explicit token (--token flag)
|
|
82
|
+
* 2. VIDEODRAFT_API_KEY env
|
|
83
|
+
* 3. the profile in the config store (PAT, or OAuth with auto-refresh)
|
|
84
|
+
*
|
|
85
|
+
* OAuth refresh tokens are SINGLE-USE (the server rotates them), and the CLI
|
|
86
|
+
* shares its config store with other consumers (the macOS app's sidecar). So
|
|
87
|
+
* refresh runs under a cross-process file lock and re-reads the store after
|
|
88
|
+
* acquiring it — if another process already rotated, we use its fresh token
|
|
89
|
+
* instead of redeeming a now-dead refresh token.
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
interface ResolvedAuth {
|
|
93
|
+
tokenProvider: TokenProvider;
|
|
94
|
+
baseUrl: string;
|
|
95
|
+
source: "flag" | "env" | "profile";
|
|
96
|
+
profileName?: string;
|
|
97
|
+
}
|
|
98
|
+
declare function profileTokenProvider(profileName: string, env?: NodeJS.ProcessEnv): TokenProvider;
|
|
99
|
+
declare function resolveAuth(options: {
|
|
100
|
+
token?: string;
|
|
101
|
+
baseUrl?: string;
|
|
102
|
+
profile?: string;
|
|
103
|
+
env?: NodeJS.ProcessEnv;
|
|
104
|
+
}): ResolvedAuth;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Config store: $VIDEODRAFT_CONFIG_DIR || $XDG_CONFIG_HOME/videodraft || ~/.config/videodraft
|
|
108
|
+
*
|
|
109
|
+
* Deliberately NOT ~/.videodraft — the VideoDraft macOS app owns ~/videodraft/
|
|
110
|
+
* (user workspaces) and dot/no-dot adjacency invites confusion.
|
|
111
|
+
*
|
|
112
|
+
* The schema below is a documented contract: the macOS app's sidecar reads the
|
|
113
|
+
* same store to inherit `videodraft login` credentials (the same way it
|
|
114
|
+
* inherits `claude login` / `codex login`). Bump `version` on breaking changes.
|
|
115
|
+
*/
|
|
116
|
+
interface Profile {
|
|
117
|
+
base_url: string;
|
|
118
|
+
auth_kind: "pat" | "oauth";
|
|
119
|
+
access_token: string;
|
|
120
|
+
/** OAuth only. */
|
|
121
|
+
refresh_token?: string;
|
|
122
|
+
/** OAuth only — ISO timestamp the access token expires at. */
|
|
123
|
+
expires_at?: string;
|
|
124
|
+
/** OAuth only — the client_id the grant belongs to. */
|
|
125
|
+
client_id?: string;
|
|
126
|
+
}
|
|
127
|
+
interface CliConfig {
|
|
128
|
+
version: 1;
|
|
129
|
+
active_profile: string;
|
|
130
|
+
profiles: Record<string, Profile>;
|
|
131
|
+
/** Anonymous machine id for opt-out telemetry. */
|
|
132
|
+
anonymous_id?: string;
|
|
133
|
+
/** Explicit telemetry opt-out persisted via `videodraft config set telemetry false`. */
|
|
134
|
+
telemetry?: boolean;
|
|
135
|
+
/** Epoch ms of the last npm update check. */
|
|
136
|
+
last_update_check?: number;
|
|
137
|
+
}
|
|
138
|
+
declare const DEFAULT_BASE_URL = "https://app.videodraft.ai";
|
|
139
|
+
declare function configDir(env?: NodeJS.ProcessEnv): string;
|
|
140
|
+
declare function configPath(env?: NodeJS.ProcessEnv): string;
|
|
141
|
+
declare function readConfig(env?: NodeJS.ProcessEnv): CliConfig;
|
|
142
|
+
/** Atomic write (tmp + rename), 0700 dir / 0600 file. */
|
|
143
|
+
declare function writeConfig(config: CliConfig, env?: NodeJS.ProcessEnv): void;
|
|
144
|
+
declare function updateConfig(mutate: (config: CliConfig) => void, env?: NodeJS.ProcessEnv): CliConfig;
|
|
145
|
+
declare function getProfile(name?: string, env?: NodeJS.ProcessEnv): {
|
|
146
|
+
name: string;
|
|
147
|
+
profile: Profile | undefined;
|
|
148
|
+
config: CliConfig;
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Polling for async work: generation jobs (check_generation_status) and
|
|
153
|
+
* video exports (check_export_status).
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
interface PollOptions {
|
|
157
|
+
intervalMs?: number;
|
|
158
|
+
timeoutMs?: number;
|
|
159
|
+
/**
|
|
160
|
+
* Adaptive backoff (default true): the effective interval grows as a job
|
|
161
|
+
* runs long (base → ×2 after 60s → ×3 after 3min, capped at 15s) with ±10%
|
|
162
|
+
* jitter so many concurrent CLIs don't poll in lockstep. Set false (the CLI
|
|
163
|
+
* does this when --wait-interval is passed explicitly) for a fixed cadence.
|
|
164
|
+
*/
|
|
165
|
+
adaptive?: boolean;
|
|
166
|
+
/** Called every poll with the latest payload (drives spinners). */
|
|
167
|
+
onTick?: (status: string, payload: any) => void;
|
|
168
|
+
}
|
|
169
|
+
/** Effective poll delay for a job that's been running `elapsedMs`. */
|
|
170
|
+
declare function nextPollDelay(baseMs: number, elapsedMs: number, adaptive?: boolean): number;
|
|
171
|
+
interface GenerationResult {
|
|
172
|
+
status: string;
|
|
173
|
+
outputUrls: string[];
|
|
174
|
+
payload: any;
|
|
175
|
+
}
|
|
176
|
+
/** Extract output media URLs across the server's result shapes. */
|
|
177
|
+
declare function extractOutputUrls(payload: any): string[];
|
|
178
|
+
declare function pollGeneration(client: VideoDraftClient, jobId: string, options?: PollOptions): Promise<GenerationResult>;
|
|
179
|
+
/**
|
|
180
|
+
* Poll MANY jobs from ONE process with ONE batched JSON-RPC request per tick.
|
|
181
|
+
* This is the multi-CLI answer: N parallel generations should not mean N idle
|
|
182
|
+
* Node processes and N req/tick — submit with --no-wait, then
|
|
183
|
+
* `videodraft wait <id1> <id2> ...` (or the macOS app's sidecar calling this).
|
|
184
|
+
* Per-job tool failures resolve that job as status "failed" without aborting
|
|
185
|
+
* the rest.
|
|
186
|
+
*/
|
|
187
|
+
declare function pollGenerationsBatch(client: VideoDraftClient, jobIds: string[], options?: PollOptions & {
|
|
188
|
+
onJobDone?: (jobId: string, result: GenerationResult) => void;
|
|
189
|
+
}): Promise<Map<string, GenerationResult>>;
|
|
190
|
+
declare function pollExport(client: VideoDraftClient, ref: {
|
|
191
|
+
exportId?: string;
|
|
192
|
+
projectId?: string;
|
|
193
|
+
}, options?: PollOptions): Promise<{
|
|
194
|
+
status: string;
|
|
195
|
+
videoUrl?: string;
|
|
196
|
+
payload: any;
|
|
197
|
+
}>;
|
|
198
|
+
/** Poll many jobs concurrently (used by `shots --wait` batches). */
|
|
199
|
+
declare function pollGenerations(client: VideoDraftClient, jobIds: string[], options?: PollOptions): Promise<GenerationResult[]>;
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Download generated media to local files.
|
|
203
|
+
*
|
|
204
|
+
* Path templates (genmedia-style): {job_id} {index} {ext} {name}
|
|
205
|
+
* videodraft generate image "..." --download "./out/{job_id}_{index}.{ext}"
|
|
206
|
+
* A template without placeholders and without an extension is treated as a
|
|
207
|
+
* directory: <dir>/<job_id>_<index>.<ext>.
|
|
208
|
+
*/
|
|
209
|
+
interface DownloadedFile {
|
|
210
|
+
url: string;
|
|
211
|
+
path: string;
|
|
212
|
+
bytes: number;
|
|
213
|
+
}
|
|
214
|
+
declare function extFromUrl(url: string, fallback?: string): string;
|
|
215
|
+
declare function renderTemplate(template: string, vars: {
|
|
216
|
+
job_id?: string;
|
|
217
|
+
index: number;
|
|
218
|
+
ext: string;
|
|
219
|
+
name?: string;
|
|
220
|
+
}): string;
|
|
221
|
+
declare function downloadUrl(url: string, destPath: string, fetchImpl?: typeof fetch): Promise<DownloadedFile>;
|
|
222
|
+
declare function downloadOutputs(urls: string[], template: string, vars: {
|
|
223
|
+
job_id?: string;
|
|
224
|
+
name?: string;
|
|
225
|
+
}, fetchImpl?: typeof fetch): Promise<DownloadedFile[]>;
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Local-file upload via the MCP two-step flow:
|
|
229
|
+
* create_media_upload → PUT bytes to the presigned upload_url → finalize_media_upload
|
|
230
|
+
* The bytes go directly to GCS; they never pass through the MCP server.
|
|
231
|
+
*/
|
|
232
|
+
|
|
233
|
+
declare function guessContentType(filename: string): string | undefined;
|
|
234
|
+
interface UploadResult {
|
|
235
|
+
url: string;
|
|
236
|
+
file_path?: string;
|
|
237
|
+
[key: string]: unknown;
|
|
238
|
+
}
|
|
239
|
+
declare function uploadFile(client: VideoDraftClient, localPath: string, options?: {
|
|
240
|
+
contentType?: string;
|
|
241
|
+
fetchImpl?: typeof fetch;
|
|
242
|
+
}): Promise<UploadResult>;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Error taxonomy + stable exit codes.
|
|
246
|
+
*
|
|
247
|
+
* 0 success
|
|
248
|
+
* 1 generic / server / network error
|
|
249
|
+
* 2 usage error (bad flags/args — commander's default)
|
|
250
|
+
* 3 authentication required or invalid
|
|
251
|
+
* 4 insufficient credits
|
|
252
|
+
*
|
|
253
|
+
* Agents and scripts can branch on these; they are part of the CLI contract
|
|
254
|
+
* and documented in the README.
|
|
255
|
+
*/
|
|
256
|
+
declare const EXIT: {
|
|
257
|
+
readonly OK: 0;
|
|
258
|
+
readonly ERROR: 1;
|
|
259
|
+
readonly USAGE: 2;
|
|
260
|
+
readonly AUTH: 3;
|
|
261
|
+
readonly CREDITS: 4;
|
|
262
|
+
};
|
|
263
|
+
declare class CliError extends Error {
|
|
264
|
+
exitCode: number;
|
|
265
|
+
/** One-line remediation shown under the error (human mode only). */
|
|
266
|
+
hint?: string;
|
|
267
|
+
constructor(message: string, exitCode?: number, hint?: string);
|
|
268
|
+
}
|
|
269
|
+
declare class AuthError extends CliError {
|
|
270
|
+
constructor(message?: string);
|
|
271
|
+
}
|
|
272
|
+
/** JSON-RPC layer error (the envelope, not the tool). */
|
|
273
|
+
declare class RpcError extends CliError {
|
|
274
|
+
code: number;
|
|
275
|
+
data?: unknown;
|
|
276
|
+
constructor(code: number, message: string, data?: unknown);
|
|
277
|
+
}
|
|
278
|
+
/** A tools/call result that came back isError:true. */
|
|
279
|
+
declare class ToolError extends CliError {
|
|
280
|
+
toolName: string;
|
|
281
|
+
constructor(toolName: string, message: string);
|
|
282
|
+
}
|
|
283
|
+
declare class TimeoutError extends CliError {
|
|
284
|
+
constructor(message: string);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* OAuth 2.1 authorization-code + PKCE flow against the VideoDraft AS,
|
|
289
|
+
* using an RFC 8252 loopback redirect (http://127.0.0.1:<ephemeral-port>/callback).
|
|
290
|
+
*
|
|
291
|
+
* Server contract (app/api/oauth/* in the VideoDraft app):
|
|
292
|
+
* GET /api/oauth/authorize ?response_type=code&client_id&redirect_uri&scope
|
|
293
|
+
* &state&code_challenge&code_challenge_method=S256&resource
|
|
294
|
+
* POST /api/oauth/token form or JSON; authorization_code | refresh_token grants
|
|
295
|
+
* POST /api/oauth/register RFC 7591 DCR (https or http-loopback redirect URIs only)
|
|
296
|
+
* POST /api/oauth/revoke RFC 7009
|
|
297
|
+
*
|
|
298
|
+
* Client identity: the static public client `vd_client_cli` (pre-registered in
|
|
299
|
+
* oauth_clients — see sql/ in this repo). When that id is missing on the target
|
|
300
|
+
* server (e.g. a fresh local stack), we fall back to Dynamic Client Registration
|
|
301
|
+
* and persist the issued client_id in the profile.
|
|
302
|
+
*/
|
|
303
|
+
declare const STATIC_CLI_CLIENT_ID = "vd_client_cli";
|
|
304
|
+
interface OAuthTokens {
|
|
305
|
+
access_token: string;
|
|
306
|
+
refresh_token: string;
|
|
307
|
+
expires_in: number;
|
|
308
|
+
scope?: string;
|
|
309
|
+
}
|
|
310
|
+
declare function createPkcePair(): {
|
|
311
|
+
verifier: string;
|
|
312
|
+
challenge: string;
|
|
313
|
+
};
|
|
314
|
+
declare function buildAuthorizeUrl(params: {
|
|
315
|
+
baseUrl: string;
|
|
316
|
+
clientId: string;
|
|
317
|
+
redirectUri: string;
|
|
318
|
+
state: string;
|
|
319
|
+
codeChallenge: string;
|
|
320
|
+
}): string;
|
|
321
|
+
/**
|
|
322
|
+
* Is this client_id known to the server? The authorize endpoint renders a
|
|
323
|
+
* non-redirect 400 HTML page for an unknown client, and 3xx-redirects to the
|
|
324
|
+
* consent page for a valid request — probe with redirect:"manual" so we can
|
|
325
|
+
* fall back to DCR before ever opening a browser tab on an error page.
|
|
326
|
+
*/
|
|
327
|
+
declare function probeClientId(baseUrl: string, clientId: string, redirectUri: string, fetchImpl?: typeof fetch): Promise<boolean>;
|
|
328
|
+
/** RFC 7591 dynamic registration fallback. Returns the issued client_id. */
|
|
329
|
+
declare function registerCliClient(baseUrl: string, fetchImpl?: typeof fetch): Promise<string>;
|
|
330
|
+
/**
|
|
331
|
+
* Run the loopback listener + browser round trip and return the authorization
|
|
332
|
+
* code. `onAuthorizeUrl` receives the URL to open (the command layer opens the
|
|
333
|
+
* browser and prints it — this module stays headless/testable).
|
|
334
|
+
*/
|
|
335
|
+
declare function authorizeViaLoopback(params: {
|
|
336
|
+
baseUrl: string;
|
|
337
|
+
clientId: string;
|
|
338
|
+
onAuthorizeUrl: (url: string) => void | Promise<void>;
|
|
339
|
+
timeoutMs?: number;
|
|
340
|
+
fetchImpl?: typeof fetch;
|
|
341
|
+
}): Promise<{
|
|
342
|
+
code: string;
|
|
343
|
+
redirectUri: string;
|
|
344
|
+
verifier: string;
|
|
345
|
+
}>;
|
|
346
|
+
declare function exchangeCode(params: {
|
|
347
|
+
baseUrl: string;
|
|
348
|
+
clientId: string;
|
|
349
|
+
code: string;
|
|
350
|
+
redirectUri: string;
|
|
351
|
+
verifier: string;
|
|
352
|
+
fetchImpl?: typeof fetch;
|
|
353
|
+
}): Promise<OAuthTokens>;
|
|
354
|
+
declare function refreshAccessToken(params: {
|
|
355
|
+
baseUrl: string;
|
|
356
|
+
clientId: string;
|
|
357
|
+
refreshToken: string;
|
|
358
|
+
fetchImpl?: typeof fetch;
|
|
359
|
+
}): Promise<OAuthTokens | null>;
|
|
360
|
+
/** RFC 7009 revocation — best-effort, used by `videodraft logout`. */
|
|
361
|
+
declare function revokeToken(baseUrl: string, token: string, fetchImpl?: typeof fetch): Promise<void>;
|
|
362
|
+
|
|
363
|
+
export { AuthError, type CliConfig, CliError, DEFAULT_BASE_URL, type DownloadedFile, EXIT, type GenerationResult, type McpToolInfo, type PollOptions, type Profile, type ResolvedAuth, RpcError, STATIC_CLI_CLIENT_ID, TimeoutError, type TokenProvider, ToolError, type UploadResult, VideoDraftClient, type VideoDraftClientOptions, authorizeViaLoopback, buildAuthorizeUrl, configDir, configPath, createPkcePair, downloadOutputs, downloadUrl, exchangeCode, extFromUrl, extractOutputUrls, getProfile, guessContentType, nextPollDelay, pollExport, pollGeneration, pollGenerations, pollGenerationsBatch, probeClientId, profileTokenProvider, readConfig, refreshAccessToken, registerCliClient, renderTemplate, resolveAuth, revokeToken, staticTokenProvider, updateConfig, uploadFile, writeConfig };
|