@mevdragon/vidfarm-devcli 0.20.5 → 0.20.8

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.
Files changed (154) hide show
  1. package/.agents/skills/editor-capabilities/SKILL.md +15 -1
  2. package/.agents/skills/vidfarm-director/SKILL.md +106 -0
  3. package/.agents/skills/vidfarm-director/recipes/find-and-fork-template.md +16 -0
  4. package/.agents/skills/vidfarm-director/recipes/local-edit-render-approve.md +13 -0
  5. package/.agents/skills/vidfarm-director/recipes/onboard-a-new-director.md +13 -0
  6. package/.agents/skills/vidfarm-director/recipes/retheme-template.md +17 -0
  7. package/.agents/skills/vidfarm-director/references/assets-and-sourcing.md +111 -0
  8. package/.agents/skills/vidfarm-director/references/automation-and-local-dev.md +243 -0
  9. package/.agents/skills/vidfarm-director/references/core-workflows.md +273 -0
  10. package/.agents/skills/vidfarm-director/references/editor-workflows.md +365 -0
  11. package/.agents/skills/vidfarm-director/references/onboarding.md +28 -0
  12. package/.agents/skills/vidfarm-director/references/primitives.md +265 -0
  13. package/SKILL.director.md +521 -261
  14. package/dist/src/cli.js +404 -96
  15. package/dist/src/devcli/clips.js +15 -10
  16. package/dist/src/devcli/doctor.js +2 -2
  17. package/dist/src/devcli/local-backend.js +46 -2
  18. package/dist/src/services/clip-curation/cost.js +5 -1
  19. package/dist/src/services/clip-curation/gemini.js +10 -0
  20. package/package.json +30 -10
  21. package/SKILL.platform.md +0 -432
  22. package/demo/README.md +0 -28
  23. package/demo/dist/app.css +0 -1
  24. package/demo/dist/app.js +0 -1850
  25. package/demo/dist/chunks/chunk-DXB73IDG.js +0 -1
  26. package/demo/dist/chunks/chunk-S7OWAJDS.js +0 -36
  27. package/demo/dist/chunks/chunk-VTIBZ6AN.js +0 -1
  28. package/demo/dist/chunks/dist-ADSJKBVE.js +0 -332
  29. package/demo/dist/chunks/domEditingLayers-VZMLL4AP-SGHWPND4.js +0 -1
  30. package/demo/dist/chunks/hyperframes-player-XB65TCD6.js +0 -425
  31. package/demo/dist/chunks/lib-XAQ37YOE.js +0 -1
  32. package/demo/dist/chunks/src-TJ2QYA4U.js +0 -207
  33. package/demo/dist/favicon.ico +0 -0
  34. package/demo/dist/icons/timeline/audio.svg +0 -7
  35. package/demo/dist/icons/timeline/captions.svg +0 -5
  36. package/demo/dist/icons/timeline/composition.svg +0 -12
  37. package/demo/dist/icons/timeline/image.svg +0 -18
  38. package/demo/dist/icons/timeline/music.svg +0 -10
  39. package/demo/dist/icons/timeline/text.svg +0 -3
  40. package/demo/dist/index.html +0 -15
  41. package/dist/src/account-pages-legacy.js +0 -9396
  42. package/dist/src/account-pages.js +0 -61
  43. package/dist/src/app.js +0 -21602
  44. package/dist/src/composition-runtime.js +0 -1053
  45. package/dist/src/config.js +0 -217
  46. package/dist/src/context.js +0 -447
  47. package/dist/src/dev-app-legacy.js +0 -739
  48. package/dist/src/dev-app.js +0 -6
  49. package/dist/src/devcli/migrate-local.js +0 -140
  50. package/dist/src/devcli/sync.js +0 -368
  51. package/dist/src/domain.js +0 -5
  52. package/dist/src/editor-chat-history.js +0 -82
  53. package/dist/src/editor-chat.js +0 -756
  54. package/dist/src/editor-dark-theme.js +0 -1128
  55. package/dist/src/frontend/debug.js +0 -71
  56. package/dist/src/frontend/discover-client.js +0 -130
  57. package/dist/src/frontend/discover-store.js +0 -23
  58. package/dist/src/frontend/file-directory.js +0 -1018
  59. package/dist/src/frontend/flockposter-cache-store.js +0 -124
  60. package/dist/src/frontend/homepage-client.js +0 -446
  61. package/dist/src/frontend/homepage-shared.js +0 -201
  62. package/dist/src/frontend/homepage-store.js +0 -66
  63. package/dist/src/frontend/homepage-view.js +0 -705
  64. package/dist/src/frontend/page-runtime-client.js +0 -132
  65. package/dist/src/frontend/page-runtime-store.js +0 -9
  66. package/dist/src/frontend/sentry.js +0 -42
  67. package/dist/src/frontend/template-editor-chat.js +0 -4181
  68. package/dist/src/help-page.js +0 -346
  69. package/dist/src/homepage.js +0 -1458
  70. package/dist/src/index.js +0 -16
  71. package/dist/src/instrument.js +0 -30
  72. package/dist/src/landing-page.js +0 -384
  73. package/dist/src/page-runtime.js +0 -2
  74. package/dist/src/page-shell.js +0 -1452
  75. package/dist/src/primitive-context.js +0 -416
  76. package/dist/src/primitive-registry.js +0 -3940
  77. package/dist/src/primitive-sdk.js +0 -4
  78. package/dist/src/primitives/hyperframes-media.js +0 -108
  79. package/dist/src/react-page-shell.js +0 -35
  80. package/dist/src/ready-post-schedule-component.js +0 -1540
  81. package/dist/src/registry.js +0 -296
  82. package/dist/src/reskin/agency-page.js +0 -299
  83. package/dist/src/reskin/calendar-page.js +0 -568
  84. package/dist/src/reskin/chat-page.js +0 -942
  85. package/dist/src/reskin/discover-page.js +0 -1788
  86. package/dist/src/reskin/document.js +0 -1587
  87. package/dist/src/reskin/help-page.js +0 -357
  88. package/dist/src/reskin/index-page.js +0 -62
  89. package/dist/src/reskin/inpaint-clipper-page.js +0 -890
  90. package/dist/src/reskin/inpaint-page.js +0 -2554
  91. package/dist/src/reskin/inpaint-video-page.js +0 -1339
  92. package/dist/src/reskin/job-runs-page.js +0 -477
  93. package/dist/src/reskin/library-page.js +0 -1634
  94. package/dist/src/reskin/login-page.js +0 -262
  95. package/dist/src/reskin/portfolio-page.js +0 -687
  96. package/dist/src/reskin/pricing-page.js +0 -390
  97. package/dist/src/reskin/settings-page.js +0 -732
  98. package/dist/src/reskin/theme.js +0 -711
  99. package/dist/src/runtime.js +0 -35
  100. package/dist/src/services/api-call-history.js +0 -249
  101. package/dist/src/services/auth.js +0 -152
  102. package/dist/src/services/billing-pricing.js +0 -39
  103. package/dist/src/services/billing.js +0 -241
  104. package/dist/src/services/cast.js +0 -127
  105. package/dist/src/services/chat-threads.js +0 -92
  106. package/dist/src/services/clip-records.js +0 -250
  107. package/dist/src/services/clip-search.js +0 -77
  108. package/dist/src/services/clip-vectors.js +0 -125
  109. package/dist/src/services/composition-sanitize.js +0 -124
  110. package/dist/src/services/composition-watch.js +0 -79
  111. package/dist/src/services/elevenlabs.js +0 -222
  112. package/dist/src/services/file-directory.js +0 -117
  113. package/dist/src/services/fork-access.js +0 -93
  114. package/dist/src/services/fork-manifest.js +0 -42
  115. package/dist/src/services/ghostcut.js +0 -179
  116. package/dist/src/services/hyperframes.js +0 -3517
  117. package/dist/src/services/job-capacity.js +0 -14
  118. package/dist/src/services/job-logs.js +0 -197
  119. package/dist/src/services/jobs.js +0 -136
  120. package/dist/src/services/local-dynamo.js +0 -0
  121. package/dist/src/services/media-processing.js +0 -766
  122. package/dist/src/services/primitive-media-lambda.js +0 -280
  123. package/dist/src/services/providers.js +0 -2748
  124. package/dist/src/services/rate-limits.js +0 -262
  125. package/dist/src/services/scene-annotations.js +0 -32
  126. package/dist/src/services/serverless-auth.js +0 -382
  127. package/dist/src/services/serverless-jobs.js +0 -1084
  128. package/dist/src/services/serverless-provider-keys.js +0 -409
  129. package/dist/src/services/serverless-records.js +0 -1515
  130. package/dist/src/services/serverless-template-configs.js +0 -75
  131. package/dist/src/services/storage.js +0 -461
  132. package/dist/src/services/swipe-customize.js +0 -437
  133. package/dist/src/services/template-certification.js +0 -413
  134. package/dist/src/services/template-loader.js +0 -99
  135. package/dist/src/services/template-runtime-bundles.js +0 -217
  136. package/dist/src/services/template-sources.js +0 -1017
  137. package/dist/src/services/upstream.js +0 -248
  138. package/dist/src/services/video-normalization.js +0 -2
  139. package/dist/src/services/webhooks.js +0 -62
  140. package/dist/src/template-editor-pages.js +0 -2576
  141. package/dist/src/template-editor-shell.js +0 -2893
  142. package/dist/src/template-sdk.js +0 -4
  143. package/dist/src/worker.js +0 -17
  144. package/public/assets/discover-client-app.js +0 -1
  145. package/public/assets/file-directory-app.js +0 -3
  146. package/public/assets/homepage-app.js +0 -54
  147. package/public/assets/homepage-client-app.js +0 -80
  148. package/public/assets/page-runtime-client-app.js +0 -94
  149. package/public/assets/placeholders/scene-placeholder.png +0 -0
  150. package/src/assets/SELLING_AWARENESS_STAGES.md +0 -579
  151. package/src/assets/SELLING_WITH_HOOKS.md +0 -377
  152. package/src/assets/SELLING_WITH_VSLS.md +0 -606
  153. package/src/assets/favicon.ico +0 -0
  154. package/src/assets/logo-vidfarm.png +0 -0
