@mevdragon/vidfarm-devcli 0.5.2 → 0.6.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/README.md +3 -3
- package/demo/README.md +28 -0
- package/demo/dist/app.css +1 -0
- package/demo/dist/app.js +1184 -0
- package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
- package/demo/dist/chunks/chunk-S7OWAJDS.js +36 -0
- package/demo/dist/chunks/chunk-VTIBZ6AN.js +1 -0
- package/demo/dist/chunks/dist-ADSJKBVE.js +332 -0
- package/demo/dist/chunks/domEditingLayers-VZMLL4AP-SGHWPND4.js +1 -0
- package/demo/dist/chunks/hyperframes-player-XB65TCD6.js +425 -0
- package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
- package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
- package/demo/dist/favicon.ico +0 -0
- package/demo/dist/icons/timeline/audio.svg +7 -0
- package/demo/dist/icons/timeline/captions.svg +5 -0
- package/demo/dist/icons/timeline/composition.svg +12 -0
- package/demo/dist/icons/timeline/image.svg +18 -0
- package/demo/dist/icons/timeline/music.svg +10 -0
- package/demo/dist/icons/timeline/text.svg +3 -0
- package/demo/dist/index.html +15 -0
- package/dist/src/account-pages-legacy.js +9396 -0
- package/dist/src/account-pages.js +61 -0
- package/dist/src/app.js +14378 -0
- package/dist/src/cli.js +1 -1
- package/dist/src/composition-runtime.js +613 -0
- package/dist/src/config.js +166 -0
- package/dist/src/context.js +447 -0
- package/dist/src/dev-app-legacy.js +739 -0
- package/dist/src/dev-app.js +6 -0
- package/dist/src/domain.js +2 -0
- package/dist/src/editor-chat-history.js +82 -0
- package/dist/src/editor-chat.js +449 -0
- package/dist/src/editor-dark-theme.js +1128 -0
- package/dist/src/frontend/debug.js +71 -0
- package/dist/src/frontend/flockposter-cache-store.js +124 -0
- package/dist/src/frontend/homepage-client.js +182 -0
- package/dist/src/frontend/homepage-shared.js +4 -0
- package/dist/src/frontend/homepage-store.js +28 -0
- package/dist/src/frontend/homepage-view.js +547 -0
- package/dist/src/frontend/page-runtime-client.js +132 -0
- package/dist/src/frontend/page-runtime-store.js +9 -0
- package/dist/src/frontend/sentry.js +42 -0
- package/dist/src/frontend/template-editor-chat.js +3960 -0
- package/dist/src/help-page.js +346 -0
- package/dist/src/homepage.js +1235 -0
- package/dist/src/hyperframes/composition.js +180 -0
- package/dist/src/index.js +16 -0
- package/dist/src/instrument.js +30 -0
- package/dist/src/lib/crypto.js +45 -0
- package/dist/src/lib/dev-log.js +54 -0
- package/dist/src/lib/display-name.js +11 -0
- package/dist/src/lib/ids.js +24 -0
- package/dist/src/lib/images.js +19 -0
- package/dist/src/lib/json.js +15 -0
- package/dist/src/lib/package-root.js +47 -0
- package/dist/src/lib/template-paths.js +28 -0
- package/dist/src/lib/time.js +7 -0
- package/dist/src/lib/url-clean.js +85 -0
- package/dist/src/page-runtime.js +2 -0
- package/dist/src/page-shell.js +1381 -0
- package/dist/src/primitive-context.js +357 -0
- package/dist/src/primitive-registry.js +2436 -0
- package/dist/src/primitive-sdk.js +4 -0
- package/dist/src/primitives/hyperframes-media.js +108 -0
- package/dist/src/react-page-shell.js +35 -0
- package/dist/src/ready-post-schedule-component.js +1540 -0
- package/dist/src/registry.js +296 -0
- package/dist/src/runtime.js +35 -0
- package/dist/src/services/api-call-history.js +249 -0
- package/dist/src/services/auth.js +152 -0
- package/dist/src/services/billing-pricing.js +39 -0
- package/dist/src/services/billing.js +228 -0
- package/dist/src/services/cast.js +127 -0
- package/dist/src/services/chat-threads.js +92 -0
- package/dist/src/services/composition-sanitize.js +124 -0
- package/dist/src/services/composition-watch.js +79 -0
- package/dist/src/services/fork-access.js +93 -0
- package/dist/src/services/fork-manifest.js +42 -0
- package/dist/src/services/ghostcut.js +179 -0
- package/dist/src/services/hyperframes.js +2307 -0
- package/dist/src/services/job-capacity.js +14 -0
- package/dist/src/services/job-logs.js +197 -0
- package/dist/src/services/jobs.js +136 -0
- package/dist/src/services/local-dynamo.js +0 -0
- package/dist/src/services/media-processing.js +766 -0
- package/dist/src/services/primitive-media-lambda.js +280 -0
- package/dist/src/services/providers.js +2926 -0
- package/dist/src/services/rate-limits.js +262 -0
- package/dist/src/services/serverless-auth.js +382 -0
- package/dist/src/services/serverless-jobs.js +1082 -0
- package/dist/src/services/serverless-provider-keys.js +409 -0
- package/dist/src/services/serverless-records.js +1385 -0
- package/dist/src/services/serverless-template-configs.js +75 -0
- package/dist/src/services/storage.js +383 -0
- package/dist/src/services/template-certification.js +413 -0
- package/dist/src/services/template-loader.js +99 -0
- package/dist/src/services/template-runtime-bundles.js +217 -0
- package/dist/src/services/template-sources.js +1017 -0
- package/dist/src/services/video-normalization.js +2 -0
- package/dist/src/services/webhooks.js +62 -0
- package/dist/src/template-editor-pages.js +2576 -0
- package/dist/src/template-editor-shell.js +2840 -0
- package/dist/src/template-sdk.js +4 -0
- package/dist/src/worker.js +17 -0
- package/package.json +6 -4
- package/public/assets/homepage-app.js +54 -0
- package/public/assets/homepage-client-app.js +80 -0
- package/public/assets/page-runtime-client-app.js +94 -0
- package/src/assets/SELLING_AWARENESS_STAGES.md +579 -0
- package/src/assets/SELLING_WITH_HOOKS.md +377 -0
- package/src/assets/SELLING_WITH_VSLS.md +606 -0
- package/src/assets/favicon.ico +0 -0
- package/src/assets/logo-vidfarm.png +0 -0
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import * as Sentry from "@sentry/node";
|
|
3
|
+
import { config } from "./config.js";
|
|
4
|
+
import { devErrorFields, devLog } from "./lib/dev-log.js";
|
|
5
|
+
import { createId } from "./lib/ids.js";
|
|
6
|
+
import { jobLogStore } from "./services/job-logs.js";
|
|
7
|
+
import { estimateNormalizationCostUsd, normalizeVideoAsset } from "./services/video-normalization.js";
|
|
8
|
+
export function createPrimitiveJobContext(input) {
|
|
9
|
+
const prefix = input.storage.primitiveJobPrefix(input.primitive.id, input.customer.id, input.job.id);
|
|
10
|
+
const buildArtifactUrl = (storageKey, fallbackUrl) => fallbackUrl ?? input.storage.getPublicUrl(storageKey) ?? buildPlatformMediaUrl(storageKey);
|
|
11
|
+
// Billing records are written after the billable work (render, normalize,
|
|
12
|
+
// etc.) has already succeeded. A transient billing failure must never fail
|
|
13
|
+
// the job — the customer would retry and pay for the expensive work twice.
|
|
14
|
+
const recordBillingNonFatal = async (record) => {
|
|
15
|
+
try {
|
|
16
|
+
await input.billing.record(record);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
Sentry.captureException(error);
|
|
20
|
+
devLog("billing.record_failed_nonfatal", {
|
|
21
|
+
job_id: input.job.id,
|
|
22
|
+
customer_id: input.customer.id,
|
|
23
|
+
template_id: input.primitive.id,
|
|
24
|
+
cost_center_slug: record.costCenterSlug ?? null,
|
|
25
|
+
idempotency_key: record.idempotencyKey ?? null,
|
|
26
|
+
...devErrorFields(error)
|
|
27
|
+
}, "warn");
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
return {
|
|
31
|
+
env: config.isProduction ? "production" : "development",
|
|
32
|
+
customer: input.customer,
|
|
33
|
+
logger: {
|
|
34
|
+
debug(message, metadata = {}) {
|
|
35
|
+
jobLogStore.addEvent({
|
|
36
|
+
id: createId("evt"),
|
|
37
|
+
jobId: input.job.id,
|
|
38
|
+
level: "debug",
|
|
39
|
+
message,
|
|
40
|
+
metadata,
|
|
41
|
+
progress: null,
|
|
42
|
+
artifactKey: null
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
info(message, metadata = {}) {
|
|
46
|
+
jobLogStore.addEvent({
|
|
47
|
+
id: createId("evt"),
|
|
48
|
+
jobId: input.job.id,
|
|
49
|
+
level: "info",
|
|
50
|
+
message,
|
|
51
|
+
metadata,
|
|
52
|
+
progress: null,
|
|
53
|
+
artifactKey: null
|
|
54
|
+
});
|
|
55
|
+
},
|
|
56
|
+
warn(message, metadata = {}) {
|
|
57
|
+
jobLogStore.addEvent({
|
|
58
|
+
id: createId("evt"),
|
|
59
|
+
jobId: input.job.id,
|
|
60
|
+
level: "warn",
|
|
61
|
+
message,
|
|
62
|
+
metadata,
|
|
63
|
+
progress: null,
|
|
64
|
+
artifactKey: null
|
|
65
|
+
});
|
|
66
|
+
},
|
|
67
|
+
error(message, metadata = {}) {
|
|
68
|
+
jobLogStore.addEvent({
|
|
69
|
+
id: createId("evt"),
|
|
70
|
+
jobId: input.job.id,
|
|
71
|
+
level: "error",
|
|
72
|
+
message,
|
|
73
|
+
metadata,
|
|
74
|
+
progress: null,
|
|
75
|
+
artifactKey: null
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
progress(progress, message, metadata = {}) {
|
|
79
|
+
jobLogStore.addEvent({
|
|
80
|
+
id: createId("evt"),
|
|
81
|
+
jobId: input.job.id,
|
|
82
|
+
level: "info",
|
|
83
|
+
message,
|
|
84
|
+
metadata,
|
|
85
|
+
progress,
|
|
86
|
+
artifactKey: typeof metadata.artifactKey === "string" ? metadata.artifactKey : null
|
|
87
|
+
});
|
|
88
|
+
void input.jobs.updateJobStatus({
|
|
89
|
+
id: input.job.id,
|
|
90
|
+
status: "running",
|
|
91
|
+
progress
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
storage: {
|
|
96
|
+
async putJson(key, value) {
|
|
97
|
+
const stored = await input.storage.putJson(`${prefix}/${key}`, value);
|
|
98
|
+
const artifactUrl = buildArtifactUrl(stored.key, stored.url);
|
|
99
|
+
await insertArtifact("json", stored.key, artifactUrl, {});
|
|
100
|
+
return { ...stored, url: artifactUrl };
|
|
101
|
+
},
|
|
102
|
+
async putText(key, value, contentType = "text/plain; charset=utf-8") {
|
|
103
|
+
const stored = await input.storage.putText(`${prefix}/${key}`, value, contentType);
|
|
104
|
+
const artifactUrl = buildArtifactUrl(stored.key, stored.url);
|
|
105
|
+
await insertArtifact("text", stored.key, artifactUrl, { contentType });
|
|
106
|
+
return { ...stored, url: artifactUrl };
|
|
107
|
+
},
|
|
108
|
+
async putBuffer(key, value, options = {}) {
|
|
109
|
+
const stored = await input.storage.putBuffer(`${prefix}/${key}`, value, options.contentType);
|
|
110
|
+
const artifactUrl = buildArtifactUrl(stored.key, stored.url);
|
|
111
|
+
await insertArtifact(options.kind ?? "binary", stored.key, artifactUrl, {
|
|
112
|
+
...(options.metadata ?? {}),
|
|
113
|
+
contentType: options.contentType ?? null
|
|
114
|
+
});
|
|
115
|
+
return { ...stored, url: artifactUrl };
|
|
116
|
+
},
|
|
117
|
+
getPublicUrl(key) {
|
|
118
|
+
return input.storage.getPublicUrl(`${prefix}/${key}`);
|
|
119
|
+
},
|
|
120
|
+
resolveKey(key) {
|
|
121
|
+
return `${prefix}/${key}`;
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
billing: {
|
|
125
|
+
async record(record) {
|
|
126
|
+
await recordBillingNonFatal({
|
|
127
|
+
customerId: input.customer.id,
|
|
128
|
+
jobId: input.job.id,
|
|
129
|
+
tracer: input.job.tracer,
|
|
130
|
+
templateId: input.primitive.id,
|
|
131
|
+
type: record.type,
|
|
132
|
+
costUsd: record.costUsd,
|
|
133
|
+
chargeUsd: record.chargeUsd ?? Number((record.costUsd * 1.2).toFixed(4)),
|
|
134
|
+
costCenterSlug: record.costCenterSlug,
|
|
135
|
+
idempotencyKey: record.idempotencyKey,
|
|
136
|
+
occurredAtMs: record.occurredAtMs,
|
|
137
|
+
metadata: record.metadata
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
providers: {
|
|
142
|
+
listAvailableProviders() {
|
|
143
|
+
return input.providers.listAvailableProviders(input.customer.id);
|
|
144
|
+
},
|
|
145
|
+
async generateText(request) {
|
|
146
|
+
return input.providers.generateText({
|
|
147
|
+
customerId: input.customer.id,
|
|
148
|
+
jobId: input.job.id,
|
|
149
|
+
workerId: input.workerId,
|
|
150
|
+
...request
|
|
151
|
+
});
|
|
152
|
+
},
|
|
153
|
+
async generateImage(request) {
|
|
154
|
+
return input.providers.generateImage({
|
|
155
|
+
customerId: input.customer.id,
|
|
156
|
+
jobId: input.job.id,
|
|
157
|
+
workerId: input.workerId,
|
|
158
|
+
...request
|
|
159
|
+
});
|
|
160
|
+
},
|
|
161
|
+
async editImage(request) {
|
|
162
|
+
return input.providers.editImage({
|
|
163
|
+
customerId: input.customer.id,
|
|
164
|
+
jobId: input.job.id,
|
|
165
|
+
workerId: input.workerId,
|
|
166
|
+
...request
|
|
167
|
+
});
|
|
168
|
+
},
|
|
169
|
+
async inpaintImage(request) {
|
|
170
|
+
return input.providers.inpaintImage({
|
|
171
|
+
customerId: input.customer.id,
|
|
172
|
+
jobId: input.job.id,
|
|
173
|
+
workerId: input.workerId,
|
|
174
|
+
...request
|
|
175
|
+
});
|
|
176
|
+
},
|
|
177
|
+
async generateVideo(request) {
|
|
178
|
+
return input.providers.generateVideo({
|
|
179
|
+
customerId: input.customer.id,
|
|
180
|
+
jobId: input.job.id,
|
|
181
|
+
workerId: input.workerId,
|
|
182
|
+
...request
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
},
|
|
186
|
+
hyperframes: {
|
|
187
|
+
async render(request) {
|
|
188
|
+
const hyperframesOutputKey = `renders/vidfarm/primitives/${input.primitive.id}/${input.customer.id}/${input.job.id}/output.mp4`;
|
|
189
|
+
const render = await input.hyperframes.render({
|
|
190
|
+
...request,
|
|
191
|
+
outputKey: hyperframesOutputKey,
|
|
192
|
+
wait: true
|
|
193
|
+
});
|
|
194
|
+
let outputUrl = render.outputUrl;
|
|
195
|
+
let platformOutputKey = null;
|
|
196
|
+
const localOutputLocation = typeof render.metadata.outputLocation === "string"
|
|
197
|
+
? render.metadata.outputLocation
|
|
198
|
+
: null;
|
|
199
|
+
if (render.outputS3Uri) {
|
|
200
|
+
const output = await input.hyperframes.readRenderOutput(render.outputS3Uri);
|
|
201
|
+
platformOutputKey = `${prefix}/${request.outputKey || "output.mp4"}`;
|
|
202
|
+
const stored = await input.storage.putBuffer(platformOutputKey, output.bytes, output.contentType);
|
|
203
|
+
outputUrl = buildArtifactUrl(stored.key, stored.url);
|
|
204
|
+
await insertArtifact("video", stored.key, outputUrl, {
|
|
205
|
+
operation: "hyperframes-render",
|
|
206
|
+
contentType: output.contentType,
|
|
207
|
+
renderId: render.renderId,
|
|
208
|
+
outputS3Uri: render.outputS3Uri
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
else if (localOutputLocation) {
|
|
212
|
+
// In-process (local) render writes the MP4 to ephemeral local disk and
|
|
213
|
+
// returns no S3 URI. On serverless boxes that disk is per-invocation
|
|
214
|
+
// and the `renders/` prefix is not publicly served, so the raw
|
|
215
|
+
// outputUrl 404s ("Artifact not found"). Persist the bytes into the
|
|
216
|
+
// public job-scoped prefix — S3 on cloud, local disk on serve boxes —
|
|
217
|
+
// exactly like the cloud branch above.
|
|
218
|
+
const bytes = await readFile(localOutputLocation);
|
|
219
|
+
platformOutputKey = `${prefix}/${request.outputKey || "output.mp4"}`;
|
|
220
|
+
const stored = await input.storage.putBuffer(platformOutputKey, bytes, "video/mp4");
|
|
221
|
+
outputUrl = buildArtifactUrl(stored.key, stored.url);
|
|
222
|
+
await insertArtifact("video", stored.key, outputUrl, {
|
|
223
|
+
operation: "hyperframes-render-local",
|
|
224
|
+
contentType: "video/mp4",
|
|
225
|
+
renderId: render.renderId,
|
|
226
|
+
outputLocation: localOutputLocation
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
const estimatedCostUsd = typeof render.metadata.estimatedCostUsd === "number" ? render.metadata.estimatedCostUsd : null;
|
|
230
|
+
const chargeUsd = typeof render.metadata.chargeUsd === "number" ? render.metadata.chargeUsd : null;
|
|
231
|
+
if (estimatedCostUsd !== null && estimatedCostUsd > 0) {
|
|
232
|
+
await recordBillingNonFatal({
|
|
233
|
+
customerId: input.customer.id,
|
|
234
|
+
jobId: input.job.id,
|
|
235
|
+
tracer: input.job.tracer,
|
|
236
|
+
templateId: input.primitive.id,
|
|
237
|
+
type: "render",
|
|
238
|
+
costUsd: estimatedCostUsd,
|
|
239
|
+
chargeUsd: typeof chargeUsd === "number" ? chargeUsd : undefined,
|
|
240
|
+
costCenterSlug: "hyperframes_lambda",
|
|
241
|
+
idempotencyKey: `hyperframes_lambda:${render.renderId}`,
|
|
242
|
+
occurredAtMs: Date.now(),
|
|
243
|
+
metadata: {
|
|
244
|
+
...render.metadata,
|
|
245
|
+
render_id: render.renderId,
|
|
246
|
+
output_url: outputUrl,
|
|
247
|
+
signed_output_url: render.outputUrl,
|
|
248
|
+
output_s3_uri: render.outputS3Uri,
|
|
249
|
+
platform_output_key: platformOutputKey
|
|
250
|
+
}
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
renderId: render.renderId,
|
|
255
|
+
outputUrl,
|
|
256
|
+
outputS3Uri: render.outputS3Uri,
|
|
257
|
+
metadata: {
|
|
258
|
+
...render.metadata,
|
|
259
|
+
outputUrl,
|
|
260
|
+
signedOutputUrl: render.outputUrl,
|
|
261
|
+
platformOutputKey
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
},
|
|
265
|
+
async renderStill(request) {
|
|
266
|
+
const extension = (request.imageFormat ?? "png") === "jpeg" ? "jpg" : (request.imageFormat ?? "png");
|
|
267
|
+
const localOutputKey = `renders/vidfarm/primitives/${input.primitive.id}/${input.customer.id}/${input.job.id}/${request.outputKey || `output.${extension}`}`;
|
|
268
|
+
const rendered = await input.hyperframes.renderStill({
|
|
269
|
+
compositionHtml: request.compositionHtml,
|
|
270
|
+
compositionId: request.compositionId,
|
|
271
|
+
imageFormat: request.imageFormat,
|
|
272
|
+
outputKey: localOutputKey
|
|
273
|
+
});
|
|
274
|
+
// renderStill writes to ephemeral local disk under the non-public
|
|
275
|
+
// `renders/` prefix. Persist it into the public job-scoped prefix (S3 on
|
|
276
|
+
// cloud, local disk on serve boxes) so the artifact URL resolves — same
|
|
277
|
+
// fix as render() above.
|
|
278
|
+
const platformKey = `${prefix}/${request.outputKey || `output.${extension}`}`;
|
|
279
|
+
const contentType = extension === "jpg" ? "image/jpeg" : extension === "webp" ? "image/webp" : "image/png";
|
|
280
|
+
const bytes = await readFile(rendered.outputLocation);
|
|
281
|
+
const stored = await input.storage.putBuffer(platformKey, bytes, contentType);
|
|
282
|
+
const outputUrl = buildArtifactUrl(stored.key, stored.url);
|
|
283
|
+
await insertArtifact("image", stored.key, outputUrl, {
|
|
284
|
+
operation: "hyperframes-render-still",
|
|
285
|
+
renderId: rendered.renderId,
|
|
286
|
+
imageFormat: request.imageFormat ?? "png"
|
|
287
|
+
});
|
|
288
|
+
return {
|
|
289
|
+
renderId: rendered.renderId,
|
|
290
|
+
outputUrl,
|
|
291
|
+
metadata: rendered.metadata
|
|
292
|
+
};
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
media: {
|
|
296
|
+
async normalizeVideo(request) {
|
|
297
|
+
const normalized = await normalizeVideoAsset({
|
|
298
|
+
sourceUrl: request.sourceUrl,
|
|
299
|
+
maxWidth: request.maxWidth,
|
|
300
|
+
maxHeight: request.maxHeight,
|
|
301
|
+
crf: request.crf,
|
|
302
|
+
preset: request.preset,
|
|
303
|
+
maxVideoBitrateKbps: request.maxVideoBitrateKbps,
|
|
304
|
+
audioBitrateKbps: request.audioBitrateKbps
|
|
305
|
+
});
|
|
306
|
+
const stored = await input.storage.putBuffer(`${prefix}/${request.outputKey}`, normalized.bytes, normalized.contentType);
|
|
307
|
+
const artifactUrl = buildArtifactUrl(stored.key, stored.url);
|
|
308
|
+
await insertArtifact("video", stored.key, artifactUrl, {
|
|
309
|
+
...(request.metadata ?? {}),
|
|
310
|
+
operation: "normalize-video",
|
|
311
|
+
contentType: normalized.contentType,
|
|
312
|
+
normalization: normalized.metadata
|
|
313
|
+
});
|
|
314
|
+
await recordBillingNonFatal({
|
|
315
|
+
customerId: input.customer.id,
|
|
316
|
+
jobId: input.job.id,
|
|
317
|
+
tracer: input.job.tracer,
|
|
318
|
+
templateId: input.primitive.id,
|
|
319
|
+
type: "cpu_estimate",
|
|
320
|
+
costUsd: estimateNormalizationCostUsd(normalized.metadata),
|
|
321
|
+
costCenterSlug: "video_normalization",
|
|
322
|
+
idempotencyKey: `video_normalization:${input.job.id}:${request.outputKey}`,
|
|
323
|
+
occurredAtMs: Date.now(),
|
|
324
|
+
metadata: {
|
|
325
|
+
...(request.metadata ?? {}),
|
|
326
|
+
operation: "normalize-video",
|
|
327
|
+
source_url: request.sourceUrl,
|
|
328
|
+
output_key: `${prefix}/${request.outputKey}`,
|
|
329
|
+
normalization: normalized.metadata
|
|
330
|
+
}
|
|
331
|
+
});
|
|
332
|
+
return {
|
|
333
|
+
...stored,
|
|
334
|
+
url: artifactUrl,
|
|
335
|
+
contentType: normalized.contentType,
|
|
336
|
+
normalization: normalized.metadata
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
async function insertArtifact(kind, storageKey, publicUrl, metadata) {
|
|
342
|
+
await input.jobs.insertArtifact({
|
|
343
|
+
id: createId("art"),
|
|
344
|
+
jobId: input.job.id,
|
|
345
|
+
customerId: input.customer.id,
|
|
346
|
+
templateId: input.primitive.id,
|
|
347
|
+
kind,
|
|
348
|
+
storageKey,
|
|
349
|
+
publicUrl,
|
|
350
|
+
metadata
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function buildPlatformMediaUrl(storageKey) {
|
|
355
|
+
return `${config.PUBLIC_BASE_URL.replace(/\/$/, "")}/template-media?key=${encodeURIComponent(storageKey)}`;
|
|
356
|
+
}
|
|
357
|
+
//# sourceMappingURL=primitive-context.js.map
|