@mevdragon/vidfarm-devcli 0.5.3 → 0.7.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.
Files changed (116) hide show
  1. package/README.md +3 -3
  2. package/SKILL.director.md +28 -7
  3. package/SKILL.platform.md +9 -5
  4. package/demo/README.md +28 -0
  5. package/demo/dist/app.css +1 -0
  6. package/demo/dist/app.js +1184 -0
  7. package/demo/dist/chunks/chunk-DXB73IDG.js +1 -0
  8. package/demo/dist/chunks/chunk-S7OWAJDS.js +36 -0
  9. package/demo/dist/chunks/chunk-VTIBZ6AN.js +1 -0
  10. package/demo/dist/chunks/dist-ADSJKBVE.js +332 -0
  11. package/demo/dist/chunks/domEditingLayers-VZMLL4AP-SGHWPND4.js +1 -0
  12. package/demo/dist/chunks/hyperframes-player-XB65TCD6.js +425 -0
  13. package/demo/dist/chunks/lib-XAQ37YOE.js +1 -0
  14. package/demo/dist/chunks/src-TJ2QYA4U.js +207 -0
  15. package/demo/dist/favicon.ico +0 -0
  16. package/demo/dist/icons/timeline/audio.svg +7 -0
  17. package/demo/dist/icons/timeline/captions.svg +5 -0
  18. package/demo/dist/icons/timeline/composition.svg +12 -0
  19. package/demo/dist/icons/timeline/image.svg +18 -0
  20. package/demo/dist/icons/timeline/music.svg +10 -0
  21. package/demo/dist/icons/timeline/text.svg +3 -0
  22. package/demo/dist/index.html +15 -0
  23. package/dist/src/account-pages-legacy.js +9396 -0
  24. package/dist/src/account-pages.js +61 -0
  25. package/dist/src/app.js +14663 -0
  26. package/dist/src/cli.js +60 -97
  27. package/dist/src/composition-runtime.js +613 -0
  28. package/dist/src/config.js +173 -0
  29. package/dist/src/context.js +447 -0
  30. package/dist/src/dev-app-legacy.js +739 -0
  31. package/dist/src/dev-app.js +6 -0
  32. package/dist/src/domain.js +2 -0
  33. package/dist/src/editor-chat-history.js +82 -0
  34. package/dist/src/editor-chat.js +449 -0
  35. package/dist/src/editor-dark-theme.js +1128 -0
  36. package/dist/src/frontend/debug.js +71 -0
  37. package/dist/src/frontend/flockposter-cache-store.js +124 -0
  38. package/dist/src/frontend/homepage-client.js +182 -0
  39. package/dist/src/frontend/homepage-shared.js +4 -0
  40. package/dist/src/frontend/homepage-store.js +28 -0
  41. package/dist/src/frontend/homepage-view.js +547 -0
  42. package/dist/src/frontend/page-runtime-client.js +132 -0
  43. package/dist/src/frontend/page-runtime-store.js +9 -0
  44. package/dist/src/frontend/sentry.js +42 -0
  45. package/dist/src/frontend/template-editor-chat.js +3960 -0
  46. package/dist/src/help-page.js +346 -0
  47. package/dist/src/homepage.js +1235 -0
  48. package/dist/src/hyperframes/composition.js +180 -0
  49. package/dist/src/index.js +16 -0
  50. package/dist/src/instrument.js +30 -0
  51. package/dist/src/lib/crypto.js +45 -0
  52. package/dist/src/lib/dev-log.js +54 -0
  53. package/dist/src/lib/display-name.js +11 -0
  54. package/dist/src/lib/ids.js +24 -0
  55. package/dist/src/lib/images.js +19 -0
  56. package/dist/src/lib/json.js +15 -0
  57. package/dist/src/lib/package-root.js +47 -0
  58. package/dist/src/lib/template-paths.js +28 -0
  59. package/dist/src/lib/time.js +7 -0
  60. package/dist/src/lib/url-clean.js +85 -0
  61. package/dist/src/page-runtime.js +2 -0
  62. package/dist/src/page-shell.js +1381 -0
  63. package/dist/src/primitive-context.js +357 -0
  64. package/dist/src/primitive-registry.js +2561 -0
  65. package/dist/src/primitive-sdk.js +4 -0
  66. package/dist/src/primitives/hyperframes-media.js +108 -0
  67. package/dist/src/react-page-shell.js +35 -0
  68. package/dist/src/ready-post-schedule-component.js +1540 -0
  69. package/dist/src/registry.js +296 -0
  70. package/dist/src/runtime.js +35 -0
  71. package/dist/src/services/api-call-history.js +249 -0
  72. package/dist/src/services/auth.js +152 -0
  73. package/dist/src/services/billing-pricing.js +39 -0
  74. package/dist/src/services/billing.js +228 -0
  75. package/dist/src/services/cast.js +127 -0
  76. package/dist/src/services/chat-threads.js +92 -0
  77. package/dist/src/services/composition-sanitize.js +124 -0
  78. package/dist/src/services/composition-watch.js +79 -0
  79. package/dist/src/services/fork-access.js +93 -0
  80. package/dist/src/services/fork-manifest.js +42 -0
  81. package/dist/src/services/ghostcut.js +179 -0
  82. package/dist/src/services/hyperframes.js +2307 -0
  83. package/dist/src/services/job-capacity.js +14 -0
  84. package/dist/src/services/job-logs.js +197 -0
  85. package/dist/src/services/jobs.js +136 -0
  86. package/dist/src/services/local-dynamo.js +0 -0
  87. package/dist/src/services/media-processing.js +766 -0
  88. package/dist/src/services/primitive-media-lambda.js +280 -0
  89. package/dist/src/services/providers.js +2926 -0
  90. package/dist/src/services/rate-limits.js +262 -0
  91. package/dist/src/services/serverless-auth.js +382 -0
  92. package/dist/src/services/serverless-jobs.js +1082 -0
  93. package/dist/src/services/serverless-provider-keys.js +409 -0
  94. package/dist/src/services/serverless-records.js +1385 -0
  95. package/dist/src/services/serverless-template-configs.js +75 -0
  96. package/dist/src/services/storage.js +383 -0
  97. package/dist/src/services/template-certification.js +413 -0
  98. package/dist/src/services/template-loader.js +99 -0
  99. package/dist/src/services/template-runtime-bundles.js +217 -0
  100. package/dist/src/services/template-sources.js +1017 -0
  101. package/dist/src/services/upstream.js +248 -0
  102. package/dist/src/services/video-normalization.js +2 -0
  103. package/dist/src/services/webhooks.js +62 -0
  104. package/dist/src/template-editor-pages.js +2576 -0
  105. package/dist/src/template-editor-shell.js +2840 -0
  106. package/dist/src/template-sdk.js +4 -0
  107. package/dist/src/worker.js +17 -0
  108. package/package.json +6 -4
  109. package/public/assets/homepage-app.js +54 -0
  110. package/public/assets/homepage-client-app.js +80 -0
  111. package/public/assets/page-runtime-client-app.js +94 -0
  112. package/src/assets/SELLING_AWARENESS_STAGES.md +579 -0
  113. package/src/assets/SELLING_WITH_HOOKS.md +377 -0
  114. package/src/assets/SELLING_WITH_VSLS.md +606 -0
  115. package/src/assets/favicon.ico +0 -0
  116. package/src/assets/logo-vidfarm.png +0 -0