@@ -1,413 +0,0 @@
1
- import { existsSync, readFileSync, readdirSync } from "node:fs";
2
- import path from "node:path";
3
- const APPROVED_TEMPLATE_MODEL_IDS = new Set([
4
- "gpt-5.4",
5
- "gemini-3.1-flash-lite",
6
- "gemini-3.1-flash-lite-preview",
7
- "gemini-2.5-flash-lite",
8
- "qwen/qwen3.6-plus",
9
- "sonar",
10
- "gpt-image-1",
11
- "gpt-image-2",
12
- "gemini-3.1-flash-image-preview",
13
- "gemini-2.5-flash-image",
14
- "gemini-3-pro-image-preview",
15
- "google/gemini-3.1-flash-image-preview",
16
- "google/gemini-2.5-flash-image-preview",
17
- "bytedance/seedance-2.0",
18
- "bytedance-seed/seedream-4.5",
19
- "google/gemini-3.1-flash-tts-preview",
20
- "gemini-3.1-flash-tts-preview",
21
- "gemini-2.5-flash-preview-tts",
22
- "gpt-4o-mini-tts-2025-12-15",
23
- "openai/gpt-4o-mini-transcribe",
24
- "gpt-4o-mini-transcribe-2025-12-15",
25
- "sora-2",
26
- "veo-3.0-generate-001"
27
- ]);
28
- const TEMPLATE_DIRECT_PROVIDER_ACCESS_PATTERNS = [
29
- /process\.env\.(OPENAI_API_KEY|GEMINI_API_KEY|OPENROUTER_API_KEY|PERPLEXITY_API_KEY)/,
30
- /https?:\/\/api\.openai\.com/,
31
- /https?:\/\/generativelanguage\.googleapis\.com/,
32
- /https?:\/\/openrouter\.ai/,
33
- /https?:\/\/api\.perplexity\.ai/,
34
- /\bAuthorization\s*:/,
35
- /\bapiKey\s*:/,
36
- /\bapi_key\s*:/
37
- ];
38
- const TEMPLATE_OPERATION_PROVIDER_DEFAULT_PATTERN = /(?:^|[\s,{])(?:provider|text_provider|image_provider|tts_provider|speech_provider|transcription_provider)\s*:\s*z\.enum\([^;\n]+\.default\(/;
39
- const TEMPLATE_GEMINI_PROVIDER_FALLBACK_PATTERN = /(?:default(?:Text|Image)?Provider|textProvider|imageProvider|ttsProvider|voiceProvider|transcriptionProvider)\s*:\s*z\.enum\([^;\n]+\.default\(["']gemini["']\)|return\s+["']gemini["'];/g;
40
- const TEMPLATE_MODEL_LITERAL_PATTERN = /["'`](dall-e-3|dall-e|gpt-[^"'`]+|gemini-[^"'`]+|google\/gemini-[^"'`]+|openai\/gpt-[^"'`]+|qwen\/qwen[^"'`]+|bytedance\/[^"'`]+|bytedance-seed\/[^"'`]+|sora-[^"'`]+|veo-[^"'`]+|sonar(?:-[^"'`]+)?)["'`]/g;
41
- const TEMPLATE_UNSAFE_MODEL_PASSTHROUGH_PATTERN = /String\(ctx\.templateConfig\.[A-Za-z_]*Model|ctx\.templateConfig\.[A-Za-z_]*Model\s*\?\?|payload\.[A-Za-z_]*model\s*\?\?|sanitizeConfiguredModel\([^;\n]*(?:textModel|imageModel|layoutModel|ttsModel|transcriptionModel|speechModel|payload\.model|payload\.tts_model|payload\.transcription_model|payload\.speech_model)/g;
42
- export class TemplateCertificationService {
43
- async certify(input) {
44
- const checks = [];
45
- const { template, skillPath } = input;
46
- checks.push(this.check("template.metadata", Boolean(template.id &&
47
- template.slugId &&
48
- template.version &&
49
- template.about &&
50
- typeof template.about.title === "string" &&
51
- typeof template.about.description === "string" &&
52
- ["easy", "medium", "hard", "expert"].includes(template.about.difficulty) &&
53
- typeof template.about.viral_dna === "string" &&
54
- typeof template.about.visual_dna === "string" &&
55
- Array.isArray(template.about.preview_media) &&
56
- template.about.preview_media.every((entry) => typeof entry === "string") &&
57
- typeof template.about.link_to_original === "string" &&
58
- Array.isArray(template.about.links_to_inspiration) &&
59
- template.about.links_to_inspiration.every((entry) => typeof entry === "string") &&
60
- template.about.sound &&
61
- typeof template.about.sound.sound_title === "string" &&
62
- typeof template.about.sound.sound_url === "string" &&
63
- typeof template.about.proposal_generator === "string" &&
64
- typeof template.about.skeleton_prompt === "string" &&
65
- template.about.skeleton_prompt.length > 0 &&
66
- Array.isArray(template.about.sample_prompts) &&
67
- template.about.sample_prompts.every((entry) => typeof entry === "string") &&
68
- template.about.sample_prompts.length > 0 &&
69
- Array.isArray(template.examples) &&
70
- template.examples.every((example) => Array.isArray(example) && example.every((entry) => (entry &&
71
- typeof entry.media_url === "string" &&
72
- typeof entry.note === "string")))), "Template must define id, slugId, version, examples, and complete about metadata, including difficulty, links_to_inspiration, sound, proposal_generator, skeleton_prompt, and sample prompts.", {
73
- templateId: template.id,
74
- slugId: template.slugId,
75
- version: template.version,
76
- difficulty: template.about?.difficulty ?? null,
77
- inspirationLinkCount: template.about?.links_to_inspiration?.length ?? 0,
78
- hasSound: Boolean(template.about?.sound),
79
- exampleCount: template.examples?.length ?? 0,
80
- previewMediaCount: template.about?.preview_media?.length ?? 0,
81
- hasProposalGenerator: typeof template.about?.proposal_generator === "string" && template.about.proposal_generator.length > 0,
82
- hasSkeletonPrompt: typeof template.about?.skeleton_prompt === "string" && template.about.skeleton_prompt.length > 0,
83
- samplePromptCount: template.about?.sample_prompts?.length ?? 0
84
- }));
85
- checks.push(this.check("template.operations", Object.keys(template.operations).length > 0, "Template must define at least one operation."));
86
- checks.push(this.checkSkill(skillPath));
87
- checks.push(...this.checkProviderPolicy({ modulePath: input.modulePath }));
88
- for (const [operationName, operation] of Object.entries(template.operations)) {
89
- checks.push(this.check(`operation.${operationName}.workflow`, typeof template.jobs[operation.workflow] === "function", `Operation ${operationName} must reference an existing workflow.`, { workflow: operation.workflow }));
90
- checks.push(this.check(`operation.${operationName}.smoke_payload`, Boolean(operation.smokeTestPayload), `Operation ${operationName} must define smokeTestPayload for certification.`));
91
- if (!operation.smokeTestPayload) {
92
- continue;
93
- }
94
- try {
95
- const payload = operation.inputSchema.parse(operation.smokeTestPayload);
96
- const workflow = template.jobs[operation.workflow];
97
- const smoke = createSmokeContext(template.id);
98
- const result = await workflow(smoke.ctx, payload);
99
- checks.push(this.check(`operation.${operationName}.smoke_run`, Boolean(result && (result.output || result.progress !== undefined)), `Operation ${operationName} smoke run completed.`, {
100
- logCount: smoke.logCount,
101
- storageWrites: smoke.storageWrites,
102
- billingCalls: smoke.billingCalls,
103
- providerCalls: smoke.providerCalls,
104
- remotionCalls: smoke.remotionCalls
105
- }));
106
- checks.push(this.check(`operation.${operationName}.logs`, smoke.logCount > 0, `Operation ${operationName} must emit at least one log/progress event during smoke run.`));
107
- }
108
- catch (error) {
109
- checks.push(this.check(`operation.${operationName}.smoke_run`, false, error instanceof Error ? error.message : "Smoke run failed."));
110
- }
111
- }
112
- return {
113
- passed: checks.every((check) => check.ok),
114
- checks
115
- };
116
- }
117
- check(code, ok, message, details) {
118
- return { code, ok, message, details };
119
- }
120
- checkSkill(skillPath) {
121
- try {
122
- const contents = readFileSync(skillPath, "utf8").trim();
123
- return this.check("template.skill", contents.length >= 40, "Template must include a non-trivial SKILL.md for customer agents.", { skillPath });
124
- }
125
- catch (error) {
126
- return this.check("template.skill", false, error instanceof Error ? error.message : "Unable to read SKILL.md.", { skillPath });
127
- }
128
- }
129
- checkProviderPolicy(input) {
130
- if (!input.modulePath) {
131
- return [
132
- this.check("template.provider_policy.source", true, "Template module path was not provided; skipped provider policy source validation.")
133
- ];
134
- }
135
- const moduleContents = readFileSync(input.modulePath, "utf8");
136
- const directProviderAccess = TEMPLATE_DIRECT_PROVIDER_ACCESS_PATTERNS
137
- .flatMap((pattern) => collectPatternMatches(moduleContents, pattern))
138
- .map((match) => ({
139
- line: lineNumberForOffset(moduleContents, match.index),
140
- text: match.text.slice(0, 140)
141
- }));
142
- const providerDefaults = collectPatternMatches(moduleContents, TEMPLATE_OPERATION_PROVIDER_DEFAULT_PATTERN)
143
- .map((match) => ({
144
- line: lineNumberForOffset(moduleContents, match.index),
145
- text: match.text.slice(0, 140)
146
- }));
147
- const geminiFallbacks = collectPatternMatches(moduleContents, TEMPLATE_GEMINI_PROVIDER_FALLBACK_PATTERN)
148
- .map((match) => ({
149
- line: lineNumberForOffset(moduleContents, match.index),
150
- text: match.text.slice(0, 140)
151
- }));
152
- const unsupportedModels = collectUnsupportedModelLiterals(moduleContents);
153
- const unsafeModelPassthrough = collectPatternMatches(moduleContents, TEMPLATE_UNSAFE_MODEL_PASSTHROUGH_PATTERN)
154
- .filter((match) => !isInsideSafeProviderModelResolver(moduleContents, match.index))
155
- .map((match) => ({
156
- line: lineNumberForOffset(moduleContents, match.index),
157
- text: match.text.slice(0, 140)
158
- }));
159
- return [
160
- this.check("template.provider_policy.keys", directProviderAccess.length === 0, "Templates must use ctx.providers so AI calls lease the customer's saved provider keys; direct provider env/API usage is not allowed.", directProviderAccess.length > 0 ? { modulePath: input.modulePath, matches: directProviderAccess.slice(0, 10) } : { modulePath: input.modulePath }),
161
- this.check("template.provider_policy.operation_defaults", providerDefaults.length === 0, "Operation payload provider fields must be optional explicit overrides; provider defaults belong in saved template config.", providerDefaults.length > 0 ? { modulePath: input.modulePath, matches: providerDefaults.slice(0, 10) } : { modulePath: input.modulePath }),
162
- this.check("template.provider_policy.provider_fallbacks", geminiFallbacks.length === 0, "Templates must not hide Gemini provider defaults or parser fallbacks. AI calls must use ctx.providers so platform resolution can choose from the customer's saved active keys first.", geminiFallbacks.length > 0 ? { modulePath: input.modulePath, matches: geminiFallbacks.slice(0, 10) } : { modulePath: input.modulePath }),
163
- this.check("template.provider_policy.models", unsupportedModels.length === 0, "Templates may only reference model IDs from the approved Vidfarm provider allowlist.", unsupportedModels.length > 0 ? { modulePath: input.modulePath, models: unsupportedModels.slice(0, 20) } : { modulePath: input.modulePath }),
164
- this.check("template.provider_policy.model_resolution", unsafeModelPassthrough.length === 0, "Template model config and payload overrides must be validated against the selected provider/model allowlist before calling ctx.providers.", unsafeModelPassthrough.length > 0 ? { modulePath: input.modulePath, matches: unsafeModelPassthrough.slice(0, 10) } : { modulePath: input.modulePath })
165
- ];
166
- }
167
- }
168
- const MOCK_PNG_BYTES = Uint8Array.from(Buffer.from("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAADUlEQVR4nGP4////fwAJ+wP9KobjigAAAABJRU5ErkJggg==", "base64"));
169
- function createSmokeContext(templateId) {
170
- let logCount = 0;
171
- let storageWrites = 0;
172
- let billingCalls = 0;
173
- let providerCalls = 0;
174
- let remotionCalls = 0;
175
- const prefix = `templates/${templateId}/users/certification-user/jobs/certification-job`;
176
- const ctx = {
177
- env: "development",
178
- customer: {
179
- id: "certification-user",
180
- email: "certification@vidfarm.local",
181
- name: "Certification",
182
- defaultWebhookUrl: null,
183
- isDeveloper: true,
184
- isAgency: false,
185
- isPaidPlan: true,
186
- planTier: "standalone",
187
- about: null,
188
- groupchatUrl: null,
189
- flockposterApiKey: null,
190
- createdAt: new Date(0).toISOString(),
191
- updatedAt: new Date(0).toISOString()
192
- },
193
- template: {
194
- id: templateId,
195
- slugId: "certification-template",
196
- previewMediaUrls: [],
197
- previewMediaPolicy: "auto"
198
- },
199
- templateConfig: {},
200
- logger: {
201
- debug() { logCount += 1; },
202
- info() { logCount += 1; },
203
- warn() { logCount += 1; },
204
- error() { logCount += 1; },
205
- progress() { logCount += 1; }
206
- },
207
- jobs: {
208
- async enqueueChild() {
209
- return { jobId: "child-certification-job" };
210
- }
211
- },
212
- storage: {
213
- async putJson(key) {
214
- storageWrites += 1;
215
- return { key: `${prefix}/${key}`, url: `https://certification.local/${encodeURIComponent(key)}` };
216
- },
217
- async putText(key) {
218
- storageWrites += 1;
219
- return { key: `${prefix}/${key}`, url: `https://certification.local/${encodeURIComponent(key)}` };
220
- },
221
- async putBuffer(key) {
222
- storageWrites += 1;
223
- return { key: `${prefix}/${key}`, url: `https://certification.local/${encodeURIComponent(key)}` };
224
- },
225
- getPublicUrl(key) {
226
- return `https://certification.local/${encodeURIComponent(`${prefix}/${key}`)}`;
227
- }
228
- },
229
- billing: {
230
- async record() {
231
- billingCalls += 1;
232
- }
233
- },
234
- providers: {
235
- listAvailableProviders() {
236
- return ["openai", "gemini", "openrouter", "perplexity"];
237
- },
238
- async generateText() {
239
- providerCalls += 1;
240
- return { text: "certification text", usage: { inputTokens: 1, outputTokens: 1, costUsd: 0 } };
241
- },
242
- async generateSpeech() {
243
- providerCalls += 1;
244
- return { bytes: Uint8Array.from([0, 1, 2, 3]), contentType: "audio/mpeg", usage: { inputTokens: 1, outputTokens: 1, costUsd: 0 } };
245
- },
246
- async generateImage() {
247
- providerCalls += 1;
248
- return { bytes: MOCK_PNG_BYTES, contentType: "image/png", revisedPrompt: null };
249
- },
250
- async analyzeImageLayout() {
251
- providerCalls += 1;
252
- return {
253
- zone: "bottom",
254
- align: "center",
255
- maxWidthPercent: 80,
256
- justification: "Certification mock layout."
257
- };
258
- },
259
- async transcribeSpeech() {
260
- providerCalls += 1;
261
- return { text: "certification transcript", usage: { inputTokens: 1, outputTokens: 1, costUsd: 0 } };
262
- }
263
- },
264
- hyperframes: {
265
- async render() {
266
- remotionCalls += 1;
267
- return {
268
- renderId: "hyperframes-render-certification",
269
- outputUrl: "https://certification.local/hyperframes-render.mp4",
270
- outputS3Uri: null,
271
- metadata: { mode: "certification-mock", architecture: "timeline_layers" }
272
- };
273
- }
274
- },
275
- media: {
276
- async normalizeVideo(input) {
277
- storageWrites += 1;
278
- return {
279
- key: `${prefix}/${input.outputKey}`,
280
- url: `https://certification.local/${encodeURIComponent(input.outputKey)}`,
281
- contentType: "video/mp4",
282
- normalization: {
283
- source: {
284
- durationSeconds: 5,
285
- width: 1080,
286
- height: 1920,
287
- videoCodec: "h264",
288
- audioCodec: "aac",
289
- videoBitrateKbps: 2000,
290
- audioBitrateKbps: 128,
291
- formatBitrateKbps: 2200,
292
- hasAudio: true,
293
- hasVideo: true,
294
- sampleRateHz: 48_000,
295
- channels: 2,
296
- frameRate: 30,
297
- formatName: "mp4",
298
- bytes: 1_000_000,
299
- url: input.sourceUrl
300
- },
301
- normalized: {
302
- durationSeconds: 5,
303
- width: 1080,
304
- height: 1920,
305
- videoCodec: "h264",
306
- audioCodec: "aac",
307
- videoBitrateKbps: 1500,
308
- audioBitrateKbps: 128,
309
- formatBitrateKbps: 1650,
310
- hasAudio: true,
311
- hasVideo: true,
312
- sampleRateHz: 48_000,
313
- channels: 2,
314
- frameRate: 30,
315
- formatName: "mp4",
316
- bytes: 750_000
317
- },
318
- compressionRatio: 0.75
319
- }
320
- };
321
- }
322
- }
323
- };
324
- return {
325
- ctx,
326
- get logCount() { return logCount; },
327
- get storageWrites() { return storageWrites; },
328
- get billingCalls() { return billingCalls; },
329
- get providerCalls() { return providerCalls; },
330
- get remotionCalls() { return remotionCalls; }
331
- };
332
- }
333
- function findTemplateRoot(modulePath) {
334
- let current = path.dirname(modulePath);
335
- for (let index = 0; index < 10; index += 1) {
336
- if (existsSync(path.join(current, "template.config.json"))) {
337
- return current;
338
- }
339
- const parent = path.dirname(current);
340
- if (parent === current) {
341
- break;
342
- }
343
- current = parent;
344
- }
345
- return null;
346
- }
347
- function nonBlankString(value) {
348
- if (typeof value !== "string") {
349
- return null;
350
- }
351
- const trimmed = value.trim();
352
- return trimmed ? trimmed : null;
353
- }
354
- function collectTemplateSourceFiles(templateRoot) {
355
- const files = [];
356
- const stack = [templateRoot];
357
- while (stack.length > 0) {
358
- const current = stack.pop();
359
- if (!current) {
360
- continue;
361
- }
362
- for (const entry of readdirSync(current, { withFileTypes: true })) {
363
- if (entry.name === "node_modules" || entry.name === "build" || entry.name === "dist" || entry.name.startsWith(".")) {
364
- continue;
365
- }
366
- const fullPath = path.join(current, entry.name);
367
- if (entry.isDirectory()) {
368
- stack.push(fullPath);
369
- continue;
370
- }
371
- if (/\.(?:[cm]?[jt]sx?)$/i.test(entry.name)) {
372
- files.push(fullPath);
373
- }
374
- }
375
- }
376
- return files;
377
- }
378
- function collectPatternMatches(contents, pattern) {
379
- const source = pattern.global ? pattern : new RegExp(pattern.source, pattern.flags.includes("g") ? pattern.flags : `${pattern.flags}g`);
380
- const matches = [];
381
- for (const match of contents.matchAll(source)) {
382
- matches.push({ index: match.index ?? 0, text: match[0] });
383
- }
384
- return matches;
385
- }
386
- function collectUnsupportedModelLiterals(contents) {
387
- const seen = new Map();
388
- for (const match of contents.matchAll(TEMPLATE_MODEL_LITERAL_PATTERN)) {
389
- const model = match[1]?.trim();
390
- if (!model || APPROVED_TEMPLATE_MODEL_IDS.has(model) || seen.has(model)) {
391
- continue;
392
- }
393
- seen.set(model, {
394
- model,
395
- line: lineNumberForOffset(contents, match.index ?? 0)
396
- });
397
- }
398
- return [...seen.values()];
399
- }
400
- function lineNumberForOffset(contents, offset) {
401
- let line = 1;
402
- for (let index = 0; index < offset; index += 1) {
403
- if (contents.charCodeAt(index) === 10) {
404
- line += 1;
405
- }
406
- }
407
- return line;
408
- }
409
- function isInsideSafeProviderModelResolver(contents, offset) {
410
- const prefix = contents.slice(Math.max(0, offset - 80), offset);
411
- return prefix.includes("sanitizeProviderModel(");
412
- }
413
- //# sourceMappingURL=template-certification.js.map
@@ -1,99 +0,0 @@
1
- import { pathToFileURL } from "node:url";
2
- export async function loadTemplateFromModule(modulePath) {
3
- const loaded = await import(pathToFileURL(modulePath).href);
4
- const candidates = Object.values(loaded);
5
- for (const candidate of candidates) {
6
- if (isTemplateDefinition(candidate)) {
7
- return normalizeTemplateDefinition(candidate);
8
- }
9
- }
10
- throw new Error(`No template definition export found in ${modulePath}`);
11
- }
12
- function normalizeTemplateDefinition(template) {
13
- return {
14
- ...template,
15
- about: {
16
- ...template.about,
17
- // Older runtime template releases may predate prompt metadata fields.
18
- difficulty: template.about.difficulty ?? "easy",
19
- links_to_inspiration: normalizeTemplateInspirationLinks(template.about.links_to_inspiration, template.about.link_to_original),
20
- sound: normalizeTemplateSound(template.about.sound),
21
- proposal_generator: template.about.proposal_generator ?? "",
22
- skeleton_prompt: template.about.skeleton_prompt ?? "",
23
- sample_prompts: template.about.sample_prompts ?? []
24
- },
25
- examples: template.examples ?? []
26
- };
27
- }
28
- function isTemplateDefinition(value) {
29
- if (!value || typeof value !== "object") {
30
- return false;
31
- }
32
- const candidate = value;
33
- const about = typeof candidate.about === "object" && candidate.about !== null
34
- ? candidate.about
35
- : null;
36
- const previewMedia = about && Array.isArray(about.preview_media)
37
- ? about.preview_media
38
- : null;
39
- const samplePrompts = about && Array.isArray(about.sample_prompts)
40
- ? about.sample_prompts
41
- : null;
42
- const sound = about && typeof about.sound === "object" && about.sound !== null
43
- ? about.sound
44
- : null;
45
- const linksToInspiration = about && Array.isArray(about.links_to_inspiration)
46
- ? about.links_to_inspiration
47
- : null;
48
- const examples = Array.isArray(candidate.examples)
49
- ? candidate.examples
50
- : null;
51
- return (typeof candidate.id === "string" &&
52
- typeof candidate.slugId === "string" &&
53
- typeof candidate.version === "string" &&
54
- about !== null &&
55
- typeof about.title === "string" &&
56
- typeof about.description === "string" &&
57
- (["easy", "medium", "hard", "expert"].includes(String(about.difficulty)) || typeof about.difficulty === "undefined") &&
58
- typeof about.viral_dna === "string" &&
59
- typeof about.visual_dna === "string" &&
60
- Array.isArray(previewMedia) &&
61
- previewMedia.every((entry) => typeof entry === "string") &&
62
- typeof about.link_to_original === "string" &&
63
- (linksToInspiration === null || linksToInspiration.every((entry) => typeof entry === "string")) &&
64
- (sound === null || (typeof sound.sound_title === "string" &&
65
- typeof sound.sound_url === "string")) &&
66
- (typeof about.proposal_generator === "string" || typeof about.proposal_generator === "undefined") &&
67
- (typeof about.skeleton_prompt === "string" || typeof about.skeleton_prompt === "undefined") &&
68
- (samplePrompts === null || samplePrompts.every((entry) => typeof entry === "string")) &&
69
- (examples === null || examples.every((example) => Array.isArray(example) && example.every((entry) => {
70
- if (!entry || typeof entry !== "object") {
71
- return false;
72
- }
73
- const media = entry;
74
- return typeof media.media_url === "string" && typeof media.note === "string";
75
- }))) &&
76
- typeof candidate.configSchema === "object" &&
77
- typeof candidate.operations === "object" &&
78
- typeof candidate.jobs === "object");
79
- }
80
- function normalizeTemplateSound(value) {
81
- if (!value || typeof value !== "object") {
82
- return {
83
- sound_title: "",
84
- sound_url: ""
85
- };
86
- }
87
- const sound = value;
88
- return {
89
- sound_title: typeof sound.sound_title === "string" ? sound.sound_title : "",
90
- sound_url: typeof sound.sound_url === "string" ? sound.sound_url : ""
91
- };
92
- }
93
- function normalizeTemplateInspirationLinks(value, linkToOriginal) {
94
- if (Array.isArray(value)) {
95
- return value.filter((entry) => typeof entry === "string");
96
- }
97
- return linkToOriginal ? [linkToOriginal] : [];
98
- }
99
- //# sourceMappingURL=template-loader.js.map