@program-video/cli 0.1.12 → 0.2.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.
@@ -0,0 +1,414 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/lib/output.ts
4
+ import chalk from "chalk";
5
+ function outputSuccess(data, options = {}) {
6
+ if (options.json) {
7
+ const result = { success: true, data };
8
+ console.log(JSON.stringify(result, null, 2));
9
+ } else {
10
+ console.log(data);
11
+ }
12
+ }
13
+ function outputError(error, options = {}) {
14
+ if (options.json) {
15
+ const result = { success: false, error };
16
+ console.log(JSON.stringify(result, null, 2));
17
+ } else {
18
+ console.error(chalk.red("Error:"), error);
19
+ }
20
+ }
21
+ function formatTable(headers, rows, options = {}) {
22
+ const indent = " ".repeat(options.indent ?? 0);
23
+ const widths = headers.map((h, i) => {
24
+ const maxRow = Math.max(...rows.map((r) => (r[i] ?? "").length));
25
+ return Math.max(h.length, maxRow);
26
+ });
27
+ const headerLine = headers.map((h, i) => chalk.bold(h.padEnd(widths[i] ?? 0))).join(" ");
28
+ const separator = widths.map((w) => "-".repeat(w)).join(" ");
29
+ const formattedRows = rows.map(
30
+ (row) => row.map((cell, i) => (cell || "").padEnd(widths[i] ?? 0)).join(" ")
31
+ );
32
+ return [
33
+ indent + headerLine,
34
+ indent + separator,
35
+ ...formattedRows.map((r) => indent + r)
36
+ ].join("\n");
37
+ }
38
+ function formatKeyValue(items, options = {}) {
39
+ const indent = " ".repeat(options.indent ?? 0);
40
+ const maxKeyLength = Math.max(...items.map((item) => item.key.length));
41
+ return items.map(
42
+ (item) => indent + chalk.dim(item.key.padEnd(maxKeyLength) + ":") + " " + item.value
43
+ ).join("\n");
44
+ }
45
+ function formatSuccess(message) {
46
+ return chalk.green("\u2713") + " " + message;
47
+ }
48
+ function formatWarning(message) {
49
+ return chalk.yellow("\u26A0") + " " + message;
50
+ }
51
+
52
+ // src/lib/local-convex.ts
53
+ import { existsSync, readFileSync } from "fs";
54
+ import { homedir } from "os";
55
+ import { join } from "path";
56
+ var LOCAL_URL = "http://127.0.0.1:3210";
57
+ var _cachedIdentity = null;
58
+ function getIdentity() {
59
+ if (_cachedIdentity) return _cachedIdentity;
60
+ const identityPath = join(
61
+ homedir(),
62
+ "Library",
63
+ "Application Support",
64
+ "video.program.desktop",
65
+ "cli-identity.json"
66
+ );
67
+ try {
68
+ if (existsSync(identityPath)) {
69
+ const raw = JSON.parse(readFileSync(identityPath, "utf-8"));
70
+ if (raw.userId && raw.organizationId) {
71
+ _cachedIdentity = raw;
72
+ return raw;
73
+ }
74
+ }
75
+ } catch {
76
+ }
77
+ throw new Error(
78
+ "Local desktop identity not found. Sign in to Program in the desktop app first."
79
+ );
80
+ }
81
+ function getLocalUserId() {
82
+ return getIdentity().userId;
83
+ }
84
+ function getLocalOrgId() {
85
+ return getIdentity().organizationId;
86
+ }
87
+ async function convexQuery(functionPath, args) {
88
+ const res = await fetch(`${LOCAL_URL}/api/query`, {
89
+ method: "POST",
90
+ headers: { "Content-Type": "application/json" },
91
+ body: JSON.stringify({ path: functionPath, args, format: "json" })
92
+ });
93
+ if (!res.ok) {
94
+ throw new Error(`Convex query failed: ${res.status} ${res.statusText}`);
95
+ }
96
+ const data = await res.json();
97
+ if (data.status === "error") {
98
+ throw new Error(`Convex error: ${data.errorMessage}`);
99
+ }
100
+ return data.value;
101
+ }
102
+ async function convexMutation(functionPath, args) {
103
+ const res = await fetch(`${LOCAL_URL}/api/mutation`, {
104
+ method: "POST",
105
+ headers: { "Content-Type": "application/json" },
106
+ body: JSON.stringify({ path: functionPath, args, format: "json" })
107
+ });
108
+ if (!res.ok) {
109
+ throw new Error(`Convex mutation failed: ${res.status} ${res.statusText}`);
110
+ }
111
+ const data = await res.json();
112
+ if (data.status === "error") {
113
+ throw new Error(`Convex error: ${data.errorMessage}`);
114
+ }
115
+ return data.value;
116
+ }
117
+ async function isLocalAvailable() {
118
+ try {
119
+ const res = await fetch(`${LOCAL_URL}/version`, {
120
+ signal: AbortSignal.timeout(2e3)
121
+ });
122
+ return res.ok;
123
+ } catch {
124
+ return false;
125
+ }
126
+ }
127
+ async function listResearch(platform, limit) {
128
+ return convexQuery("functions/research:localList", {
129
+ organizationId: getLocalOrgId(),
130
+ ...platform ? { platform } : {},
131
+ ...limit ? { limit } : {}
132
+ });
133
+ }
134
+ async function createResearch(sourceUrl, note) {
135
+ return convexMutation("functions/research:localCreate", {
136
+ organizationId: getLocalOrgId(),
137
+ userId: getLocalUserId(),
138
+ sourceUrl,
139
+ ...note ? { note } : {}
140
+ });
141
+ }
142
+ async function getResearch(id) {
143
+ return convexQuery("functions/research:localGet", {
144
+ organizationId: getLocalOrgId(),
145
+ id
146
+ });
147
+ }
148
+ async function patchResearch(id, metadata) {
149
+ return convexMutation("functions/research:localPatch", {
150
+ organizationId: getLocalOrgId(),
151
+ id,
152
+ metadata
153
+ });
154
+ }
155
+ async function getIntegrationApiKey(provider) {
156
+ try {
157
+ return await convexQuery(
158
+ "functions/integrations:localGetApiKey",
159
+ { organizationId: getLocalOrgId(), provider }
160
+ );
161
+ } catch {
162
+ return null;
163
+ }
164
+ }
165
+ async function upsertStep(researchItemId, step, label, status, extra) {
166
+ try {
167
+ await convexMutation("functions/research:localUpsertStep", {
168
+ researchItemId,
169
+ step,
170
+ label,
171
+ status,
172
+ ...extra
173
+ });
174
+ } catch {
175
+ }
176
+ }
177
+ async function clearSteps(researchItemId) {
178
+ try {
179
+ await convexMutation("functions/research:localClearSteps", {
180
+ researchItemId
181
+ });
182
+ } catch {
183
+ }
184
+ }
185
+ async function listTemplates(limit) {
186
+ return convexQuery("functions/templates:localList", {
187
+ organizationId: getLocalOrgId(),
188
+ ...limit ? { limit } : {}
189
+ });
190
+ }
191
+ async function getTemplate(id) {
192
+ return convexQuery("functions/templates:localGet", {
193
+ organizationId: getLocalOrgId(),
194
+ id
195
+ });
196
+ }
197
+ async function createTemplate(name, steps, description, metadata) {
198
+ return convexMutation("functions/templates:localCreate", {
199
+ organizationId: getLocalOrgId(),
200
+ userId: getLocalUserId(),
201
+ name,
202
+ steps,
203
+ description,
204
+ metadata
205
+ });
206
+ }
207
+ async function updateTemplate(id, updates) {
208
+ return convexMutation("functions/templates:localUpdate", {
209
+ organizationId: getLocalOrgId(),
210
+ id,
211
+ ...updates
212
+ });
213
+ }
214
+ async function createExecution(templateId, input) {
215
+ return convexMutation("functions/templates:localCreateExecution", {
216
+ organizationId: getLocalOrgId(),
217
+ userId: getLocalUserId(),
218
+ templateId,
219
+ input
220
+ });
221
+ }
222
+ async function updateExecution(id, updates) {
223
+ return convexMutation("functions/templates:localUpdateExecution", {
224
+ id,
225
+ ...updates
226
+ });
227
+ }
228
+ async function createExecutionLog(executionId, log) {
229
+ return convexMutation("functions/templates:localCreateExecutionLog", {
230
+ executionId,
231
+ organizationId: getLocalOrgId(),
232
+ ...log
233
+ });
234
+ }
235
+ async function listCompositions(limit) {
236
+ return convexQuery("functions/compositions:localList", {
237
+ organizationId: getLocalOrgId(),
238
+ ...limit ? { limit } : {}
239
+ });
240
+ }
241
+ async function createComposition(title, opts) {
242
+ return convexMutation("functions/compositions:localCreate", {
243
+ organizationId: getLocalOrgId(),
244
+ userId: getLocalUserId(),
245
+ title,
246
+ description: opts?.description,
247
+ fps: opts?.fps ?? 30,
248
+ width: opts?.width ?? 1920,
249
+ height: opts?.height ?? 1080
250
+ });
251
+ }
252
+ async function getComposition(id) {
253
+ return convexQuery(
254
+ "functions/compositions:localGet",
255
+ { organizationId: getLocalOrgId(), id }
256
+ );
257
+ }
258
+ async function updateComposition(id, updates) {
259
+ return convexMutation("functions/compositions:localUpdate", {
260
+ organizationId: getLocalOrgId(),
261
+ id,
262
+ ...updates
263
+ });
264
+ }
265
+ async function addScene(compositionId, scene) {
266
+ return convexMutation("functions/compositions:localAddScene", {
267
+ organizationId: getLocalOrgId(),
268
+ id: compositionId,
269
+ scene
270
+ });
271
+ }
272
+ async function updateScene(compositionId, sceneId, updates) {
273
+ return convexMutation("functions/compositions:localUpdateScene", {
274
+ organizationId: getLocalOrgId(),
275
+ id: compositionId,
276
+ sceneId,
277
+ updates
278
+ });
279
+ }
280
+ async function deleteScene(compositionId, sceneId) {
281
+ return convexMutation("functions/compositions:localDeleteScene", {
282
+ organizationId: getLocalOrgId(),
283
+ id: compositionId,
284
+ sceneId
285
+ });
286
+ }
287
+ async function deleteAllScenes(compositionId) {
288
+ return convexMutation("functions/compositions:localDeleteAllScenes", {
289
+ organizationId: getLocalOrgId(),
290
+ id: compositionId
291
+ });
292
+ }
293
+ async function generateUploadUrl() {
294
+ return convexMutation("functions/files:localGenerateUploadUrl", {});
295
+ }
296
+ async function uploadToStorage(uploadUrl, fileData, contentType) {
297
+ const res = await fetch(uploadUrl, {
298
+ method: "POST",
299
+ headers: { "Content-Type": contentType },
300
+ body: fileData
301
+ });
302
+ if (!res.ok) {
303
+ throw new Error(`Storage upload failed: ${res.status} ${res.statusText}`);
304
+ }
305
+ const data = await res.json();
306
+ return data.storageId;
307
+ }
308
+ async function getStorageUrl(storageId) {
309
+ return convexQuery("functions/files:localGetStorageUrl", {
310
+ storageId
311
+ });
312
+ }
313
+ function inferContentType(url) {
314
+ const ext = (url.split("?")[0] ?? url).split(".").pop()?.toLowerCase() ?? "";
315
+ const mimeMap = {
316
+ webp: "image/webp",
317
+ jpg: "image/jpeg",
318
+ jpeg: "image/jpeg",
319
+ png: "image/png",
320
+ gif: "image/gif",
321
+ mp4: "video/mp4",
322
+ webm: "video/webm",
323
+ mov: "video/quicktime"
324
+ };
325
+ return mimeMap[ext] ?? "application/octet-stream";
326
+ }
327
+ async function saveRemoteMediaToStorage(remoteUrl) {
328
+ const res = await fetch(remoteUrl);
329
+ if (!res.ok) {
330
+ throw new Error(`Failed to download media (${res.status}): ${remoteUrl}`);
331
+ }
332
+ const contentType = res.headers.get("content-type") ?? inferContentType(remoteUrl);
333
+ const buffer = Buffer.from(await res.arrayBuffer());
334
+ const uploadUrl = await generateUploadUrl();
335
+ const storageId = await uploadToStorage(uploadUrl, buffer, contentType);
336
+ const servingUrl = await getStorageUrl(storageId);
337
+ if (!servingUrl) {
338
+ throw new Error("Failed to get serving URL for uploaded media");
339
+ }
340
+ return servingUrl;
341
+ }
342
+ async function updateExecutionLog(id, updates) {
343
+ return convexMutation("functions/templates:localUpdateExecutionLog", {
344
+ id,
345
+ ...updates
346
+ });
347
+ }
348
+ async function recordUsage(entry) {
349
+ return convexMutation("functions/usage:localRecordUsage", {
350
+ organizationId: getLocalOrgId(),
351
+ userId: getLocalUserId(),
352
+ ...entry
353
+ });
354
+ }
355
+ async function createStepExecution(entry) {
356
+ return convexMutation(
357
+ "functions/templates:localCreateStepExecution",
358
+ {
359
+ organizationId: getLocalOrgId(),
360
+ userId: getLocalUserId(),
361
+ ...entry
362
+ }
363
+ );
364
+ }
365
+ async function updateStepExecution(id, updates) {
366
+ return convexMutation(
367
+ "functions/templates:localUpdateStepExecution",
368
+ {
369
+ id,
370
+ ...updates
371
+ }
372
+ );
373
+ }
374
+
375
+ export {
376
+ outputSuccess,
377
+ outputError,
378
+ formatTable,
379
+ formatKeyValue,
380
+ formatSuccess,
381
+ formatWarning,
382
+ isLocalAvailable,
383
+ listResearch,
384
+ createResearch,
385
+ getResearch,
386
+ patchResearch,
387
+ getIntegrationApiKey,
388
+ upsertStep,
389
+ clearSteps,
390
+ listTemplates,
391
+ getTemplate,
392
+ createTemplate,
393
+ updateTemplate,
394
+ createExecution,
395
+ updateExecution,
396
+ createExecutionLog,
397
+ listCompositions,
398
+ createComposition,
399
+ getComposition,
400
+ updateComposition,
401
+ addScene,
402
+ updateScene,
403
+ deleteScene,
404
+ deleteAllScenes,
405
+ generateUploadUrl,
406
+ uploadToStorage,
407
+ getStorageUrl,
408
+ saveRemoteMediaToStorage,
409
+ updateExecutionLog,
410
+ recordUsage,
411
+ createStepExecution,
412
+ updateStepExecution
413
+ };
414
+ //# sourceMappingURL=chunk-2PMNEXGG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/lib/output.ts","../src/lib/local-convex.ts"],"sourcesContent":["import chalk from \"chalk\";\n\nexport interface OutputOptions {\n json?: boolean;\n}\n\nexport interface SuccessResult<T> {\n success: true;\n data: T;\n}\n\nexport interface ErrorResult {\n success: false;\n error: string;\n}\n\nexport type Result<T> = SuccessResult<T> | ErrorResult;\n\n/**\n * Output a success result in the appropriate format\n */\nexport function outputSuccess<T>(data: T, options: OutputOptions = {}): void {\n if (options.json) {\n const result: SuccessResult<T> = { success: true, data };\n console.log(JSON.stringify(result, null, 2));\n } else {\n // For human-readable output, we'll handle this per-command\n // This is a fallback that just pretty-prints\n console.log(data);\n }\n}\n\n/**\n * Output an error result in the appropriate format\n */\nexport function outputError(error: string, options: OutputOptions = {}): void {\n if (options.json) {\n const result: ErrorResult = { success: false, error };\n console.log(JSON.stringify(result, null, 2));\n } else {\n console.error(chalk.red(\"Error:\"), error);\n }\n}\n\n/**\n * Format a table for human-readable output\n */\nexport function formatTable(\n headers: string[],\n rows: string[][],\n options: { indent?: number } = {},\n): string {\n const indent = \" \".repeat(options.indent ?? 0);\n\n // Calculate column widths\n const widths = headers.map((h, i) => {\n const maxRow = Math.max(...rows.map((r) => (r[i] ?? \"\").length));\n return Math.max(h.length, maxRow);\n });\n\n // Format header\n const headerLine = headers\n .map((h, i) => chalk.bold(h.padEnd(widths[i] ?? 0)))\n .join(\" \");\n\n // Format separator\n const separator = widths.map((w) => \"-\".repeat(w)).join(\" \");\n\n // Format rows\n const formattedRows = rows.map((row) =>\n row.map((cell, i) => (cell || \"\").padEnd(widths[i] ?? 0)).join(\" \"),\n );\n\n return [\n indent + headerLine,\n indent + separator,\n ...formattedRows.map((r) => indent + r),\n ].join(\"\\n\");\n}\n\n/**\n * Format a key-value list for human-readable output\n */\nexport function formatKeyValue(\n items: { key: string; value: string }[],\n options: { indent?: number } = {},\n): string {\n const indent = \" \".repeat(options.indent ?? 0);\n const maxKeyLength = Math.max(...items.map((item) => item.key.length));\n\n return items\n .map(\n (item) =>\n indent +\n chalk.dim(item.key.padEnd(maxKeyLength) + \":\") +\n \" \" +\n item.value,\n )\n .join(\"\\n\");\n}\n\n/**\n * Format a success message\n */\nexport function formatSuccess(message: string): string {\n return chalk.green(\"✓\") + \" \" + message;\n}\n\n/**\n * Format a warning message\n */\nexport function formatWarning(message: string): string {\n return chalk.yellow(\"⚠\") + \" \" + message;\n}\n\n/**\n * Format an info message\n */\nexport function formatInfo(message: string): string {\n return chalk.blue(\"ℹ\") + \" \" + message;\n}\n","// ============================================\n// LOCAL CONVEX HTTP CLIENT\n// ============================================\n// Plain fetch against the local Convex backend (http://127.0.0.1:3210).\n// No auth needed — local backend only binds loopback.\n// No npm dependencies — keeps the published CLI lightweight.\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nconst LOCAL_URL = \"http://127.0.0.1:3210\";\n\n/** Identity written by the desktop app at sign-in. */\ninterface CliIdentity {\n userId: string;\n organizationId: string;\n}\n\nlet _cachedIdentity: CliIdentity | null = null;\n\nfunction getIdentity(): CliIdentity {\n if (_cachedIdentity) return _cachedIdentity;\n const identityPath = join(\n homedir(),\n \"Library\",\n \"Application Support\",\n \"video.program.desktop\",\n \"cli-identity.json\",\n );\n try {\n if (existsSync(identityPath)) {\n const raw = JSON.parse(readFileSync(identityPath, \"utf-8\")) as CliIdentity;\n if (raw.userId && raw.organizationId) {\n _cachedIdentity = raw;\n return raw;\n }\n }\n } catch {\n // Fall through to explicit auth error\n }\n throw new Error(\n \"Local desktop identity not found. Sign in to Program in the desktop app first.\",\n );\n}\n\n/** Re-export for consumers that need explicit values. */\nexport function getLocalUserId(): string {\n return getIdentity().userId;\n}\n\nexport function getLocalOrgId(): string {\n return getIdentity().organizationId;\n}\n\ninterface ConvexResponse<T> {\n status: \"success\" | \"error\";\n value?: T;\n errorMessage?: string;\n}\n\nasync function convexQuery<T>(\n functionPath: string,\n args: Record<string, unknown>,\n): Promise<T> {\n const res = await fetch(`${LOCAL_URL}/api/query`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ path: functionPath, args, format: \"json\" }),\n });\n\n if (!res.ok) {\n throw new Error(`Convex query failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as ConvexResponse<T>;\n if (data.status === \"error\") {\n throw new Error(`Convex error: ${data.errorMessage}`);\n }\n return data.value as T;\n}\n\nasync function convexMutation<T>(\n functionPath: string,\n args: Record<string, unknown>,\n): Promise<T> {\n const res = await fetch(`${LOCAL_URL}/api/mutation`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ path: functionPath, args, format: \"json\" }),\n });\n\n if (!res.ok) {\n throw new Error(`Convex mutation failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as ConvexResponse<T>;\n if (data.status === \"error\") {\n throw new Error(`Convex error: ${data.errorMessage}`);\n }\n return data.value as T;\n}\n\nexport async function isLocalAvailable(): Promise<boolean> {\n try {\n const res = await fetch(`${LOCAL_URL}/version`, {\n signal: AbortSignal.timeout(2000),\n });\n return res.ok;\n } catch {\n return false;\n }\n}\n\nexport interface LocalResearchItem {\n _id: string;\n _creationTime: number;\n organizationId: string;\n userId: string;\n platform: string;\n sourceUrl: string;\n title?: string;\n authorName?: string;\n authorUrl?: string;\n thumbnailUrl?: string;\n note?: string;\n tags?: string[];\n metadata?: Record<string, unknown>;\n createdAt: number;\n}\n\nexport async function listResearch(\n platform?: string,\n limit?: number,\n): Promise<LocalResearchItem[]> {\n return convexQuery<LocalResearchItem[]>(\"functions/research:localList\", {\n organizationId: getLocalOrgId(),\n ...(platform ? { platform } : {}),\n ...(limit ? { limit } : {}),\n });\n}\n\nexport async function createResearch(\n sourceUrl: string,\n note?: string,\n): Promise<string> {\n return convexMutation<string>(\"functions/research:localCreate\", {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n sourceUrl,\n ...(note ? { note } : {}),\n });\n}\n\nexport async function getResearch(\n id: string,\n): Promise<LocalResearchItem | null> {\n return convexQuery<LocalResearchItem | null>(\"functions/research:localGet\", {\n organizationId: getLocalOrgId(),\n id,\n });\n}\n\nexport async function patchResearch(\n id: string,\n metadata: unknown,\n): Promise<string> {\n return convexMutation<string>(\"functions/research:localPatch\", {\n organizationId: getLocalOrgId(),\n id,\n metadata,\n });\n}\n\n// ============================================\n// INTEGRATION API KEY ACCESS\n// ============================================\n\nexport async function getIntegrationApiKey(\n provider: string,\n): Promise<string | null> {\n try {\n return await convexQuery<string | null>(\n \"functions/integrations:localGetApiKey\",\n { organizationId: getLocalOrgId(), provider },\n );\n } catch {\n return null;\n }\n}\n\n// ============================================\n// ANALYSIS STEP TRACKING\n// ============================================\n\nexport async function upsertStep(\n researchItemId: string,\n step: string,\n label: string,\n status: \"pending\" | \"running\" | \"success\" | \"error\",\n extra?: { startedAt?: number; completedAt?: number; error?: string },\n): Promise<void> {\n try {\n await convexMutation(\"functions/research:localUpsertStep\", {\n researchItemId,\n step,\n label,\n status,\n ...extra,\n });\n } catch {\n // Step tracking is best-effort — don't break the pipeline\n }\n}\n\nexport async function clearSteps(researchItemId: string): Promise<void> {\n try {\n await convexMutation(\"functions/research:localClearSteps\", {\n researchItemId,\n });\n } catch {\n // Best-effort\n }\n}\n\n// ============================================\n// TEMPLATE CRUD\n// ============================================\n\nexport interface LocalTemplate {\n _id: string;\n _creationTime: number;\n name: string;\n description?: string;\n organizationId: string;\n userId?: string;\n steps: unknown[];\n public: boolean;\n metadata?: unknown;\n createdAt: number;\n updatedAt: number;\n}\n\nexport async function listTemplates(limit?: number): Promise<LocalTemplate[]> {\n return convexQuery<LocalTemplate[]>(\"functions/templates:localList\", {\n organizationId: getLocalOrgId(),\n ...(limit ? { limit } : {}),\n });\n}\n\nexport async function getTemplate(id: string): Promise<LocalTemplate | null> {\n return convexQuery<LocalTemplate | null>(\"functions/templates:localGet\", {\n organizationId: getLocalOrgId(),\n id,\n });\n}\n\nexport async function createTemplate(\n name: string,\n steps: unknown[],\n description?: string,\n metadata?: unknown,\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localCreate\", {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n name,\n steps,\n description,\n metadata,\n });\n}\n\nexport async function updateTemplate(\n id: string,\n updates: {\n name?: string;\n description?: string;\n steps?: unknown[];\n metadata?: unknown;\n },\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localUpdate\", {\n organizationId: getLocalOrgId(),\n id,\n ...updates,\n });\n}\n\n// ============================================\n// WORKFLOW EXECUTION TRACKING\n// ============================================\n\nexport async function createExecution(\n templateId: string,\n input?: unknown,\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localCreateExecution\", {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n templateId,\n input,\n });\n}\n\nexport async function updateExecution(\n id: string,\n updates: {\n status?: \"pending\" | \"running\" | \"success\" | \"error\" | \"cancelled\";\n output?: unknown;\n error?: string;\n completedAt?: number;\n duration?: string;\n },\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localUpdateExecution\", {\n id,\n ...updates,\n });\n}\n\nexport async function createExecutionLog(\n executionId: string,\n log: {\n nodeId: string;\n nodeName: string;\n nodeType: string;\n status: \"pending\" | \"running\" | \"success\" | \"error\";\n input?: unknown;\n output?: unknown;\n error?: string;\n startedAt: number;\n completedAt?: number;\n duration?: string;\n },\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localCreateExecutionLog\", {\n executionId,\n organizationId: getLocalOrgId(),\n ...log,\n });\n}\n\n// ============================================\n// COMPOSITION CRUD\n// ============================================\n\nexport interface LocalComposition {\n _id: string;\n _creationTime: number;\n organizationId: string;\n title?: string;\n description?: string;\n script?: string;\n duration?: number;\n fps?: number;\n width?: number;\n height?: number;\n scenes?: unknown[];\n createdAt: number;\n updatedAt: number;\n}\n\nexport async function listCompositions(\n limit?: number,\n): Promise<LocalComposition[]> {\n return convexQuery<LocalComposition[]>(\"functions/compositions:localList\", {\n organizationId: getLocalOrgId(),\n ...(limit ? { limit } : {}),\n });\n}\n\nexport async function createComposition(\n title: string,\n opts?: { width?: number; height?: number; fps?: number; description?: string },\n): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localCreate\", {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n title,\n description: opts?.description,\n fps: opts?.fps ?? 30,\n width: opts?.width ?? 1920,\n height: opts?.height ?? 1080,\n });\n}\n\nexport async function getComposition(\n id: string,\n): Promise<LocalComposition | null> {\n return convexQuery<LocalComposition | null>(\n \"functions/compositions:localGet\",\n { organizationId: getLocalOrgId(), id },\n );\n}\n\nexport async function updateComposition(\n id: string,\n updates: {\n title?: string;\n description?: string;\n script?: string;\n duration?: number;\n scenes?: unknown[];\n },\n): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localUpdate\", {\n organizationId: getLocalOrgId(),\n id,\n ...updates,\n });\n}\n\nexport async function addScene(\n compositionId: string,\n scene: Record<string, unknown>,\n): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localAddScene\", {\n organizationId: getLocalOrgId(),\n id: compositionId,\n scene,\n });\n}\n\nexport async function updateScene(\n compositionId: string,\n sceneId: string,\n updates: Record<string, unknown>,\n): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localUpdateScene\", {\n organizationId: getLocalOrgId(),\n id: compositionId,\n sceneId,\n updates,\n });\n}\n\nexport async function deleteScene(\n compositionId: string,\n sceneId: string,\n): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localDeleteScene\", {\n organizationId: getLocalOrgId(),\n id: compositionId,\n sceneId,\n });\n}\n\nexport async function deleteAllScenes(compositionId: string): Promise<string> {\n return convexMutation<string>(\"functions/compositions:localDeleteAllScenes\", {\n organizationId: getLocalOrgId(),\n id: compositionId,\n });\n}\n\n// ============================================\n// FILE STORAGE\n// ============================================\n\n/**\n * Generate an upload URL for storing files in Convex storage.\n * Returns a short-lived URL to POST file data to.\n */\nexport async function generateUploadUrl(): Promise<string> {\n return convexMutation<string>(\"functions/files:localGenerateUploadUrl\", {});\n}\n\n/**\n * Upload a file to Convex storage using a generated upload URL.\n * Returns the storage ID for the uploaded file.\n */\nexport async function uploadToStorage(\n uploadUrl: string,\n fileData: Buffer | Uint8Array,\n contentType: string,\n): Promise<string> {\n const res = await fetch(uploadUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": contentType },\n body: fileData,\n });\n\n if (!res.ok) {\n throw new Error(`Storage upload failed: ${res.status} ${res.statusText}`);\n }\n\n const data = (await res.json()) as { storageId: string };\n return data.storageId;\n}\n\n/**\n * Get the serving URL for a stored file by its storage ID.\n */\nexport async function getStorageUrl(storageId: string): Promise<string | null> {\n return convexQuery<string | null>(\"functions/files:localGetStorageUrl\", {\n storageId,\n });\n}\n\nfunction inferContentType(url: string): string {\n const ext = (url.split(\"?\")[0] ?? url).split(\".\").pop()?.toLowerCase() ?? \"\";\n const mimeMap: Record<string, string> = {\n webp: \"image/webp\",\n jpg: \"image/jpeg\",\n jpeg: \"image/jpeg\",\n png: \"image/png\",\n gif: \"image/gif\",\n mp4: \"video/mp4\",\n webm: \"video/webm\",\n mov: \"video/quicktime\",\n };\n return mimeMap[ext] ?? \"application/octet-stream\";\n}\n\n/**\n * Download a remote media URL and save it to local Convex storage.\n * Returns a local storage URL that won't expire.\n */\nexport async function saveRemoteMediaToStorage(remoteUrl: string): Promise<string> {\n const res = await fetch(remoteUrl);\n if (!res.ok) {\n throw new Error(`Failed to download media (${res.status}): ${remoteUrl}`);\n }\n\n const contentType = res.headers.get(\"content-type\") ?? inferContentType(remoteUrl);\n const buffer = Buffer.from(await res.arrayBuffer());\n\n const uploadUrl = await generateUploadUrl();\n const storageId = await uploadToStorage(uploadUrl, buffer, contentType);\n\n const servingUrl = await getStorageUrl(storageId);\n if (!servingUrl) {\n throw new Error(\"Failed to get serving URL for uploaded media\");\n }\n\n return servingUrl;\n}\n\nexport async function updateExecutionLog(\n id: string,\n updates: {\n status?: \"pending\" | \"running\" | \"success\" | \"error\";\n output?: unknown;\n error?: string;\n completedAt?: number;\n duration?: string;\n },\n): Promise<string> {\n return convexMutation<string>(\"functions/templates:localUpdateExecutionLog\", {\n id,\n ...updates,\n });\n}\n\n/**\n * Record a usage event for local execution tracking.\n */\nexport async function recordUsage(entry: {\n model: string;\n provider: string;\n step?: string;\n compositionId?: string;\n costUsd?: number;\n durationMs?: number;\n predictionId?: string;\n input?: Record<string, unknown>;\n output?: Record<string, unknown>;\n status?: string;\n error?: string;\n}): Promise<string> {\n return convexMutation<string>(\"functions/usage:localRecordUsage\", {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n ...entry,\n });\n}\n\n/**\n * Create a step execution record when a step starts.\n */\nexport async function createStepExecution(entry: {\n step: string;\n model: string;\n provider: string;\n compositionId?: string;\n sceneId?: string;\n nodeId?: string;\n input?: Record<string, unknown>;\n}): Promise<string> {\n return convexMutation<string>(\n \"functions/templates:localCreateStepExecution\",\n {\n organizationId: getLocalOrgId(),\n userId: getLocalUserId(),\n ...entry,\n },\n );\n}\n\n/**\n * Update a step execution record when a step completes.\n */\nexport async function updateStepExecution(\n id: string,\n updates: {\n status: \"running\" | \"success\" | \"error\";\n output?: Record<string, unknown>;\n error?: string;\n costUsd?: number;\n durationMs?: number;\n },\n): Promise<string> {\n return convexMutation<string>(\n \"functions/templates:localUpdateStepExecution\",\n {\n id,\n ...updates,\n },\n );\n}\n"],"mappings":"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","names":[]}