@@ -0,0 +1,180 @@
1
+ export function buildHyperframeCompositionHtml(input) {
2
+ const duration = positiveNumber(input.duration, inferDuration(input.layers));
3
+ const width = positiveInteger(input.width, 720);
4
+ const height = positiveInteger(input.height, 1280);
5
+ const background = input.backgroundColor || "#050604";
6
+ const fontImport = input.fontImportCss ?? "@import url(\"https://fonts.googleapis.com/css2?family=Abel&family=Montserrat:wght@600&family=Source+Code+Pro:wght@700&family=TikTok+Sans:wght@400;600;700;800;900&display=swap\");";
7
+ const layers = input.layers.map(renderLayer).join("\n ");
8
+ return `<!doctype html>
9
+ <html>
10
+ <head>
11
+ <meta charset="UTF-8" />
12
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
13
+ <style>
14
+ ${fontImport}
15
+ html, body { width:100%; height:100%; margin:0; overflow:hidden; background:${background}; }
16
+ [data-composition-id] { position:relative; width:100vw; height:100vh; overflow:hidden; background:${background}; }
17
+ audio { display:none; }
18
+ ${input.css ?? ""}
19
+ </style>
20
+ </head>
21
+ <body>
22
+ <div data-composition-id="${escapeAttr(input.compositionId)}" data-source-folder="${escapeAttr(input.sourceFolder || "")}" data-width="${width}" data-height="${height}" data-duration="${num(duration)}">
23
+ ${layers}
24
+ </div>
25
+ </body>
26
+ </html>
27
+ `;
28
+ }
29
+ export function inferDuration(layers) {
30
+ return layers.reduce((max, layer) => Math.max(max, positiveNumber(layer.start, 0) + positiveNumber(layer.duration, 0)), 0);
31
+ }
32
+ export function assertHyperframeTimeline(layers) {
33
+ const timedLayers = layers.filter((layer) => positiveNumber(layer.duration, 0) > 0);
34
+ for (const layer of timedLayers) {
35
+ if (!layer.id.trim())
36
+ throw new Error("HyperFrame layer id is required.");
37
+ if (positiveNumber(layer.start, -1) < 0)
38
+ throw new Error(`HyperFrame layer ${layer.id} has a negative start.`);
39
+ if (positiveNumber(layer.duration, 0) <= 0)
40
+ throw new Error(`HyperFrame layer ${layer.id} must have a positive duration.`);
41
+ }
42
+ }
43
+ function renderLayer(layer) {
44
+ const attrs = timedAttrs(layer);
45
+ const style = layerStyle(layer);
46
+ if (layer.kind === "video") {
47
+ return `<video ${attrs} src="${escapeAttr(layer.src || "")}" ${layer.muted === false ? "" : "muted"} playsinline preload="auto" style="${escapeAttr(style)}"></video>`;
48
+ }
49
+ if (layer.kind === "audio") {
50
+ return `<audio ${attrs} src="${escapeAttr(layer.src || "")}" data-timeline-role="music" data-volume="${num(positiveNumber(layer.volume, 1))}" preload="metadata"></audio>`;
51
+ }
52
+ if (layer.kind === "image") {
53
+ return `<img ${attrs} src="${escapeAttr(layer.src || "")}" alt="" style="${escapeAttr(style)}" />`;
54
+ }
55
+ if (layer.kind === "html") {
56
+ return `<div ${attrs} style="${escapeAttr(style)}">${layer.html || ""}</div>`;
57
+ }
58
+ const text = layer.text ?? layer.label ?? "";
59
+ const inlineStyle = textInlineCss(layer.textBackgroundStyle || "plain", layer.color || "#ffffff", layer.background || "#000000", layer.fontFamily || "TikTok Sans", positiveInteger(layer.fontWeight, 700));
60
+ const linesStyle = [
61
+ "display:block",
62
+ "max-width:100%",
63
+ "text-align:inherit",
64
+ `line-height:${positiveNumber(layer.lineHeight, 1.18)}`,
65
+ "white-space:pre-wrap",
66
+ "overflow:visible"
67
+ ].join(";");
68
+ return `<div ${attrs} style="${escapeAttr(style)}"><span data-vf-text-lines="true" style="${escapeAttr(linesStyle)}"><span data-vf-text-inline="true" style="${escapeAttr(inlineStyle)}">${escapeHtml(text)}</span></span></div>`;
69
+ }
70
+ function timedAttrs(layer) {
71
+ const attrs = [
72
+ `id="${escapeAttr(layer.id)}"`,
73
+ `data-hf-id="${escapeAttr(layer.id)}"`,
74
+ `data-layer-mode="${escapeAttr(layer.mode || "publish")}"`,
75
+ `data-layer-kind="${escapeAttr(layer.kind)}"`,
76
+ `data-viral-note="${escapeAttr(layer.viralAlignment || "")}"`,
77
+ `data-start="${num(positiveNumber(layer.start, 0))}"`,
78
+ `data-duration="${num(positiveNumber(layer.duration, 0))}"`,
79
+ `data-track-index="${positiveInteger(layer.track, 0)}"`,
80
+ `data-label="${escapeAttr(layer.label || layer.id)}"`
81
+ ];
82
+ if (layer.mediaStart !== undefined || layer.playbackStart !== undefined) {
83
+ const mediaStart = positiveNumber(layer.playbackStart ?? layer.mediaStart, 0);
84
+ attrs.push(`data-media-start="${num(mediaStart)}"`, `data-playback-start="${num(mediaStart)}"`);
85
+ }
86
+ if (["caption", "text", "shape", "html"].includes(layer.kind)) {
87
+ attrs.push(`data-text-background-style="${escapeAttr(layer.textBackgroundStyle || "plain")}"`, `data-text-background-color="${escapeAttr(layer.background || "#000000")}"`, `data-font-family="${escapeAttr(layer.fontFamily || "TikTok Sans")}"`);
88
+ }
89
+ return attrs.join(" ");
90
+ }
91
+ function layerStyle(layer) {
92
+ const styles = [
93
+ "position:absolute",
94
+ `left:${positiveNumber(layer.x, 0)}%`,
95
+ `top:${positiveNumber(layer.y, 0)}%`,
96
+ `width:${positiveNumber(layer.width, 100)}%`,
97
+ `height:${positiveNumber(layer.height, 100)}%`,
98
+ `z-index:${positiveInteger(layer.z, 0)}`,
99
+ `opacity:${positiveNumber(layer.opacity, 1)}`,
100
+ `border-radius:${positiveInteger(layer.radius, 0)}px`,
101
+ "overflow:hidden"
102
+ ];
103
+ if (layer.kind === "video" || layer.kind === "image") {
104
+ styles.push(`object-fit:${layer.fit || "cover"}`);
105
+ }
106
+ if (["caption", "text", "shape", "html"].includes(layer.kind)) {
107
+ const fontFamily = layer.fontFamily || "TikTok Sans";
108
+ styles.push("display:flex", "align-items:center", "justify-content:center", "padding:3px", `font-family:${fontCssFamily(fontFamily)}, 'TikTok Sans', Montserrat, Abel, sans-serif`, `font-weight:${positiveInteger(layer.fontWeight, 700)}`, `line-height:${positiveNumber(layer.lineHeight, 1.18)}`, "text-align:center", "text-transform:none", `font-size:${positiveInteger(layer.fontSize, 32)}px`, `color:${layer.color || "#ffffff"}`, layer.kind === "shape" && layer.textBackgroundStyle === "panel"
109
+ ? `background:${layer.background || "transparent"}`
110
+ : "background:transparent");
111
+ }
112
+ for (const [property, value] of Object.entries(layer.style || {})) {
113
+ styles.push(`${property}:${value}`);
114
+ }
115
+ return styles.join(";");
116
+ }
117
+ function textInlineCss(style, color, background, fontFamily, fontWeight) {
118
+ const styles = [
119
+ "display:inline",
120
+ "box-decoration-break:clone",
121
+ "-webkit-box-decoration-break:clone",
122
+ "line-height:inherit"
123
+ ];
124
+ if (style === "plain" || style === "panel") {
125
+ styles.push("padding:0", "border-radius:0", "background:transparent", "text-shadow:none", "-webkit-text-stroke:0 transparent");
126
+ }
127
+ else if (style === "outline") {
128
+ styles.push("padding:0", "border-radius:0", "background:transparent", `text-shadow:2px 0 ${background},-2px 0 ${background},0 2px ${background},0 -2px ${background},1.5px 1.5px ${background},-1.5px 1.5px ${background},1.5px -1.5px ${background},-1.5px -1.5px ${background}`, `-webkit-text-stroke:1.5px ${background}`, "paint-order:stroke fill");
129
+ }
130
+ else if (style === "highlight-solid") {
131
+ styles.push("padding:0.07em 0.46em 0.09em", "border-radius:0.32em", `background:${background}`, "text-shadow:none", "-webkit-text-stroke:0 transparent");
132
+ }
133
+ else if (style === "highlight-translucent") {
134
+ styles.push("padding:0.07em 0.46em 0.09em", "border-radius:0.32em", `background:${rgbaFromColor(background, 0.34)}`, "text-shadow:none", "-webkit-text-stroke:0 transparent");
135
+ }
136
+ styles.push(`font-family:${fontCssFamily(fontFamily)}, 'TikTok Sans', sans-serif`);
137
+ styles.push(`font-weight:${fontWeight}`);
138
+ styles.push(`color:${color}`);
139
+ return styles.join(";");
140
+ }
141
+ function fontCssFamily(font) {
142
+ return font === "Georgia" ? "Georgia" : `'${font.replaceAll("'", "")}'`;
143
+ }
144
+ function rgbaFromColor(value, alpha) {
145
+ const clean = String(value || "").trim();
146
+ const hex = clean.startsWith("#") ? clean.slice(1) : "";
147
+ if (hex.length === 3 || hex.length === 6) {
148
+ const full = hex.length === 3 ? hex.split("").map((part) => part + part).join("") : hex;
149
+ const numeric = Number.parseInt(full, 16);
150
+ if (Number.isFinite(numeric)) {
151
+ const red = (numeric >> 16) & 255;
152
+ const green = (numeric >> 8) & 255;
153
+ const blue = numeric & 255;
154
+ return `rgba(${red}, ${green}, ${blue}, ${alpha})`;
155
+ }
156
+ }
157
+ return clean.startsWith("rgba(") || clean.startsWith("rgb(") ? clean : `rgba(0, 0, 0, ${alpha})`;
158
+ }
159
+ function positiveNumber(value, fallback) {
160
+ const next = Number(value);
161
+ return Number.isFinite(next) && next >= 0 ? next : fallback;
162
+ }
163
+ function positiveInteger(value, fallback) {
164
+ const next = Math.round(Number(value));
165
+ return Number.isFinite(next) && next >= 0 ? next : fallback;
166
+ }
167
+ function num(value) {
168
+ return Number(Number(value || 0).toFixed(3)).toString();
169
+ }
170
+ function escapeHtml(value) {
171
+ return String(value ?? "")
172
+ .replaceAll("&", "&amp;")
173
+ .replaceAll("<", "&lt;")
174
+ .replaceAll(">", "&gt;")
175
+ .replaceAll('"', "&quot;");
176
+ }
177
+ function escapeAttr(value) {
178
+ return escapeHtml(String(value ?? ""));
179
+ }
180
+ //# sourceMappingURL=composition.js.map
@@ -0,0 +1,16 @@
1
+ import { startRuntime } from "./runtime.js";
2
+ void (async () => {
3
+ const runtime = await startRuntime();
4
+ for (const signal of ["SIGINT", "SIGTERM"]) {
5
+ process.on(signal, () => {
6
+ void (async () => {
7
+ await runtime.shutdown();
8
+ process.exit(0);
9
+ })();
10
+ });
11
+ }
12
+ })().catch((error) => {
13
+ console.error(error instanceof Error ? error.stack ?? error.message : String(error));
14
+ process.exit(1);
15
+ });
16
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,30 @@
1
+ import dotenv from "dotenv";
2
+ import * as Sentry from "@sentry/hono/node";
3
+ dotenv.config();
4
+ function readBoolean(name, defaultValue) {
5
+ const raw = process.env[name]?.trim().toLowerCase();
6
+ if (!raw)
7
+ return defaultValue;
8
+ return raw === "1" || raw === "true" || raw === "yes";
9
+ }
10
+ function readSampleRate(name, defaultValue) {
11
+ const raw = process.env[name]?.trim();
12
+ if (!raw)
13
+ return defaultValue;
14
+ const parsed = Number(raw);
15
+ return Number.isFinite(parsed) && parsed >= 0 && parsed <= 1 ? parsed : defaultValue;
16
+ }
17
+ const dsn = process.env.SENTRY_DSN?.trim();
18
+ if (dsn) {
19
+ const environment = process.env.SENTRY_ENVIRONMENT?.trim() || process.env.NODE_ENV || "development";
20
+ const defaultTracesSampleRate = environment === "production" ? 0.1 : 1.0;
21
+ Sentry.init({
22
+ dsn,
23
+ environment,
24
+ release: process.env.SENTRY_RELEASE?.trim() || undefined,
25
+ tracesSampleRate: readSampleRate("SENTRY_TRACES_SAMPLE_RATE", defaultTracesSampleRate),
26
+ enableLogs: readBoolean("SENTRY_ENABLE_LOGS", true),
27
+ sendDefaultPii: readBoolean("SENTRY_SEND_DEFAULT_PII", false)
28
+ });
29
+ }
30
+ //# sourceMappingURL=instrument.js.map
@@ -0,0 +1,45 @@
1
+ import { createCipheriv, createDecipheriv, createHash, randomBytes, scryptSync, timingSafeEqual } from "node:crypto";
2
+ function deriveKey(secret) {
3
+ return scryptSync(secret, "vidfarm", 32);
4
+ }
5
+ export function hashSecret(value) {
6
+ return createHash("sha256").update(value).digest("hex");
7
+ }
8
+ export function safeEqualHash(raw, hashed) {
9
+ const left = Buffer.from(hashSecret(raw), "hex");
10
+ const right = Buffer.from(hashed, "hex");
11
+ return left.length === right.length && timingSafeEqual(left, right);
12
+ }
13
+ export function encryptString(value, secret) {
14
+ const iv = randomBytes(12);
15
+ const key = deriveKey(secret);
16
+ const cipher = createCipheriv("aes-256-gcm", key, iv);
17
+ const encrypted = Buffer.concat([cipher.update(value, "utf8"), cipher.final()]);
18
+ const tag = cipher.getAuthTag();
19
+ return Buffer.concat([iv, tag, encrypted]).toString("base64");
20
+ }
21
+ export function decryptString(value, secret) {
22
+ const raw = Buffer.from(value, "base64");
23
+ const iv = raw.subarray(0, 12);
24
+ const tag = raw.subarray(12, 28);
25
+ const encrypted = raw.subarray(28);
26
+ const key = deriveKey(secret);
27
+ const decipher = createDecipheriv("aes-256-gcm", key, iv);
28
+ decipher.setAuthTag(tag);
29
+ return Buffer.concat([decipher.update(encrypted), decipher.final()]).toString("utf8");
30
+ }
31
+ export function hashPassword(password) {
32
+ const salt = randomBytes(16).toString("hex");
33
+ const digest = scryptSync(password, salt, 32).toString("hex");
34
+ return `${salt}:${digest}`;
35
+ }
36
+ export function verifyPassword(password, storedHash) {
37
+ const [salt, digest] = storedHash.split(":");
38
+ if (!salt || !digest) {
39
+ return false;
40
+ }
41
+ const left = Buffer.from(scryptSync(password, salt, 32).toString("hex"), "hex");
42
+ const right = Buffer.from(digest, "hex");
43
+ return left.length === right.length && timingSafeEqual(left, right);
44
+ }
45
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1,54 @@
1
+ import { config } from "../config.js";
2
+ const SECRET_KEY_PATTERN = /(secret|token|password|api[_-]?key|authorization|credential)/i;
3
+ export function devLog(event, fields = {}, level = "info") {
4
+ if (!config.debugLogs) {
5
+ return;
6
+ }
7
+ const entry = {
8
+ level,
9
+ event,
10
+ time: new Date().toISOString(),
11
+ deployment_target: config.VIDFARM_DEPLOYMENT_TARGET ?? null,
12
+ runtime_backend: config.VIDFARM_RUNTIME_BACKEND,
13
+ ...sanitizeLogFields(fields)
14
+ };
15
+ const line = JSON.stringify(entry);
16
+ if (level === "error") {
17
+ console.error(line);
18
+ }
19
+ else if (level === "warn") {
20
+ console.warn(line);
21
+ }
22
+ else {
23
+ console.log(line);
24
+ }
25
+ }
26
+ export function devErrorFields(error) {
27
+ if (error instanceof Error) {
28
+ return {
29
+ error_name: error.name,
30
+ error_message: error.message,
31
+ error_stack: error.stack?.split("\n").slice(0, 8).join("\n") ?? null
32
+ };
33
+ }
34
+ return {
35
+ error_message: String(error)
36
+ };
37
+ }
38
+ function sanitizeLogValue(value) {
39
+ if (Array.isArray(value)) {
40
+ return value.map(sanitizeLogValue);
41
+ }
42
+ if (!value || typeof value !== "object") {
43
+ return value;
44
+ }
45
+ const output = {};
46
+ for (const [key, child] of Object.entries(value)) {
47
+ output[key] = SECRET_KEY_PATTERN.test(key) ? "[redacted]" : sanitizeLogValue(child);
48
+ }
49
+ return output;
50
+ }
51
+ function sanitizeLogFields(fields) {
52
+ return sanitizeLogValue(fields);
53
+ }
54
+ //# sourceMappingURL=dev-log.js.map
@@ -0,0 +1,11 @@
1
+ export function displayNameFromEmail(email) {
2
+ const normalized = email.trim().toLowerCase();
3
+ const localPart = normalized.split("@", 1)[0] || normalized;
4
+ const words = localPart
5
+ .split(/[^a-z0-9]+/i)
6
+ .map((word) => word.trim())
7
+ .filter(Boolean)
8
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
9
+ return words.join(" ") || normalized;
10
+ }
11
+ //# sourceMappingURL=display-name.js.map
@@ -0,0 +1,24 @@
1
+ import { randomBytes, randomUUID } from "node:crypto";
2
+ export function createId(prefix) {
3
+ return `${prefix}_${randomUUID().replace(/-/g, "")}`;
4
+ }
5
+ // UUIDv7: time-ordered 128-bit id. First 48 bits are Unix millis, next 4 bits
6
+ // are the version (7), next 12 bits are random, next 2 bits are the variant
7
+ // (0b10), and the rest is random. Chronologically sortable — good for DDB
8
+ // keys and for humans skimming a list of forks.
9
+ export function uuidv7() {
10
+ const timestampMs = BigInt(Date.now());
11
+ const rand = randomBytes(10);
12
+ const bytes = Buffer.alloc(16);
13
+ bytes.writeUIntBE(Number((timestampMs >> 16n) & 0xffffffffn), 0, 4);
14
+ bytes.writeUIntBE(Number(timestampMs & 0xffffn), 4, 2);
15
+ rand.copy(bytes, 6);
16
+ bytes[6] = (bytes[6] & 0x0f) | 0x70; // version 7
17
+ bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant RFC 4122
18
+ const hex = bytes.toString("hex");
19
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
20
+ }
21
+ export function createIdV7(prefix) {
22
+ return `${prefix}_${uuidv7().replace(/-/g, "")}`;
23
+ }
24
+ //# sourceMappingURL=ids.js.map
@@ -0,0 +1,19 @@
1
+ import sharp from "sharp";
2
+ export async function normalizeToPortraitFrame(input, target = { width: 1080, height: 1920 }) {
3
+ const buffer = Buffer.isBuffer(input) ? input : Buffer.from(input);
4
+ const output = await sharp(buffer, { density: 144 })
5
+ .rotate()
6
+ .resize(target.width, target.height, {
7
+ fit: "cover",
8
+ position: sharp.strategy.attention
9
+ })
10
+ .png()
11
+ .toBuffer();
12
+ return {
13
+ bytes: output,
14
+ contentType: "image/png",
15
+ width: target.width,
16
+ height: target.height
17
+ };
18
+ }
19
+ //# sourceMappingURL=images.js.map
@@ -0,0 +1,15 @@
1
+ export function parseJson(value, fallback) {
2
+ if (!value) {
3
+ return fallback;
4
+ }
5
+ try {
6
+ return JSON.parse(value);
7
+ }
8
+ catch {
9
+ return fallback;
10
+ }
11
+ }
12
+ export function stringifyJson(value) {
13
+ return JSON.stringify(value ?? null);
14
+ }
15
+ //# sourceMappingURL=json.js.map
@@ -0,0 +1,47 @@
1
+ import { existsSync, readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ // Server asset files (the hyperframes editor bundle, public/assets JS bundles,
5
+ // SKILL.*.md, src/assets binaries) are laid out relative to the PACKAGE root:
6
+ // the repo checkout in dev, /app–/var/task in Docker/Lambda, or
7
+ // node_modules/@mevdragon/vidfarm-devcli when `vidfarm serve` runs from the
8
+ // published npm package. cwd-relative reads only cover the first two, so every
9
+ // root-file read should try cwd first (preserves the existing dev/Docker
10
+ // behavior) and then fall back to this package root.
11
+ function findPackageRoot() {
12
+ let current = path.dirname(fileURLToPath(import.meta.url));
13
+ for (let depth = 0; depth < 6; depth += 1) {
14
+ const manifest = path.join(current, "package.json");
15
+ if (existsSync(manifest)) {
16
+ try {
17
+ const parsed = JSON.parse(readFileSync(manifest, "utf8"));
18
+ if (parsed.name === "@mevdragon/vidfarm-devcli") {
19
+ return current;
20
+ }
21
+ }
22
+ catch {
23
+ // Unreadable manifest — keep walking up.
24
+ }
25
+ }
26
+ const parent = path.dirname(current);
27
+ if (parent === current)
28
+ break;
29
+ current = parent;
30
+ }
31
+ return null;
32
+ }
33
+ export const packageRoot = findPackageRoot();
34
+ // All plausible absolute paths for a package-root-relative file, ordered
35
+ // cwd-first so a dev checkout (or Docker task root) always wins over the
36
+ // installed package copy.
37
+ export function resolveRootFileCandidates(relativePath) {
38
+ const candidates = [path.resolve(relativePath)];
39
+ if (packageRoot) {
40
+ const packaged = path.resolve(packageRoot, relativePath);
41
+ if (!candidates.includes(packaged)) {
42
+ candidates.push(packaged);
43
+ }
44
+ }
45
+ return candidates;
46
+ }
47
+ //# sourceMappingURL=package-root.js.map
@@ -0,0 +1,28 @@
1
+ import path from "node:path";
2
+ export const TEMPLATE_FOLDER_PREFIX = "vidfarm_template_";
3
+ export const LEGACY_TEMPLATE_FOLDER_PREFIX = "template_";
4
+ export function assertTemplateFolderNameHasPrefix(folderName) {
5
+ if (!folderName.startsWith(TEMPLATE_FOLDER_PREFIX) && !folderName.startsWith(LEGACY_TEMPLATE_FOLDER_PREFIX)) {
6
+ throw new Error(`Template folder name must start with ${TEMPLATE_FOLDER_PREFIX} or ${LEGACY_TEMPLATE_FOLDER_PREFIX}. Received: ${folderName}`);
7
+ }
8
+ }
9
+ export function deriveTemplateRootDirFromModulePath(templateModulePath) {
10
+ const normalizedModulePath = templateModulePath.replace(/\\/g, "/");
11
+ const templateSourceDir = path.posix.dirname(normalizedModulePath);
12
+ const templateRootDir = path.posix.dirname(templateSourceDir);
13
+ const sourceDirName = path.posix.basename(templateSourceDir);
14
+ if (sourceDirName !== "src") {
15
+ throw new Error("template_module_path must point at a TypeScript entrypoint inside a src/ folder, such as src/template.ts or templates/vidfarm_template_example/src/template.ts.");
16
+ }
17
+ if (templateRootDir === "." || templateRootDir === "") {
18
+ return "";
19
+ }
20
+ const folderName = path.posix.basename(templateRootDir);
21
+ assertTemplateFolderNameHasPrefix(folderName);
22
+ return templateRootDir;
23
+ }
24
+ export function defaultSkillPathForTemplateModule(templateModulePath) {
25
+ const templateRootDir = deriveTemplateRootDirFromModulePath(templateModulePath);
26
+ return templateRootDir ? path.posix.join(templateRootDir, "SKILL.md") : "SKILL.md";
27
+ }
28
+ //# sourceMappingURL=template-paths.js.map
@@ -0,0 +1,7 @@
1
+ export function nowIso() {
2
+ return new Date().toISOString();
3
+ }
4
+ export function addSeconds(date, seconds) {
5
+ return new Date(date.getTime() + seconds * 1000).toISOString();
6
+ }
7
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1,85 @@
1
+ const TRACKING_PARAM_PREFIXES = ["utm_", "mc_", "ic_"];
2
+ const TRACKING_PARAMS = new Set([
3
+ "si",
4
+ "share_link_id",
5
+ "share_app_id",
6
+ "share_iid",
7
+ "shareid",
8
+ "sender_device",
9
+ "sender_web_id",
10
+ "source",
11
+ "timestamp",
12
+ "user_id",
13
+ "sec_uid",
14
+ "t",
15
+ "feature",
16
+ "app",
17
+ "referer",
18
+ "referrer",
19
+ "ref",
20
+ "ref_src",
21
+ "ref_url",
22
+ "fbclid",
23
+ "gclid",
24
+ "igshid",
25
+ "igsh",
26
+ "mibextid",
27
+ "twclid",
28
+ "twsrc",
29
+ "trk",
30
+ "hl",
31
+ "context",
32
+ "checksum",
33
+ "_r",
34
+ "_t",
35
+ "_d",
36
+ "_i",
37
+ "_hsenc",
38
+ "_hsmi"
39
+ ]);
40
+ function shouldStrip(param) {
41
+ const lower = param.toLowerCase();
42
+ if (TRACKING_PARAMS.has(lower))
43
+ return true;
44
+ return TRACKING_PARAM_PREFIXES.some((prefix) => lower.startsWith(prefix));
45
+ }
46
+ export function stripTrackingParams(input) {
47
+ const trimmed = input.trim();
48
+ if (!trimmed)
49
+ return trimmed;
50
+ let url;
51
+ try {
52
+ url = new URL(trimmed);
53
+ }
54
+ catch {
55
+ return trimmed;
56
+ }
57
+ const kept = [];
58
+ url.searchParams.forEach((value, key) => {
59
+ if (!shouldStrip(key))
60
+ kept.push([key, value]);
61
+ });
62
+ const params = new URLSearchParams(kept);
63
+ const search = params.toString();
64
+ url.search = search ? `?${search}` : "";
65
+ url.hash = "";
66
+ return url.toString();
67
+ }
68
+ export function detectSourceHost(rawUrl) {
69
+ try {
70
+ const host = new URL(rawUrl).hostname.toLowerCase().replace(/^www\./, "");
71
+ if (host.endsWith("tiktok.com"))
72
+ return "tiktok";
73
+ if (host === "instagram.com" || host.endsWith(".instagram.com"))
74
+ return "instagram";
75
+ if (host === "youtube.com" || host.endsWith(".youtube.com") || host === "youtu.be")
76
+ return "youtube";
77
+ if (host === "twitter.com" || host === "x.com" || host.endsWith(".twitter.com") || host.endsWith(".x.com"))
78
+ return "twitter";
79
+ return "other";
80
+ }
81
+ catch {
82
+ return "other";
83
+ }
84
+ }
85
+ //# sourceMappingURL=url-clean.js.map
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=page-runtime.js.map