@mevdragon/vidfarm-devcli 0.2.7 → 0.2.9
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/.env.example +9 -0
- package/GETTING_STARTED.developers.md +1 -30
- package/README.md +22 -5
- package/SKILL.developer.md +464 -12
- package/auto-create-templates/AUTO_CREATE_TEMPLATES.md +475 -0
- package/auto-create-templates/extractor-system-prompt.md +113 -0
- package/auto-create-templates/production-graph.schema.json +276 -0
- package/auto-create-templates/runbook.md +140 -0
- package/auto-create-templates/template-plan.schema.json +230 -0
- package/auto-create-templates/template-planner-prompt.md +75 -0
- package/dist/src/account-pages-legacy.js +9064 -0
- package/dist/src/account-pages.js +41 -620
- package/dist/src/app.js +7173 -494
- package/dist/src/cli.js +525 -29
- package/dist/src/config.js +14 -7
- package/dist/src/context.js +51 -35
- package/dist/src/db.js +1049 -55
- package/dist/src/dev-app-legacy.js +693 -0
- package/dist/src/dev-app.js +4 -904
- package/dist/src/domain.js +1 -1
- package/dist/src/editor-chat-history.js +72 -0
- package/dist/src/editor-chat.js +202 -0
- package/dist/src/frontend/flockposter-cache-store.js +116 -0
- package/dist/src/frontend/homepage-client.js +114 -0
- package/dist/src/frontend/homepage-shared.js +3 -0
- package/dist/src/frontend/homepage-store.js +27 -0
- package/dist/src/frontend/homepage-view.js +147 -0
- package/dist/src/frontend/page-runtime-client.js +100 -0
- package/dist/src/frontend/page-runtime-store.js +8 -0
- package/dist/src/frontend/template-editor-chat.js +2261 -0
- package/dist/src/homepage.js +695 -339
- package/dist/src/lib/template-paths.js +10 -4
- package/dist/src/lib/template-style-options.js +95 -15
- package/dist/src/page-runtime.js +1 -0
- package/dist/src/page-shell.js +941 -0
- package/dist/src/primitive-context.js +163 -0
- package/dist/src/primitive-registry.js +340 -0
- package/dist/src/primitive-sdk.js +3 -0
- package/dist/src/primitives/remotion/html-image.js +28 -0
- package/dist/src/react-page-shell.js +34 -0
- package/dist/src/ready-post-schedule-component.js +1514 -0
- package/dist/src/registry.js +44 -18
- package/dist/src/runtime.js +6 -1
- package/dist/src/services/api-call-history.js +245 -0
- package/dist/src/services/auth.js +27 -9
- package/dist/src/services/billing.js +248 -9
- package/dist/src/services/chat-threads.js +88 -0
- package/dist/src/services/job-logs.js +10 -3
- package/dist/src/services/jobs.js +13 -2
- package/dist/src/services/providers.js +944 -55
- package/dist/src/services/rate-limits.js +236 -0
- package/dist/src/services/remotion.js +143 -16
- package/dist/src/services/storage.js +23 -8
- package/dist/src/services/template-certification.js +26 -3
- package/dist/src/services/template-loader.js +19 -1
- package/dist/src/services/template-sources.js +316 -7
- package/dist/src/template-editor-pages.js +2309 -0
- package/dist/src/template-editor-shell.js +1507 -0
- package/dist/src/worker.js +120 -22
- package/package.json +30 -6
- package/public/assets/homepage-app.js +54 -0
- package/public/assets/homepage-client-app.js +54 -0
- package/public/assets/page-runtime-client-app.js +68 -0
- package/dist/templates/template_0000/src/lib/images.js +0 -202
- package/dist/templates/template_0000/src/remotion/Root.js +0 -33
- package/dist/templates/template_0000/src/remotion/index.js +0 -3
- package/dist/templates/template_0000/src/sdk.js +0 -3
- package/dist/templates/template_0000/src/style-options.js +0 -51
- package/dist/templates/template_0000/src/template-dna.js +0 -9
- package/dist/templates/template_0000/src/template.js +0 -1441
- package/templates/template_0000/README.md +0 -77
- package/templates/template_0000/SKILL.md +0 -225
- package/templates/template_0000/assets/Abel-Regular.ttf +0 -0
- package/templates/template_0000/assets/DMSerifDisplay-Regular.ttf +0 -0
- package/templates/template_0000/assets/Montserrat[wght].ttf +0 -0
- package/templates/template_0000/assets/SourceCodePro[wght].ttf +0 -0
- package/templates/template_0000/assets/TikTokSans-SemiBold.ttf +0 -0
- package/templates/template_0000/assets/Yesteryear-Regular.ttf +0 -0
- package/templates/template_0000/composition.json +0 -11
- package/templates/template_0000/package.json +0 -28
- package/templates/template_0000/research/preview/.gitkeep +0 -1
- package/templates/template_0000/research/source_notes.md +0 -7
- package/templates/template_0000/src/lib/images.js +0 -202
- package/templates/template_0000/src/lib/images.ts +0 -241
- package/templates/template_0000/src/remotion/Root.js +0 -33
- package/templates/template_0000/src/remotion/Root.tsx +0 -75
- package/templates/template_0000/src/remotion/index.js +0 -3
- package/templates/template_0000/src/remotion/index.tsx +0 -4
- package/templates/template_0000/src/sdk.js +0 -3
- package/templates/template_0000/src/sdk.ts +0 -122
- package/templates/template_0000/src/style-options.js +0 -51
- package/templates/template_0000/src/style-options.ts +0 -60
- package/templates/template_0000/src/template-dna.js +0 -9
- package/templates/template_0000/src/template-dna.ts +0 -15
- package/templates/template_0000/src/template.js +0 -1441
- package/templates/template_0000/src/template.ts +0 -2042
- package/templates/template_0000/template.config.json +0 -21
- package/templates/template_0000/tsconfig.json +0 -19
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHash, createHmac } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import { execFile } from "node:child_process";
|
|
4
6
|
import { promisify } from "node:util";
|
|
@@ -9,7 +11,9 @@ import { defaultSkillPathForTemplateModule, deriveTemplateRootDirFromModulePath
|
|
|
9
11
|
import { nowIso } from "../lib/time.js";
|
|
10
12
|
import { loadTemplateFromModule } from "./template-loader.js";
|
|
11
13
|
import { TemplateCertificationService } from "./template-certification.js";
|
|
14
|
+
import { StorageService } from "./storage.js";
|
|
12
15
|
const execFileAsync = promisify(execFile);
|
|
16
|
+
const storage = new StorageService();
|
|
13
17
|
export class TemplateSourceAlreadyRegisteredError extends Error {
|
|
14
18
|
existingSource;
|
|
15
19
|
conflictField;
|
|
@@ -22,8 +26,8 @@ export class TemplateSourceAlreadyRegisteredError extends Error {
|
|
|
22
26
|
}
|
|
23
27
|
export class TemplateSourceService {
|
|
24
28
|
certification = new TemplateCertificationService();
|
|
25
|
-
listSources(
|
|
26
|
-
return database.listTemplateSources(
|
|
29
|
+
listSources(input) {
|
|
30
|
+
return database.listTemplateSources(input);
|
|
27
31
|
}
|
|
28
32
|
listReleases(input) {
|
|
29
33
|
return database.listTemplateReleases(input);
|
|
@@ -127,14 +131,26 @@ export class TemplateSourceService {
|
|
|
127
131
|
if (!source) {
|
|
128
132
|
throw new Error("Template source not found.");
|
|
129
133
|
}
|
|
130
|
-
const
|
|
134
|
+
const artifactManifest = input.artifactManifestKey
|
|
135
|
+
? await this.loadAndVerifyArtifactManifest(input.artifactManifestKey, source)
|
|
136
|
+
: null;
|
|
137
|
+
const commitSha = artifactManifest?.commit_sha ?? input.commitSha ?? await this.resolveBranchHead(source.repoUrl, source.branch);
|
|
131
138
|
const checkoutPath = path.join(config.TEMPLATE_SOURCE_ROOT, source.templateId, commitSha);
|
|
132
|
-
const skillPath = path.join(checkoutPath, source.skillPath);
|
|
139
|
+
const skillPath = path.join(checkoutPath, artifactManifest?.skill_path ?? source.skillPath);
|
|
133
140
|
const authRepoUrl = this.resolveGitRemoteUrl(source.repoUrl);
|
|
134
141
|
if (!existsSync(checkoutPath)) {
|
|
135
142
|
mkdirSync(path.dirname(checkoutPath), { recursive: true });
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
if (artifactManifest) {
|
|
144
|
+
await this.extractArtifactToCheckout({
|
|
145
|
+
checkoutPath,
|
|
146
|
+
artifactKey: artifactManifest.artifact_key,
|
|
147
|
+
expectedSha256: artifactManifest.artifact_sha256
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
await this.runShell(["git", "clone", "--branch", source.branch, authRepoUrl, checkoutPath], process.cwd());
|
|
152
|
+
await this.runShell(["git", "checkout", commitSha], checkoutPath);
|
|
153
|
+
}
|
|
138
154
|
if (source.installCommand.trim()) {
|
|
139
155
|
await this.runCommandString(source.installCommand, checkoutPath);
|
|
140
156
|
}
|
|
@@ -161,11 +177,112 @@ export class TemplateSourceService {
|
|
|
161
177
|
checkoutPath,
|
|
162
178
|
skillPath,
|
|
163
179
|
modulePath,
|
|
180
|
+
artifactManifestKey: input.artifactManifestKey ?? null,
|
|
181
|
+
artifactKey: artifactManifest?.artifact_key ?? null,
|
|
164
182
|
status,
|
|
165
183
|
certificationReport,
|
|
166
184
|
activatedAt: null
|
|
167
185
|
});
|
|
168
186
|
}
|
|
187
|
+
async publishRelease(input) {
|
|
188
|
+
const source = database.getTemplateSource(input.sourceId);
|
|
189
|
+
if (!source) {
|
|
190
|
+
throw new Error("Template source not found.");
|
|
191
|
+
}
|
|
192
|
+
if (source.status !== "approved") {
|
|
193
|
+
throw new Error("Template source must be approved before a developer can publish an update.");
|
|
194
|
+
}
|
|
195
|
+
const trimmedCommitSha = input.commitSha.trim();
|
|
196
|
+
if (!trimmedCommitSha) {
|
|
197
|
+
throw new Error("commit_sha is required.");
|
|
198
|
+
}
|
|
199
|
+
const existingRelease = database.getTemplateReleaseBySourceAndCommit(source.id, trimmedCommitSha);
|
|
200
|
+
if (existingRelease &&
|
|
201
|
+
(existingRelease.status === "pending_approval"
|
|
202
|
+
|| existingRelease.status === "approved"
|
|
203
|
+
|| existingRelease.status === "active")) {
|
|
204
|
+
return {
|
|
205
|
+
source,
|
|
206
|
+
release: existingRelease,
|
|
207
|
+
publishAction: "updated"
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
const release = await this.importRelease({
|
|
211
|
+
sourceId: source.id,
|
|
212
|
+
commitSha: trimmedCommitSha
|
|
213
|
+
});
|
|
214
|
+
return {
|
|
215
|
+
source,
|
|
216
|
+
release,
|
|
217
|
+
publishAction: existingRelease ? "updated" : "created"
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
async publishArtifactRelease(input) {
|
|
221
|
+
const source = database.getTemplateSource(input.sourceId);
|
|
222
|
+
if (!source) {
|
|
223
|
+
throw new Error("Template source not found.");
|
|
224
|
+
}
|
|
225
|
+
if (source.status !== "approved") {
|
|
226
|
+
throw new Error("Template source must be approved before a developer can publish an update.");
|
|
227
|
+
}
|
|
228
|
+
const trimmedCommitSha = input.commitSha.trim();
|
|
229
|
+
const trimmedArtifactSha256 = input.artifactSha256.trim().toLowerCase();
|
|
230
|
+
if (!trimmedCommitSha) {
|
|
231
|
+
throw new Error("commit_sha is required.");
|
|
232
|
+
}
|
|
233
|
+
if (!/^[0-9a-f]{64}$/i.test(trimmedArtifactSha256)) {
|
|
234
|
+
throw new Error("artifact_sha256 must be a 64-character hexadecimal SHA-256 hash.");
|
|
235
|
+
}
|
|
236
|
+
const existingRelease = database.getTemplateReleaseBySourceAndCommit(source.id, trimmedCommitSha);
|
|
237
|
+
if (existingRelease &&
|
|
238
|
+
(existingRelease.status === "pending_approval"
|
|
239
|
+
|| existingRelease.status === "approved"
|
|
240
|
+
|| existingRelease.status === "active")) {
|
|
241
|
+
return {
|
|
242
|
+
source,
|
|
243
|
+
release: existingRelease,
|
|
244
|
+
publishAction: "updated"
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
const { manifestKey } = await this.createSignedArtifactManifest({
|
|
248
|
+
source,
|
|
249
|
+
commitSha: trimmedCommitSha,
|
|
250
|
+
artifactSha256: trimmedArtifactSha256,
|
|
251
|
+
signedBy: input.signedBy
|
|
252
|
+
});
|
|
253
|
+
const release = await this.importRelease({
|
|
254
|
+
sourceId: source.id,
|
|
255
|
+
artifactManifestKey: manifestKey
|
|
256
|
+
});
|
|
257
|
+
return {
|
|
258
|
+
source,
|
|
259
|
+
release,
|
|
260
|
+
publishAction: existingRelease ? "updated" : "created"
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
async createDeveloperArtifactUpload(input) {
|
|
264
|
+
const source = database.getTemplateSource(input.sourceId);
|
|
265
|
+
if (!source) {
|
|
266
|
+
throw new Error("Template source not found.");
|
|
267
|
+
}
|
|
268
|
+
if (source.status !== "approved") {
|
|
269
|
+
throw new Error("Template source must be approved before a developer can publish an update.");
|
|
270
|
+
}
|
|
271
|
+
const trimmedCommitSha = input.commitSha.trim();
|
|
272
|
+
if (!trimmedCommitSha) {
|
|
273
|
+
throw new Error("commit_sha is required.");
|
|
274
|
+
}
|
|
275
|
+
const artifact = this.buildArtifactKeys(source, trimmedCommitSha);
|
|
276
|
+
const upload = await storage.createWriteUrl(artifact.artifactKey, {
|
|
277
|
+
contentType: "application/gzip",
|
|
278
|
+
publicRead: false,
|
|
279
|
+
expiresIn: 3600
|
|
280
|
+
});
|
|
281
|
+
return {
|
|
282
|
+
...artifact,
|
|
283
|
+
upload
|
|
284
|
+
};
|
|
285
|
+
}
|
|
169
286
|
approveSource(input) {
|
|
170
287
|
const source = database.getTemplateSource(input.sourceId);
|
|
171
288
|
if (!source) {
|
|
@@ -251,6 +368,7 @@ export class TemplateSourceService {
|
|
|
251
368
|
});
|
|
252
369
|
throw new Error("Template release failed certification and cannot be activated.");
|
|
253
370
|
}
|
|
371
|
+
await this.syncTemplateAboutAssets({ release, template });
|
|
254
372
|
database.clearActiveTemplateReleases(release.templateId);
|
|
255
373
|
database.updateTemplateReleaseStatus({
|
|
256
374
|
id: release.id,
|
|
@@ -315,6 +433,174 @@ export class TemplateSourceService {
|
|
|
315
433
|
}
|
|
316
434
|
});
|
|
317
435
|
}
|
|
436
|
+
async syncTemplateAboutAssets(input) {
|
|
437
|
+
const entries = Array.from(new Set(input.template.about.preview_media
|
|
438
|
+
.filter((entry) => !/^https?:\/\//i.test(entry))
|
|
439
|
+
.filter((entry) => !entry.replace(/^\/+/, "").startsWith("templates/"))));
|
|
440
|
+
for (const entry of entries) {
|
|
441
|
+
const asset = this.resolveTemplateAboutAsset(input.release, entry);
|
|
442
|
+
if (!asset) {
|
|
443
|
+
throw new Error(`Template about asset not found in release checkout: ${entry}`);
|
|
444
|
+
}
|
|
445
|
+
await storage.putBuffer(storage.templateAboutKey(input.template.id, asset.storageAssetPath), readFileSync(asset.sourcePath), inferContentType(asset.sourcePath));
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
resolveTemplateAboutAsset(release, entry) {
|
|
449
|
+
const normalizedEntry = entry.replace(/^\/+/, "");
|
|
450
|
+
const sourceRelativePath = normalizedEntry.startsWith("about/")
|
|
451
|
+
? normalizedEntry
|
|
452
|
+
: path.posix.join("about", normalizedEntry);
|
|
453
|
+
const storageAssetPath = normalizedEntry.startsWith("about/")
|
|
454
|
+
? normalizedEntry.slice("about/".length)
|
|
455
|
+
: normalizedEntry;
|
|
456
|
+
const checkoutRoot = path.resolve(release.checkoutPath);
|
|
457
|
+
let currentDir = path.dirname(release.modulePath);
|
|
458
|
+
while (true) {
|
|
459
|
+
const candidatePath = path.join(currentDir, sourceRelativePath);
|
|
460
|
+
if (existsSync(candidatePath)) {
|
|
461
|
+
return {
|
|
462
|
+
sourcePath: candidatePath,
|
|
463
|
+
storageAssetPath
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
if (path.resolve(currentDir) === checkoutRoot) {
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
const parentDir = path.dirname(currentDir);
|
|
470
|
+
if (parentDir === currentDir) {
|
|
471
|
+
break;
|
|
472
|
+
}
|
|
473
|
+
currentDir = parentDir;
|
|
474
|
+
}
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
async loadAndVerifyArtifactManifest(manifestKey, source) {
|
|
478
|
+
const raw = await storage.readText(manifestKey);
|
|
479
|
+
if (!raw) {
|
|
480
|
+
throw new Error(`Artifact manifest not found: ${manifestKey}`);
|
|
481
|
+
}
|
|
482
|
+
const manifest = JSON.parse(raw);
|
|
483
|
+
if (manifest.version !== 1 || manifest.algorithm !== "hmac-sha256") {
|
|
484
|
+
throw new Error("Unsupported template artifact manifest version or algorithm.");
|
|
485
|
+
}
|
|
486
|
+
if (!config.ARTIFACT_SIGNING_SECRET) {
|
|
487
|
+
throw new Error("ARTIFACT_SIGNING_SECRET or SUPERAGENCY_KEY is required to verify artifact manifests.");
|
|
488
|
+
}
|
|
489
|
+
const expectedSignature = createHmac("sha256", config.ARTIFACT_SIGNING_SECRET)
|
|
490
|
+
.update(this.serializeArtifactManifestPayload({
|
|
491
|
+
version: 1,
|
|
492
|
+
algorithm: "hmac-sha256",
|
|
493
|
+
template_id: String(manifest.template_id ?? ""),
|
|
494
|
+
slug_id: String(manifest.slug_id ?? ""),
|
|
495
|
+
repo_url: String(manifest.repo_url ?? ""),
|
|
496
|
+
branch: String(manifest.branch ?? ""),
|
|
497
|
+
commit_sha: String(manifest.commit_sha ?? ""),
|
|
498
|
+
template_module_path: String(manifest.template_module_path ?? ""),
|
|
499
|
+
skill_path: String(manifest.skill_path ?? ""),
|
|
500
|
+
install_command: String(manifest.install_command ?? ""),
|
|
501
|
+
build_command: String(manifest.build_command ?? ""),
|
|
502
|
+
artifact_key: String(manifest.artifact_key ?? ""),
|
|
503
|
+
artifact_sha256: String(manifest.artifact_sha256 ?? ""),
|
|
504
|
+
created_at: String(manifest.created_at ?? ""),
|
|
505
|
+
signed_by: String(manifest.signed_by ?? "")
|
|
506
|
+
}))
|
|
507
|
+
.digest("hex");
|
|
508
|
+
if (manifest.signature !== expectedSignature) {
|
|
509
|
+
throw new Error("Template artifact manifest signature verification failed.");
|
|
510
|
+
}
|
|
511
|
+
if (manifest.template_id !== source.templateId || manifest.slug_id !== source.slugId) {
|
|
512
|
+
throw new Error("Template artifact manifest does not match the registered template identity.");
|
|
513
|
+
}
|
|
514
|
+
if (manifest.repo_url !== source.repoUrl || manifest.branch !== source.branch) {
|
|
515
|
+
throw new Error("Template artifact manifest does not match the registered repo URL or branch.");
|
|
516
|
+
}
|
|
517
|
+
if (manifest.template_module_path !== source.templateModulePath) {
|
|
518
|
+
throw new Error("Template artifact manifest does not match the registered template module path.");
|
|
519
|
+
}
|
|
520
|
+
if (manifest.skill_path !== source.skillPath) {
|
|
521
|
+
throw new Error("Template artifact manifest does not match the registered skill path.");
|
|
522
|
+
}
|
|
523
|
+
if (manifest.install_command !== source.installCommand || manifest.build_command !== source.buildCommand) {
|
|
524
|
+
throw new Error("Template artifact manifest does not match the registered install or build command.");
|
|
525
|
+
}
|
|
526
|
+
return manifest;
|
|
527
|
+
}
|
|
528
|
+
async extractArtifactToCheckout(input) {
|
|
529
|
+
const archive = await storage.readBuffer(input.artifactKey);
|
|
530
|
+
if (!archive) {
|
|
531
|
+
throw new Error(`Template artifact not found: ${input.artifactKey}`);
|
|
532
|
+
}
|
|
533
|
+
const actualSha256 = createHash("sha256").update(archive).digest("hex");
|
|
534
|
+
if (actualSha256 !== input.expectedSha256) {
|
|
535
|
+
throw new Error(`Template artifact hash mismatch for ${input.artifactKey}.`);
|
|
536
|
+
}
|
|
537
|
+
mkdirSync(input.checkoutPath, { recursive: true });
|
|
538
|
+
const tempArchivePath = path.join(os.tmpdir(), `vidfarm-template-${createId("tmp")}.tar.gz`);
|
|
539
|
+
writeFileSync(tempArchivePath, archive);
|
|
540
|
+
try {
|
|
541
|
+
await execFileAsync("tar", ["-xzf", tempArchivePath, "-C", input.checkoutPath], { cwd: process.cwd() });
|
|
542
|
+
}
|
|
543
|
+
finally {
|
|
544
|
+
rmSync(tempArchivePath, { force: true });
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
serializeArtifactManifestPayload(input) {
|
|
548
|
+
return JSON.stringify({
|
|
549
|
+
version: input.version,
|
|
550
|
+
algorithm: input.algorithm,
|
|
551
|
+
template_id: input.template_id,
|
|
552
|
+
slug_id: input.slug_id,
|
|
553
|
+
repo_url: input.repo_url,
|
|
554
|
+
branch: input.branch,
|
|
555
|
+
commit_sha: input.commit_sha,
|
|
556
|
+
template_module_path: input.template_module_path,
|
|
557
|
+
skill_path: input.skill_path,
|
|
558
|
+
install_command: input.install_command,
|
|
559
|
+
build_command: input.build_command,
|
|
560
|
+
artifact_key: input.artifact_key,
|
|
561
|
+
artifact_sha256: input.artifact_sha256,
|
|
562
|
+
created_at: input.created_at,
|
|
563
|
+
signed_by: input.signed_by
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
buildArtifactKeys(source, commitSha) {
|
|
567
|
+
return {
|
|
568
|
+
artifactKey: `template-artifacts/${source.templateId}/${commitSha}/source.tar.gz`,
|
|
569
|
+
manifestKey: `template-artifacts/${source.templateId}/${commitSha}/manifest.json`
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
async createSignedArtifactManifest(input) {
|
|
573
|
+
const artifact = this.buildArtifactKeys(input.source, input.commitSha);
|
|
574
|
+
const createdAt = nowIso();
|
|
575
|
+
const payload = {
|
|
576
|
+
version: 1,
|
|
577
|
+
algorithm: "hmac-sha256",
|
|
578
|
+
template_id: input.source.templateId,
|
|
579
|
+
slug_id: input.source.slugId,
|
|
580
|
+
repo_url: input.source.repoUrl,
|
|
581
|
+
branch: input.source.branch,
|
|
582
|
+
commit_sha: input.commitSha,
|
|
583
|
+
template_module_path: input.source.templateModulePath,
|
|
584
|
+
skill_path: input.source.skillPath,
|
|
585
|
+
install_command: input.source.installCommand,
|
|
586
|
+
build_command: input.source.buildCommand,
|
|
587
|
+
artifact_key: artifact.artifactKey,
|
|
588
|
+
artifact_sha256: input.artifactSha256,
|
|
589
|
+
created_at: createdAt,
|
|
590
|
+
signed_by: input.signedBy
|
|
591
|
+
};
|
|
592
|
+
const signature = createHmac("sha256", config.ARTIFACT_SIGNING_SECRET)
|
|
593
|
+
.update(this.serializeArtifactManifestPayload(payload))
|
|
594
|
+
.digest("hex");
|
|
595
|
+
await storage.putText(artifact.manifestKey, JSON.stringify({
|
|
596
|
+
...payload,
|
|
597
|
+
signature
|
|
598
|
+
}, null, 2), "application/json");
|
|
599
|
+
return {
|
|
600
|
+
...artifact,
|
|
601
|
+
signature
|
|
602
|
+
};
|
|
603
|
+
}
|
|
318
604
|
resolveGitRemoteUrl(repoUrl) {
|
|
319
605
|
const githubToken = config.VIDFARM_GITHUB_TOKEN || config.GITHUB_TOKEN;
|
|
320
606
|
if (!githubToken) {
|
|
@@ -341,3 +627,26 @@ export class TemplateSourceService {
|
|
|
341
627
|
throw new Error(`Template module path ${declaredModulePath} was not found in the imported release.`);
|
|
342
628
|
}
|
|
343
629
|
}
|
|
630
|
+
function inferContentType(filePath) {
|
|
631
|
+
switch (path.extname(filePath).toLowerCase()) {
|
|
632
|
+
case ".png":
|
|
633
|
+
return "image/png";
|
|
634
|
+
case ".gif":
|
|
635
|
+
return "image/gif";
|
|
636
|
+
case ".jpg":
|
|
637
|
+
case ".jpeg":
|
|
638
|
+
return "image/jpeg";
|
|
639
|
+
case ".webp":
|
|
640
|
+
return "image/webp";
|
|
641
|
+
case ".svg":
|
|
642
|
+
return "image/svg+xml";
|
|
643
|
+
case ".mp4":
|
|
644
|
+
return "video/mp4";
|
|
645
|
+
case ".webm":
|
|
646
|
+
return "video/webm";
|
|
647
|
+
case ".mov":
|
|
648
|
+
return "video/quicktime";
|
|
649
|
+
default:
|
|
650
|
+
return "application/octet-stream";
|
|
651
|
+
}
|
|
652
|
+
}
|