@nodaro/shared 3.10.0 → 3.12.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 (72) hide show
  1. package/dist/index.cjs +2242 -86
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +1779 -32
  4. package/dist/index.d.ts +1779 -32
  5. package/dist/index.js +2041 -87
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__tests__/caption-styles.test.ts +207 -0
  9. package/src/__tests__/edl-multicam.test.ts +304 -0
  10. package/src/__tests__/edl.test.ts +822 -0
  11. package/src/__tests__/fan-out-rows.test.ts +208 -0
  12. package/src/__tests__/instagram-scrape.test.ts +66 -0
  13. package/src/__tests__/llm-models.test.ts +48 -11
  14. package/src/__tests__/meta-ads-scrape.test.ts +284 -0
  15. package/src/__tests__/node-runtime-keys.test.ts +15 -0
  16. package/src/__tests__/parameter-node-value.test.ts +13 -1
  17. package/src/__tests__/presentation-utils.test.ts +67 -0
  18. package/src/__tests__/producer-types.test.ts +19 -0
  19. package/src/__tests__/schedule-rules.test.ts +265 -0
  20. package/src/__tests__/speaker-layouts.test.ts +203 -0
  21. package/src/__tests__/transcribe-capabilities.test.ts +104 -0
  22. package/src/__tests__/transcribe-preflight.test.ts +60 -0
  23. package/src/__tests__/trigger-feeds.test.ts +39 -0
  24. package/src/__tests__/video-analysis.test.ts +15 -0
  25. package/src/__tests__/video-duration-auto.test.ts +65 -0
  26. package/src/__tests__/video-duration.test.ts +56 -0
  27. package/src/__tests__/video-frame-fit.test.ts +189 -0
  28. package/src/__tests__/video-link.test.ts +137 -0
  29. package/src/__tests__/workflow-export-strip.test.ts +59 -1
  30. package/src/caption-styles.ts +240 -0
  31. package/src/catalog-projection.ts +3 -0
  32. package/src/character-motion-metadata.ts +19 -0
  33. package/src/credit-identifiers.ts +31 -0
  34. package/src/edit-plan-contract.ts +96 -0
  35. package/src/edl-multicam.ts +185 -0
  36. package/src/edl.ts +747 -0
  37. package/src/entity-image-handle.ts +24 -1
  38. package/src/fan-out-rows.ts +213 -0
  39. package/src/i18n/character-motion.ar.ts +126 -75
  40. package/src/i18n/character-motion.de.ts +126 -75
  41. package/src/i18n/character-motion.es.ts +126 -75
  42. package/src/i18n/character-motion.fr.ts +126 -75
  43. package/src/i18n/character-motion.he.ts +126 -75
  44. package/src/i18n/character-motion.hi.ts +126 -75
  45. package/src/i18n/character-motion.ja.ts +126 -75
  46. package/src/i18n/character-motion.ko.ts +126 -75
  47. package/src/i18n/character-motion.pt-BR.ts +126 -75
  48. package/src/i18n/character-motion.ru.ts +126 -75
  49. package/src/i18n/character-motion.zh-CN.ts +126 -75
  50. package/src/index.ts +211 -3
  51. package/src/instagram-scrape.ts +204 -0
  52. package/src/llm-models.ts +80 -3
  53. package/src/meta-ads-scrape.ts +463 -0
  54. package/src/model-catalog.ts +48 -5
  55. package/src/model-constants.ts +148 -5
  56. package/src/node-mappable-fields.ts +2 -0
  57. package/src/node-runtime-keys.ts +28 -0
  58. package/src/parameter-node-value.ts +31 -5
  59. package/src/presentation-utils.ts +49 -0
  60. package/src/producer-types.ts +20 -0
  61. package/src/schedule-rules.ts +484 -0
  62. package/src/speaker-layouts.ts +220 -0
  63. package/src/transcribe-preflight.ts +101 -0
  64. package/src/trigger-feeds.ts +59 -0
  65. package/src/trigger-node-types.ts +20 -0
  66. package/src/video-analysis.ts +15 -0
  67. package/src/video-duration-auto.ts +18 -0
  68. package/src/video-duration.ts +32 -0
  69. package/src/video-frame-fit.ts +228 -0
  70. package/src/video-link.ts +167 -0
  71. package/src/video-output-canvas.ts +119 -0
  72. package/src/workflow-export.ts +37 -1
package/dist/index.cjs CHANGED
@@ -45,6 +45,13 @@ function isFlux2Model(m) {
45
45
  return m === "flux-2-klein" || m === "flux-2-pro" || m === "flux-2-max";
46
46
  }
47
47
 
48
+ // src/video-duration-auto.ts
49
+ var VIDEO_DURATION_AUTO = -1;
50
+ function isAutoVideoDuration(duration) {
51
+ const n = typeof duration === "string" ? parseInt(duration, 10) : duration;
52
+ return n === VIDEO_DURATION_AUTO;
53
+ }
54
+
48
55
  // src/model-catalog.ts
49
56
  var MODEL_RECOMMENDATIONS = [
50
57
  // image
@@ -64,7 +71,7 @@ var MODEL_RECOMMENDATIONS = [
64
71
  { intent: "music / song generation", modelIds: ["suno-v6", "suno-v6_wild", "suno-v6_mini", "suno-v5_5"], note: "V6 is the default flagship; V6 Wild for bolder, less predictable results; V6 Mini when speed matters; v5.5 / v5 / v4 keep their own character. Same price." },
65
72
  { intent: "voice over / narration", modelIds: ["elevenlabs-v3", "elevenlabs-turbo"], note: "v3 supports [audio tags] for emotion; Turbo is cheaper for plain narration." },
66
73
  { intent: "lip-sync a portrait to audio", modelIds: ["kling-avatar-pro", "kling-avatar", "infinitalk"], note: "Pro for best mouth shape; InfiniTalk for resolution control." },
67
- { intent: "transcription / captions", modelIds: ["elevenlabs-stt"], note: "Word-level timestamps available." },
74
+ { intent: "transcription / captions", modelIds: ["elevenlabs-stt", "incredibly-fast-whisper", "whisper"], note: "Captions need WORD timestamps: ElevenLabs STT (always) or Incredibly Fast Whisper. Plain Whisper returns phrase segments only." },
68
75
  { intent: "motion transfer (drive a subject by another video)", modelIds: ["motion-transfer", "kling-3.0-motion"], note: "Kling 2.6 base is cheap; Kling 3.0 is premium." }
69
76
  ];
70
77
  var NANO_BANANA_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "4:5", "5:4", "21:9"];
@@ -1359,6 +1366,7 @@ var VIDEO_MODELS = {
1359
1366
  features: ["end-frame", "audio", "reference-image", "video-reference"],
1360
1367
  aspectRatios: VIDEO_RATIOS_SEEDANCE_2,
1361
1368
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1369
+ autoDuration: true,
1362
1370
  resolutions: ["480p", "720p", "1080p", "4k"],
1363
1371
  pricing: [
1364
1372
  { identifier: "seedance-2", credits: 380, note: "default \u2014 see :NsR variants for exact" },
@@ -1384,6 +1392,7 @@ var VIDEO_MODELS = {
1384
1392
  features: ["end-frame", "audio", "reference-image", "video-reference"],
1385
1393
  aspectRatios: VIDEO_RATIOS_SEEDANCE_2,
1386
1394
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1395
+ autoDuration: true,
1387
1396
  resolutions: ["480p", "720p"],
1388
1397
  pricing: [
1389
1398
  { identifier: "seedance-2-fast", credits: 310, note: "default \u2014 see :NsR variants" },
@@ -1405,6 +1414,7 @@ var VIDEO_MODELS = {
1405
1414
  features: ["end-frame", "audio", "reference-image", "video-reference"],
1406
1415
  aspectRatios: VIDEO_RATIOS_SEEDANCE_2,
1407
1416
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1417
+ autoDuration: true,
1408
1418
  resolutions: ["480p", "720p"],
1409
1419
  pricing: [
1410
1420
  { identifier: "seedance-2-mini", credits: 190, note: "default \u2014 see :NsR variants" },
@@ -1432,6 +1442,7 @@ var VIDEO_MODELS = {
1432
1442
  features: ["end-frame", "audio", "reference-image", "video-reference"],
1433
1443
  aspectRatios: VIDEO_RATIOS_SEEDANCE_2,
1434
1444
  durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
1445
+ autoDuration: true,
1435
1446
  resolutions: ["480p", "720p", "1080p"],
1436
1447
  pricing: [
1437
1448
  { identifier: "seedance-2-5", credits: 1260, note: "default 8s 720p \u2014 see :Ns:res variants for exact" },
@@ -2311,10 +2322,34 @@ var AUDIO_MODELS = {
2311
2322
  family: "ElevenLabs",
2312
2323
  label: "ElevenLabs STT",
2313
2324
  series: "ElevenLabs",
2314
- description: "Speech-to-text \u2014 transcribe audio with timestamps.",
2315
- useCases: ["transcription", "stt"],
2325
+ description: "Speech-to-text with WORD-level timestamps (always on), speaker diarization and audio-event tags. The engine to use when the transcript feeds captions.",
2326
+ useCases: ["transcription", "stt", "captions"],
2327
+ features: ["word-timestamps", "diarization", "audio-events"],
2316
2328
  pricing: [{ identifier: "elevenlabs-stt", credits: 22 }]
2317
2329
  },
2330
+ "incredibly-fast-whisper": {
2331
+ id: "incredibly-fast-whisper",
2332
+ kind: "audio",
2333
+ modes: ["stt"],
2334
+ family: "OpenAI",
2335
+ label: "Incredibly Fast Whisper",
2336
+ series: "Whisper",
2337
+ description: "Fast Whisper speech-to-text. Returns WORD-level timestamps when asked, so its transcript can feed captions.",
2338
+ useCases: ["transcription", "stt", "captions"],
2339
+ features: ["word-timestamps"],
2340
+ pricing: [{ identifier: "incredibly-fast-whisper", credits: 40 }]
2341
+ },
2342
+ "whisper": {
2343
+ id: "whisper",
2344
+ kind: "audio",
2345
+ modes: ["stt"],
2346
+ family: "OpenAI",
2347
+ label: "Whisper",
2348
+ series: "Whisper",
2349
+ description: "Whisper speech-to-text \u2014 PHRASE-level segments only, NO word timestamps. Fine for a transcript or a static subtitle; not for word-timed (kinetic) captions.",
2350
+ useCases: ["transcription", "stt"],
2351
+ pricing: [{ identifier: "whisper", credits: 40 }]
2352
+ },
2318
2353
  "elevenlabs-isolation": {
2319
2354
  id: "elevenlabs-isolation",
2320
2355
  kind: "audio",
@@ -2536,7 +2571,8 @@ function validateModelInput(modelId, input) {
2536
2571
  allowed: null
2537
2572
  };
2538
2573
  }
2539
- if (!m.durations.includes(input.duration)) {
2574
+ const isAuto = m.autoDuration === true && isAutoVideoDuration(input.duration);
2575
+ if (!isAuto && !m.durations.includes(input.duration)) {
2540
2576
  return {
2541
2577
  field: "duration",
2542
2578
  message: `Model "${modelId}" does not support duration ${input.duration}s. Supported: ${m.durations.join(", ")}s.`,
@@ -2596,7 +2632,7 @@ function normalizeModelInput(modelId, input) {
2596
2632
  defaultResolutionFor(modelId)
2597
2633
  );
2598
2634
  out.quality = snap("quality", input.quality, m.qualities);
2599
- out.duration = snap("duration", input.duration, m.durations);
2635
+ out.duration = m.autoDuration === true && isAutoVideoDuration(input.duration) ? input.duration : snap("duration", input.duration, m.durations);
2600
2636
  if (modelId === "gpt-image-2" || modelId === "gpt-image-2-i2i") {
2601
2637
  if (out.aspectRatio === "auto" && out.resolution !== void 0 && out.resolution !== "1K") {
2602
2638
  adjustments.push({
@@ -3079,11 +3115,11 @@ function videoNegativeSuffix(negativePrompt, base) {
3079
3115
  }
3080
3116
  function applyVideoNegativePrompt(prompt, negativePrompt, provider) {
3081
3117
  const promptMax = getMaxVideoPromptChars(provider);
3082
- const clamp = (p) => p != null && p.length > promptMax ? p.slice(0, promptMax) : p;
3118
+ const clamp2 = (p) => p != null && p.length > promptMax ? p.slice(0, promptMax) : p;
3083
3119
  const neg = negativePrompt?.trim();
3084
- if (!neg) return { prompt: clamp(prompt), nativeNegativePrompt: void 0 };
3120
+ if (!neg) return { prompt: clamp2(prompt), nativeNegativePrompt: void 0 };
3085
3121
  if (NATIVE_NEGATIVE_VIDEO_PROVIDERS.has(provider)) {
3086
- return { prompt: clamp(prompt), nativeNegativePrompt: neg.slice(0, getMaxNegativePromptChars(provider)) };
3122
+ return { prompt: clamp2(prompt), nativeNegativePrompt: neg.slice(0, getMaxNegativePromptChars(provider)) };
3087
3123
  }
3088
3124
  const base = prompt && prompt.trim().length > 0 ? prompt : "";
3089
3125
  if (!base) return { prompt: `Avoid: ${neg}`.slice(0, promptMax), nativeNegativePrompt: void 0 };
@@ -3480,6 +3516,12 @@ var VIDEO_TO_VIDEO_PROVIDERS = [
3480
3516
  "runway-aleph",
3481
3517
  "happyhorse-edit"
3482
3518
  ];
3519
+ var SEEDANCE_VIDEO_EDIT_PROVIDERS = ["seedance-2-5"];
3520
+ function isSeedanceVideoEditProvider(provider) {
3521
+ return !!provider && SEEDANCE_VIDEO_EDIT_PROVIDERS.includes(provider);
3522
+ }
3523
+ var VIDEO_TO_VIDEO_NODE_PROVIDERS = [...VIDEO_TO_VIDEO_PROVIDERS, ...SEEDANCE_VIDEO_EDIT_PROVIDERS];
3524
+ var SEEDANCE_VIDEO_EDIT_SHAPE = { aspectRatio: "adaptive", duration: VIDEO_DURATION_AUTO };
3483
3525
  var FACE_SWAP_PROVIDERS = [
3484
3526
  "roop"
3485
3527
  ];
@@ -3607,11 +3649,29 @@ var MUSIC_PROVIDERS = [
3607
3649
  // "bark",
3608
3650
  ];
3609
3651
  var TRANSCRIBE_PROVIDERS = [
3610
- // Replicate disabled
3611
- // "whisper",
3612
- // "incredibly-fast-whisper",
3652
+ "elevenlabs-stt",
3653
+ "whisper",
3654
+ "incredibly-fast-whisper"
3655
+ ];
3656
+ var TRANSCRIBE_LANES = [
3657
+ "whisper",
3658
+ "incredibly-fast-whisper",
3613
3659
  "elevenlabs-stt"
3614
3660
  ];
3661
+ var TRANSCRIBE_PROVIDER_CAPABILITIES = {
3662
+ "whisper": { wordTimestamps: false },
3663
+ "incredibly-fast-whisper": { wordTimestamps: true },
3664
+ "elevenlabs-stt": { wordTimestamps: true }
3665
+ };
3666
+ function transcribeProvidersWithWordTimestamps() {
3667
+ return TRANSCRIBE_LANES.filter((p) => TRANSCRIBE_PROVIDER_CAPABILITIES[p].wordTimestamps);
3668
+ }
3669
+ function transcribeLaneSupportsWordTimestamps(lane) {
3670
+ if (!lane) return false;
3671
+ return TRANSCRIBE_PROVIDER_CAPABILITIES[lane]?.wordTimestamps === true;
3672
+ }
3673
+ var DEFAULT_TRANSCRIBE_PROVIDER = "whisper";
3674
+ var DEFAULT_TRANSCRIBE_NODE_PROVIDER = "elevenlabs-stt";
3615
3675
  var SCRIPT_PROVIDERS = [
3616
3676
  "gemini",
3617
3677
  "claude",
@@ -4209,7 +4269,18 @@ var PRICING_DEFAULT_DURATION_SEC = {
4209
4269
  function pricedOutputDurationSec(provider, requested) {
4210
4270
  const fallback = PRICING_DEFAULT_DURATION_SEC[provider] ?? 5;
4211
4271
  const parsed = typeof requested === "string" ? parseInt(requested, 10) : requested;
4212
- return parsed === void 0 || Number.isNaN(parsed) ? fallback : parsed;
4272
+ if (parsed === void 0 || Number.isNaN(parsed)) return fallback;
4273
+ if (parsed <= 0) {
4274
+ return isAutoVideoDuration(parsed) && supportsAutoVideoDuration(provider) ? maxVideoDurationSec(provider) ?? fallback : fallback;
4275
+ }
4276
+ return parsed;
4277
+ }
4278
+ function supportsAutoVideoDuration(provider) {
4279
+ return !!provider && MODEL_CATALOG[provider]?.autoDuration === true;
4280
+ }
4281
+ function maxVideoDurationSec(provider) {
4282
+ const tiers = VIDEO_DURATION_TIERS[provider];
4283
+ return tiers && tiers.length > 0 ? tiers[tiers.length - 1].maxSeconds : void 0;
4213
4284
  }
4214
4285
  var PRICING_DEFAULT_RESOLUTION = {
4215
4286
  // KIE renders 720p when `resolution` is omitted (kie/models.ts extraParams).
@@ -4734,10 +4805,10 @@ function band(center) {
4734
4805
  var VERT = { low: "upper", mid: "middle", high: "lower" };
4735
4806
  var HORZ = { low: "left", mid: "center", high: "right" };
4736
4807
  function describeMaskRegion(box, image) {
4737
- const clamp012 = (n) => Math.max(0, Math.min(1, n));
4808
+ const clamp013 = (n) => Math.max(0, Math.min(1, n));
4738
4809
  const round2 = (n) => Math.round(n * 100) / 100;
4739
- const nx = clamp012(box.x / image.width);
4740
- const ny = clamp012(box.y / image.height);
4810
+ const nx = clamp013(box.x / image.width);
4811
+ const ny = clamp013(box.y / image.height);
4741
4812
  const normBbox = {
4742
4813
  x: round2(nx),
4743
4814
  y: round2(ny),
@@ -4901,6 +4972,21 @@ function expandExtraRefsToConnectedReferences(extras, lookupCharacterContext) {
4901
4972
  return out;
4902
4973
  }
4903
4974
 
4975
+ // src/video-ui-defaults.ts
4976
+ function uiAspectRatioFill(provider) {
4977
+ return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider) ? "adaptive" : void 0;
4978
+ }
4979
+ function uiResolutionFill(provider) {
4980
+ if (isWan3Provider(provider)) return PRICING_DEFAULT_RESOLUTION[provider];
4981
+ if (isSeedance2Provider(provider)) return MODEL_CATALOG[provider]?.resolutions?.[0];
4982
+ return void 0;
4983
+ }
4984
+ function uiDurationFill(provider) {
4985
+ if (isWan3Provider(provider)) return 5;
4986
+ if (isGeminiOmniProvider(provider)) return 8;
4987
+ return void 0;
4988
+ }
4989
+
4904
4990
  // src/credit-identifiers.ts
4905
4991
  function flux2MegapixelTier(model, resolution) {
4906
4992
  const bare = (v) => v.replace(/\s*MP$/i, "").trim();
@@ -4935,20 +5021,20 @@ function buildCreditModelIdentifier(provider, quality, resolution, renderingSpee
4935
5021
  return provider;
4936
5022
  }
4937
5023
  function resolveNormalizedImageGen(opts) {
4938
- const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
4939
- const provider = str(opts.provider) ?? "nano-banana";
5024
+ const str3 = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
5025
+ const provider = str3(opts.provider) ?? "nano-banana";
4940
5026
  const modelId = opts.swapToI2i && opts.refCount > 0 ? T2I_TO_I2I_VARIANT[provider] ?? provider : provider;
4941
5027
  const n = normalizeModelInput(modelId, {
4942
- aspectRatio: str(opts.aspectRatio),
4943
- resolution: str(opts.resolution),
4944
- quality: str(opts.quality)
5028
+ aspectRatio: str3(opts.aspectRatio),
5029
+ resolution: str3(opts.resolution),
5030
+ quality: str3(opts.quality)
4945
5031
  });
4946
5032
  return {
4947
5033
  identifier: buildCreditModelIdentifier(
4948
5034
  modelId,
4949
5035
  n.quality,
4950
5036
  n.resolution,
4951
- str(opts.renderingSpeed),
5037
+ str3(opts.renderingSpeed),
4952
5038
  void 0,
4953
5039
  opts.refCount
4954
5040
  ),
@@ -5050,6 +5136,18 @@ function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mo
5050
5136
  }
5051
5137
  return identifier;
5052
5138
  }
5139
+ function seedanceVideoEditCreditId(provider, resolution) {
5140
+ return buildVideoCreditModelIdentifier(
5141
+ provider,
5142
+ VIDEO_DURATION_AUTO,
5143
+ void 0,
5144
+ "text-to-video",
5145
+ void 0,
5146
+ resolution ?? uiResolutionFill(provider),
5147
+ /* hasVideoRef */
5148
+ true
5149
+ );
5150
+ }
5053
5151
  function pricedVideoSelection(opts) {
5054
5152
  const adjustments = [];
5055
5153
  const ltx = ltxPricedTier(opts.provider, opts.resolution, opts.duration);
@@ -5252,6 +5350,16 @@ function extractVideoDurationFromNode(data) {
5252
5350
  }
5253
5351
  return void 0;
5254
5352
  }
5353
+ function editPlanSourceDurationSec(data) {
5354
+ const fromVideo = extractVideoDurationFromNode(data);
5355
+ if (fromVideo !== void 0) return fromVideo;
5356
+ const meta = data?.metadata;
5357
+ if (typeof meta?.mediaUrl === "string" && meta.mediaUrl !== data?.extractedAudioUrl && meta.mediaUrl !== data?.url) {
5358
+ return void 0;
5359
+ }
5360
+ const d = meta?.durationSeconds;
5361
+ return typeof d === "number" && Number.isFinite(d) && d > 0 ? d : void 0;
5362
+ }
5255
5363
 
5256
5364
  // src/topaz-upscale.ts
5257
5365
  var TOPAZ_UPSCALE_FACTORS = ["1", "2", "4"];
@@ -5423,7 +5531,20 @@ var DYNAMIC_PRODUCER_TYPES = /* @__PURE__ */ new Set([
5423
5531
  // so it lives here to be accepted on BOTH audio and video input handles. The
5424
5532
  // backend routes the correct lane by sourceHandle in getPrimaryOutput
5425
5533
  // (output-extractor.ts); the frontend does so in extractNodeOutput.
5426
- "split-media"
5534
+ "split-media",
5535
+ // apply-edl renders an EDL into ONE media output whose type is decided at
5536
+ // run time by the node's `output` setting (video OR audio) — so its static
5537
+ // medium is genuinely unknown and it belongs here, letting canvas validators
5538
+ // accept its default media handle on BOTH audio and video input handles. It
5539
+ // ALSO emits a fixed `json` handle (the remapped Transcript); that half lives
5540
+ // in JSON_PRODUCER_TYPES (frontend/src/lib/data-handles.ts). The FIRST node
5541
+ // with both a dynamic media handle and a fixed json handle. Because
5542
+ // getOutputType (presentation-utils.ts) deliberately returns "data" for
5543
+ // DYNAMIC members, apply-edl is ALSO added to the literal VIDEO_OUTPUT_TYPES
5544
+ // there so a published app renders the cut as video, mirroring the
5545
+ // voice-changer/dubbing precedent. Asserted in producer-types.test.ts (the
5546
+ // suite does not fail on omission).
5547
+ "apply-edl"
5427
5548
  ]);
5428
5549
  var AUDIO_PRODUCER_TYPES = /* @__PURE__ */ new Set([
5429
5550
  "text-to-speech",
@@ -5466,7 +5587,14 @@ var FAN_OUT_EACH_TYPES = /* @__PURE__ */ new Set([
5466
5587
  "deduplicate",
5467
5588
  "merge-lists",
5468
5589
  "sort-list",
5469
- "selector"
5590
+ "selector",
5591
+ // edit-plan `clips` mode emits a bare `Edl[]` on `data.generatedJson`, so an
5592
+ // edge leaving it defaults to "each" — one downstream execution (typically an
5593
+ // apply-edl render) per clip. The `tighten`/`chapters` modes emit an OBJECT,
5594
+ // for which the list extractors return undefined, so an "each" edge falls back
5595
+ // to the scalar `edl` value (no fan-out) — the same graceful degradation
5596
+ // web-scrape relies on. See `unwrapEditPlanOutput` in `edit-plan-contract.ts`.
5597
+ "edit-plan"
5470
5598
  ]);
5471
5599
 
5472
5600
  // src/presentation-utils.ts
@@ -5597,7 +5725,14 @@ var VIDEO_OUTPUT_TYPES = /* @__PURE__ */ new Set([
5597
5725
  "motion-transfer",
5598
5726
  "video-upscale",
5599
5727
  "add-captions",
5600
- "social-media-format"
5728
+ "social-media-format",
5729
+ // apply-edl renders an EDL into video OR audio. Its medium is decided at run
5730
+ // time (DYNAMIC_PRODUCER_TYPES), so getOutputType would answer "data" and a
5731
+ // published app would render the cut as a JSON blob. Declaring it here — as
5732
+ // the voice-changer/dubbing precedent does for their default medium — makes
5733
+ // the classifier answer "video" (the common case; an audio-only cut still
5734
+ // plays in a video element). Asserted in producer-types.test.ts.
5735
+ "apply-edl"
5601
5736
  ]);
5602
5737
  var AUDIO_OUTPUT_TYPES = /* @__PURE__ */ new Set([
5603
5738
  "text-to-speech",
@@ -5758,6 +5893,19 @@ var INPUT_FIELD_MAP = {
5758
5893
  function getInputFieldSchema(nodeType) {
5759
5894
  return INPUT_FIELD_MAP[nodeType];
5760
5895
  }
5896
+ var MEDIA_INPUT_FIELD_TYPES = /* @__PURE__ */ new Set([
5897
+ "image-url",
5898
+ "video-url",
5899
+ "audio-url"
5900
+ ]);
5901
+ function mergeNodeInputOverrides(nodeType, data, overrides) {
5902
+ const merged = { ...data, ...overrides };
5903
+ const schema = nodeType ? INPUT_FIELD_MAP[nodeType] : void 0;
5904
+ if (schema && MEDIA_INPUT_FIELD_TYPES.has(schema.type) && schema.key in overrides && overrides[schema.key] !== data[schema.key] && !("metadata" in overrides)) {
5905
+ delete merged.metadata;
5906
+ }
5907
+ return merged;
5908
+ }
5761
5909
  function migrateToItems(order) {
5762
5910
  if (!order) return void 0;
5763
5911
  return order.map((nodeId) => ({ type: "node", nodeId }));
@@ -5869,6 +6017,10 @@ function computeAggregateLanes(nodeId, wiredTypes, buckets, edges) {
5869
6017
  var LLM_REASONING_EFFORTS = ["none", "low", "medium", "high", "xhigh", "max"];
5870
6018
  var EFFORT_TIER_BUMP = /* @__PURE__ */ new Set(["xhigh", "max"]);
5871
6019
  var EFFORT_RANK = { none: 0, low: 1, medium: 2, high: 3, xhigh: 4, max: 5 };
6020
+ var REASONING_OUTPUT_FLOOR = 32768;
6021
+ function reasoningOutputFloor(model) {
6022
+ return model.reasoningOutputFloor ?? REASONING_OUTPUT_FLOOR;
6023
+ }
5872
6024
  var LLM_MODELS = [
5873
6025
  {
5874
6026
  id: "gemini-3-flash",
@@ -5887,7 +6039,12 @@ var LLM_MODELS = [
5887
6039
  directGeminiModel: "gemini-3-flash-preview",
5888
6040
  // No `reasoningEfforts` at all on the KIE lane, but the vendor API accepts
5889
6041
  // the full minimal→high ladder (`none` maps to Google's `minimal`).
5890
- directReasoningEfforts: ["none", "low", "medium", "high"]
6042
+ directReasoningEfforts: ["none", "low", "medium", "high"],
6043
+ // Reasons with no thinking param sent — Google's Gemini 3 default (dynamic
6044
+ // thinking; `minimal` is its floor, never off), measured on 3.6 in #1588.
6045
+ // Floored at the KIE-safe 8192, the same intersection as `maxOutputTokens`.
6046
+ thinkingDefaultOn: true,
6047
+ reasoningOutputFloor: 8192
5891
6048
  },
5892
6049
  {
5893
6050
  id: "gemini-3.6-flash",
@@ -5919,7 +6076,16 @@ var LLM_MODELS = [
5919
6076
  // video-analysis fast tier, so it carries the highest call volume of any
5920
6077
  // Gemini entry — the lane with the lower unit cost wins by default and
5921
6078
  // direct is the reliability fallback only.
5922
- directGeminiModel: "gemini-3.6-flash"
6079
+ directGeminiModel: "gemini-3.6-flash",
6080
+ // Reasons with NO thinking param sent — measured, issue #1588: a Generate
6081
+ // Text node capped at 1,100 tokens fell back to the direct lane (KIE 500),
6082
+ // spent ~1,060 of them reasoning, and returned 120 characters cut mid-URL.
6083
+ // On the same input the KIE runs used ~500 output tokens in all, so only
6084
+ // the fallback runs broke — every other run of a 5-minute schedule.
6085
+ // Floored at 8192, NOT the default 32768: the floor rides the KIE endpoint
6086
+ // too, and 8192 is all it is known to take (see `maxOutputTokens`).
6087
+ thinkingDefaultOn: true,
6088
+ reasoningOutputFloor: 8192
5923
6089
  },
5924
6090
  {
5925
6091
  id: "gemini-3.7-flash",
@@ -5947,7 +6113,11 @@ var LLM_MODELS = [
5947
6113
  reasoningEfforts: ["low", "high"],
5948
6114
  // Assumed parity with 3.6 pending a live probe on the direct lane.
5949
6115
  directReasoningEfforts: ["none", "low", "medium", "high"],
5950
- directGeminiModel: "gemini-3.7-flash"
6116
+ directGeminiModel: "gemini-3.7-flash",
6117
+ // Gemini 3 default: reasons with no thinking param sent (measured on 3.6,
6118
+ // #1588). KIE-safe floor, same intersection as `maxOutputTokens`.
6119
+ thinkingDefaultOn: true,
6120
+ reasoningOutputFloor: 8192
5951
6121
  },
5952
6122
  {
5953
6123
  id: "gemini-3.8-flash",
@@ -5987,7 +6157,12 @@ var LLM_MODELS = [
5987
6157
  directReasoningEfforts: ["none", "low", "medium", "high"],
5988
6158
  // KIE-first (no `preferDirect`) — 3.7's posture exactly: the cheap lane
5989
6159
  // serves the A/B, direct is Advanced mode + the reliability fallback.
5990
- directGeminiModel: "gemini-3.8-flash"
6160
+ directGeminiModel: "gemini-3.8-flash",
6161
+ // Gemini 3 default: reasons with no thinking param sent (measured on 3.6,
6162
+ // #1588). Floored at its own 16384, inside the 20000 its KIE endpoint was
6163
+ // measured to honour.
6164
+ thinkingDefaultOn: true,
6165
+ reasoningOutputFloor: 16384
5991
6166
  },
5992
6167
  {
5993
6168
  id: "claude-haiku-4.5",
@@ -6060,7 +6235,12 @@ var LLM_MODELS = [
6060
6235
  // control, native media ingestion, and a `responseJsonSchema` that honours
6061
6236
  // `additionalProperties` (KIE's `response_format` silently DROPS
6062
6237
  // record/map-shaped fields — see the z.record rule in backend/CLAUDE.md).
6063
- preferDirect: true
6238
+ preferDirect: true,
6239
+ // Reasons with no thinking param sent on both lanes — the proxied endpoint
6240
+ // DEFAULTS to "high" (above), and the direct lane reasons harder still.
6241
+ // Floored at its own 16384: its KIE fallback is not known to take more.
6242
+ thinkingDefaultOn: true,
6243
+ reasoningOutputFloor: 16384
6064
6244
  },
6065
6245
  {
6066
6246
  id: "claude-opus-4.7",
@@ -6155,7 +6335,23 @@ var LLM_MODELS = [
6155
6335
  supportsImages: true,
6156
6336
  maxOutputTokens: 16384,
6157
6337
  reasoningEfforts: ["none", "low", "medium", "high", "xhigh", "max"],
6158
- supportsTemperature: false
6338
+ supportsTemperature: false,
6339
+ // SERVED COLLAPSED, on the astra precedent (2026-09-17). The 2026-07-14
6340
+ // verification that KIE's non-stream responses endpoint serves the GPT-5.6
6341
+ // family reliably no longer holds: a live call — a recast continuity
6342
+ // review, ~3k tokens, `reasoning.effort: high`, `text.format: json_schema`
6343
+ // — came back `500 {"error":{"type":"server_error"}}` / "Server exception,
6344
+ // please try again later". Same endpoint family, same dialect and the same
6345
+ // signature astra was measured on (12 calls: non-stream 2/6, streaming
6346
+ // 5/6; a schema-less non-stream call 500'd too, so the lane is the trigger
6347
+ // and not the schema). ONE sighting here rather than a fresh 12-call probe
6348
+ // — the precedent is strong and the flag is cheap to reverse.
6349
+ //
6350
+ // THE COST: SSE does not reliably carry `credits_consumed`, so this model's
6351
+ // provider cost becomes the rate-table estimate instead of the billed
6352
+ // figure. That is the price of a lane that answers, and it is the same
6353
+ // trade astra already makes.
6354
+ kieCollapseStream: true
6159
6355
  },
6160
6356
  {
6161
6357
  id: "gpt-6-astra",
@@ -6350,6 +6546,10 @@ var LLM_FEATURE_DEFAULTS = {
6350
6546
  "3d-title": "claude-sonnet-4.6",
6351
6547
  "3d-scene": "claude-sonnet-4.6",
6352
6548
  "image-to-text": "claude-sonnet-4.6",
6549
+ // Economy on purpose: the analysis reads ONE frame + the copy per ad and
6550
+ // runs once per returned ad — volume, not depth. Must stay an image-capable
6551
+ // structured-output model (STRUCTURED_VISION_MODELS); a registry test pins it.
6552
+ "meta-ads-analysis": "gemini-3.6-flash",
6353
6553
  "describe-to-picker": "claude-opus-5",
6354
6554
  "qa-check": "gemini-3.6-flash",
6355
6555
  "generate-script": "gemini-3.6-flash",
@@ -6670,10 +6870,10 @@ function fieldRef(field) {
6670
6870
  return BARE_IDENT.test(field) ? `.${field}` : `.["${escapeString(field)}"]`;
6671
6871
  }
6672
6872
  function coerceValue(v) {
6673
- const trimmed = v.trim();
6674
- if (trimmed === "" || trimmed === "Infinity" || trimmed === "-Infinity" || trimmed === "NaN") return `"${trimmed}"`;
6675
- const n = Number(trimmed);
6676
- return Number.isFinite(n) ? String(n) : `"${escapeString(trimmed)}"`;
6873
+ const trimmed2 = v.trim();
6874
+ if (trimmed2 === "" || trimmed2 === "Infinity" || trimmed2 === "-Infinity" || trimmed2 === "NaN") return `"${trimmed2}"`;
6875
+ const n = Number(trimmed2);
6876
+ return Number.isFinite(n) ? String(n) : `"${escapeString(trimmed2)}"`;
6677
6877
  }
6678
6878
  function buildFilterExpr(f) {
6679
6879
  const ref = fieldRef(f.field);
@@ -7404,14 +7604,14 @@ function unresolvedRefTokens(text, opts) {
7404
7604
  // src/filter-condition.ts
7405
7605
  function tryParseJson(item) {
7406
7606
  if (typeof item !== "string") return item;
7407
- const trimmed = item.trim();
7408
- if (!trimmed) return item;
7409
- const first = trimmed[0];
7410
- if (first !== "{" && first !== "[" && first !== '"' && !/^-?\d/.test(trimmed) && trimmed !== "true" && trimmed !== "false" && trimmed !== "null") {
7607
+ const trimmed2 = item.trim();
7608
+ if (!trimmed2) return item;
7609
+ const first = trimmed2[0];
7610
+ if (first !== "{" && first !== "[" && first !== '"' && !/^-?\d/.test(trimmed2) && trimmed2 !== "true" && trimmed2 !== "false" && trimmed2 !== "null") {
7411
7611
  return item;
7412
7612
  }
7413
7613
  try {
7414
- return JSON.parse(trimmed);
7614
+ return JSON.parse(trimmed2);
7415
7615
  } catch {
7416
7616
  return item;
7417
7617
  }
@@ -7459,11 +7659,11 @@ function asComparableNumber(v) {
7459
7659
  if (typeof v === "number") return v;
7460
7660
  if (typeof v === "boolean") return v ? 1 : 0;
7461
7661
  if (typeof v === "string") {
7462
- const trimmed = v.trim();
7463
- if (trimmed === "") return NaN;
7464
- const n = Number(trimmed);
7662
+ const trimmed2 = v.trim();
7663
+ if (trimmed2 === "") return NaN;
7664
+ const n = Number(trimmed2);
7465
7665
  if (!isNaN(n)) return n;
7466
- const d = Date.parse(trimmed);
7666
+ const d = Date.parse(trimmed2);
7467
7667
  if (!isNaN(d)) return d;
7468
7668
  }
7469
7669
  return NaN;
@@ -7573,16 +7773,16 @@ var SCRAPER_OUTPUT_FIELDS = {
7573
7773
  // src/selector.ts
7574
7774
  function resolveIndex(expr, listLength, defaultExpr = "1") {
7575
7775
  if (listLength <= 0) return 0;
7576
- const trimmed = expr.trim();
7776
+ const trimmed2 = expr.trim();
7577
7777
  let index;
7578
- if (trimmed === "last") {
7778
+ if (trimmed2 === "last") {
7579
7779
  index = listLength - 1;
7580
- } else if (trimmed.startsWith("last-")) {
7581
- const offset = parseInt(trimmed.slice(5), 10);
7780
+ } else if (trimmed2.startsWith("last-")) {
7781
+ const offset = parseInt(trimmed2.slice(5), 10);
7582
7782
  if (isNaN(offset) || offset < 0) return resolveIndex(defaultExpr === expr ? "1" : defaultExpr, listLength);
7583
7783
  index = listLength - 1 - offset;
7584
7784
  } else {
7585
- const n = parseInt(trimmed, 10);
7785
+ const n = parseInt(trimmed2, 10);
7586
7786
  if (isNaN(n)) return resolveIndex(defaultExpr === expr ? "1" : defaultExpr, listLength);
7587
7787
  index = n - 1;
7588
7788
  }
@@ -7620,9 +7820,9 @@ function buildRangeLabel(mode, rangeFrom, rangeTo, rangeStep, itemIndex, selecto
7620
7820
  function buildItemLabel(mode, rangeFrom, rangeTo, rangeStep, itemIndex, selectorMode, listExpression) {
7621
7821
  if (mode === "last") return void 0;
7622
7822
  if ((mode === "each" || mode === "all") && selectorMode === "list") {
7623
- const trimmed = (listExpression ?? "").trim();
7624
- if (trimmed === "") return void 0;
7625
- return truncateLabel(trimmed, 18);
7823
+ const trimmed2 = (listExpression ?? "").trim();
7824
+ if (trimmed2 === "") return void 0;
7825
+ return truncateLabel(trimmed2, 18);
7626
7826
  }
7627
7827
  if (mode === "item") return itemIndex || void 0;
7628
7828
  const from = rangeFrom ?? "1";
@@ -7746,10 +7946,10 @@ function buildAllSentence(edgeData) {
7746
7946
  return `Passes ${phrase.text} at once.`;
7747
7947
  }
7748
7948
  function canonicalItemIndex(raw) {
7749
- const trimmed = (raw ?? "").trim();
7750
- if (trimmed === "") return "1";
7751
- if (!isValidIndexToken(trimmed)) return "1";
7752
- return trimmed;
7949
+ const trimmed2 = (raw ?? "").trim();
7950
+ if (trimmed2 === "") return "1";
7951
+ if (!isValidIndexToken(trimmed2)) return "1";
7952
+ return trimmed2;
7753
7953
  }
7754
7954
  function canonicalRange(edgeData) {
7755
7955
  const from = (edgeData?.rangeFrom ?? "").trim() || "1";
@@ -8140,6 +8340,83 @@ function expandItemsWithRepeat(listItems, nodeType, nodeData) {
8140
8340
  return null;
8141
8341
  }
8142
8342
 
8343
+ // src/fan-out-rows.ts
8344
+ var NON_PROMPT_TEXT_LANES = {
8345
+ negative: "*",
8346
+ "system-prompt": "*",
8347
+ script: ["ai-avatar"],
8348
+ transcript: ["add-captions", "apply-edl", "edit-plan"],
8349
+ edl: ["apply-edl"],
8350
+ silence: ["edit-plan"],
8351
+ qrText: ["image-overlay"],
8352
+ transition: ["slideshow"]
8353
+ };
8354
+ function fanOutTextFeedsPrompt(nodeType, targetHandle) {
8355
+ const scope = Object.hasOwn(NON_PROMPT_TEXT_LANES, targetHandle ?? "") ? NON_PROMPT_TEXT_LANES[targetHandle ?? ""] : void 0;
8356
+ if (scope === void 0) return true;
8357
+ return scope !== "*" && !scope.includes(nodeType ?? "");
8358
+ }
8359
+ var isBlank = (v) => typeof v !== "string" || v.trim().length === 0;
8360
+ function compactWithRows(aligned) {
8361
+ const items = [];
8362
+ const rowIndices = [];
8363
+ aligned.forEach((value, row) => {
8364
+ if (isBlank(value)) return;
8365
+ items.push(value);
8366
+ rowIndices.push(row);
8367
+ });
8368
+ return { items, rowIndices };
8369
+ }
8370
+ function liveRowColumn(rows, colIndex) {
8371
+ return rows.filter((row) => row.some((cell) => !isBlank(cell))).map((row) => typeof row[colIndex] === "string" ? row[colIndex].trim() : "");
8372
+ }
8373
+ function resolveListFanOut(candidates, nodeType) {
8374
+ if (candidates.length === 0) return void 0;
8375
+ const held = (c) => compactWithRows(c.aligned).items.length;
8376
+ const primary = candidates.reduce((best, c) => held(c) > held(best) ? c : best);
8377
+ const space = candidates.filter((c) => c.aligned.length === primary.aligned.length);
8378
+ const feedsPrompt = (c) => fanOutTextFeedsPrompt(nodeType, c.targetHandle) && isTextList(c.aligned);
8379
+ const driver = feedsPrompt(primary) ? primary : space.find(feedsPrompt) ?? primary;
8380
+ const rowIndices = [];
8381
+ for (let row = 0; row < primary.aligned.length; row++) {
8382
+ if (space.some((c) => !isBlank(c.aligned[row]))) rowIndices.push(row);
8383
+ }
8384
+ return {
8385
+ items: rowIndices.map((row) => isBlank(driver.aligned[row]) ? "" : driver.aligned[row]),
8386
+ rowIndices,
8387
+ targetHandle: driver.targetHandle
8388
+ };
8389
+ }
8390
+ function isFanOutUrlItem(item) {
8391
+ return item.startsWith("http") || /\.(png|jpg|jpeg|webp|gif|mp4|mov|webm|mp3|wav|ogg)(\?|$)/i.test(item);
8392
+ }
8393
+ function isTextList(aligned) {
8394
+ const first = aligned.find((v) => !isBlank(v));
8395
+ return first !== void 0 && !isFanOutUrlItem(first);
8396
+ }
8397
+ function planFanOut(fanOut, nodeType, nodeData) {
8398
+ const items = expandItemsWithRepeat(fanOut?.items, nodeType, nodeData);
8399
+ if (!items) return null;
8400
+ const listDriven = fanOut !== void 0 && fanOut.items.length > 1;
8401
+ if (!listDriven) return { items, rows: items.map(() => void 0), targetHandle: void 0 };
8402
+ const perRow = items.length / fanOut.items.length;
8403
+ return {
8404
+ items,
8405
+ rows: items.map((_, k) => fanOut.rowIndices[Math.floor(k / perRow)]),
8406
+ targetHandle: fanOut.targetHandle
8407
+ };
8408
+ }
8409
+ function alignedFieldList(value, path) {
8410
+ if (!Array.isArray(value) || value.length === 0) return void 0;
8411
+ const out = [];
8412
+ for (const element of value) {
8413
+ const found = evaluateJsonPath(element, path);
8414
+ if (found.length > 1) return void 0;
8415
+ out.push(stringifyPathResults(found)[0] ?? "");
8416
+ }
8417
+ return out.some((v) => v.length > 0) ? out : void 0;
8418
+ }
8419
+
8143
8420
  // src/settled-with-limit.ts
8144
8421
  async function settledWithLimit(tasks, limit, cancelledRef) {
8145
8422
  const results = new Array(tasks.length);
@@ -8243,7 +8520,9 @@ var VIDEO_ONLY_PARAMETER_NODE_TYPES = /* @__PURE__ */ new Set([
8243
8520
  ]);
8244
8521
  var EXECUTION_GRAPH_COMPOSED_PARAMETER_TYPES = /* @__PURE__ */ new Set([
8245
8522
  "camera-motion",
8246
- "character-motion"
8523
+ "character-motion",
8524
+ "transition",
8525
+ "character-fx"
8247
8526
  ]);
8248
8527
  var registeredPersonPackFields = [];
8249
8528
  function setRegisteredPersonPackFields(fields) {
@@ -8720,8 +8999,8 @@ function splitByLoopDelimiter(text, columns) {
8720
8999
  const firstTextCol = (columns ?? []).find((c) => (c.type ?? "text") === "text");
8721
9000
  const raw = firstTextCol?.splitDelimiter;
8722
9001
  if (raw === NO_SPLIT_DELIMITER) {
8723
- const trimmed = text.trim();
8724
- return trimmed.length > 0 ? [trimmed] : [];
9002
+ const trimmed2 = text.trim();
9003
+ return trimmed2.length > 0 ? [trimmed2] : [];
8725
9004
  }
8726
9005
  const delimiter = raw ?? "\n";
8727
9006
  return text.split(delimiter).map((s) => s.trim()).filter((s) => s.length > 0);
@@ -8756,8 +9035,8 @@ function splitGeneratedItems(text) {
8756
9035
  if (!text) return [];
8757
9036
  const parts = text.split(GENERATE_TEXT_DELIMITER).map((s) => s.trim()).filter(Boolean);
8758
9037
  if (parts.length > 0) return parts;
8759
- const trimmed = text.trim();
8760
- return trimmed ? [trimmed] : [];
9038
+ const trimmed2 = text.trim();
9039
+ return trimmed2 ? [trimmed2] : [];
8761
9040
  }
8762
9041
 
8763
9042
  // src/text-separators.ts
@@ -8814,9 +9093,9 @@ function toNumberKey(v) {
8814
9093
  if (typeof v === "number") return Number.isFinite(v) ? v : void 0;
8815
9094
  if (typeof v === "boolean") return v ? 1 : 0;
8816
9095
  if (typeof v === "string") {
8817
- const trimmed = v.trim();
8818
- if (trimmed === "") return void 0;
8819
- const n = Number(trimmed);
9096
+ const trimmed2 = v.trim();
9097
+ if (trimmed2 === "") return void 0;
9098
+ const n = Number(trimmed2);
8820
9099
  return Number.isFinite(n) ? n : void 0;
8821
9100
  }
8822
9101
  return void 0;
@@ -9277,13 +9556,341 @@ var NODE_MAPPABLE_FIELDS = {
9277
9556
  "object": ["objectName", "description"],
9278
9557
  "creature": ["creatureName", "description"],
9279
9558
  "location": ["locationName", "description"],
9280
- "web-scrape": ["query", "url", "target"]
9559
+ "web-scrape": ["query", "url", "target"],
9560
+ "meta-ads-scrape": ["query", "pageUrls"],
9561
+ "instagram-scrape": ["targets"]
9281
9562
  };
9282
9563
  var SUNO_FIELD_HANDLE_FIELDS = ["style", "lyrics", "title", "negativeStyle"];
9283
9564
  function fieldKeyFromHandle(handleId) {
9284
9565
  return handleId.startsWith("field-") ? handleId.slice("field-".length) : null;
9285
9566
  }
9286
9567
 
9568
+ // src/trigger-node-types.ts
9569
+ var SCHEDULE_TRIGGER_NODE_TYPE = "schedule-trigger";
9570
+ var WEBHOOK_TRIGGER_NODE_TYPE = "webhook-trigger";
9571
+ var TELEGRAM_TRIGGER_NODE_TYPE = "telegram-trigger";
9572
+ var PROJECTED_TRIGGER_NODE_TYPES = /* @__PURE__ */ new Set([
9573
+ SCHEDULE_TRIGGER_NODE_TYPE,
9574
+ WEBHOOK_TRIGGER_NODE_TYPE,
9575
+ TELEGRAM_TRIGGER_NODE_TYPE
9576
+ ]);
9577
+ function isProjectedTriggerNodeType(type) {
9578
+ return typeof type === "string" && PROJECTED_TRIGGER_NODE_TYPES.has(type);
9579
+ }
9580
+
9581
+ // src/trigger-feeds.ts
9582
+ function buildFeedMaps(nodes, edges) {
9583
+ const live = new Set(nodes.map((n) => n.id));
9584
+ const children = /* @__PURE__ */ new Map();
9585
+ const parents = /* @__PURE__ */ new Map();
9586
+ const feeds = (source, target) => {
9587
+ if (!live.has(source) || !live.has(target) || source === target) return;
9588
+ children.set(source, [...children.get(source) ?? [], target]);
9589
+ parents.set(target, [...parents.get(target) ?? [], source]);
9590
+ };
9591
+ for (const edge of edges) feeds(edge.source, edge.target);
9592
+ for (const n of nodes) {
9593
+ if (typeof n.parentId === "string" && n.parentId) feeds(n.id, n.parentId);
9594
+ const mappings = n.data?.fieldMappings;
9595
+ if (mappings && typeof mappings === "object") {
9596
+ for (const mapping of Object.values(mappings)) {
9597
+ const sourceNodeId = mapping?.sourceNodeId;
9598
+ if (typeof sourceNodeId === "string" && sourceNodeId) feeds(sourceNodeId, n.id);
9599
+ }
9600
+ }
9601
+ }
9602
+ return { children, parents };
9603
+ }
9604
+ function nodeFeedsAnything(nodes, edges, nodeId) {
9605
+ return (buildFeedMaps(nodes, edges).children.get(nodeId) ?? []).length > 0;
9606
+ }
9607
+
9608
+ // src/schedule-rules.ts
9609
+ var SCHEDULE_RULE_KINDS = ["minutes", "hours", "days", "weeks", "months", "cron"];
9610
+ var SCHEDULE_EVERY_LIMITS = {
9611
+ minutes: [1, 59],
9612
+ hours: [1, 23],
9613
+ days: [1, 31],
9614
+ weeks: [1, 52],
9615
+ months: [1, 12]
9616
+ };
9617
+ function int(value) {
9618
+ if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
9619
+ if (typeof value === "string" && /^-?\d+$/.test(value.trim())) return parseInt(value.trim(), 10);
9620
+ return null;
9621
+ }
9622
+ function clamp(value, lo, hi, fallback) {
9623
+ if (value === null) return fallback;
9624
+ return Math.min(hi, Math.max(lo, value));
9625
+ }
9626
+ function positiveInt(value) {
9627
+ const n = int(value);
9628
+ return n !== null && n >= 1 ? n : null;
9629
+ }
9630
+ function isCronExpression(value) {
9631
+ return typeof value === "string" && value.trim().split(/\s+/).filter(Boolean).length === 5;
9632
+ }
9633
+ function normalizeScheduleRule(raw, fallbackId = "rule-1") {
9634
+ if (!raw || typeof raw !== "object") return null;
9635
+ const r = raw;
9636
+ if (typeof r.kind !== "string" || !SCHEDULE_RULE_KINDS.includes(r.kind)) return null;
9637
+ const kind = r.kind;
9638
+ const id = typeof r.id === "string" && r.id.trim() ? r.id.trim() : fallbackId;
9639
+ const minute = clamp(int(r.minute), 0, 59, 0);
9640
+ const hour = clamp(int(r.hour), 0, 23, 0);
9641
+ switch (kind) {
9642
+ case "minutes":
9643
+ return { id, kind, every: clamp(positiveInt(r.every), ...SCHEDULE_EVERY_LIMITS.minutes, 5) };
9644
+ case "hours":
9645
+ return { id, kind, every: clamp(positiveInt(r.every), ...SCHEDULE_EVERY_LIMITS.hours, 1), minute };
9646
+ case "days":
9647
+ return { id, kind, every: clamp(positiveInt(r.every), ...SCHEDULE_EVERY_LIMITS.days, 1), hour, minute };
9648
+ case "weeks": {
9649
+ const weekdays = Array.isArray(r.weekdays) ? [...new Set(r.weekdays.map(int).filter((d) => d !== null && d >= 0 && d <= 6))].sort((a, b) => a - b) : [];
9650
+ if (weekdays.length === 0) return null;
9651
+ return { id, kind, every: clamp(positiveInt(r.every), ...SCHEDULE_EVERY_LIMITS.weeks, 1), hour, minute, weekdays };
9652
+ }
9653
+ case "months":
9654
+ return {
9655
+ id,
9656
+ kind,
9657
+ every: clamp(positiveInt(r.every), ...SCHEDULE_EVERY_LIMITS.months, 1),
9658
+ hour,
9659
+ minute,
9660
+ dayOfMonth: clamp(int(r.dayOfMonth), 1, 31, 1)
9661
+ };
9662
+ case "cron": {
9663
+ const cron = typeof r.cron === "string" ? r.cron.trim().split(/\s+/).join(" ") : "";
9664
+ return isCronExpression(cron) ? { id, kind, cron } : null;
9665
+ }
9666
+ }
9667
+ }
9668
+ function normalizeScheduleRules(raw) {
9669
+ if (!Array.isArray(raw)) return [];
9670
+ return raw.map((r, i) => normalizeScheduleRule(r, `rule-${i + 1}`)).filter((r) => r !== null);
9671
+ }
9672
+ function legacyScheduleToRules(data) {
9673
+ const interval = typeof data.interval === "string" ? data.interval.trim() : "";
9674
+ const explicit = [data.cron, data.cronExpression].find((v) => typeof v === "string" && v.trim() !== "")?.trim() ?? "";
9675
+ const m = interval.match(/^(\d+)([smhd])$/);
9676
+ if (m) {
9677
+ const n = parseInt(m[1], 10);
9678
+ if (n < 1) return [];
9679
+ switch (m[2]) {
9680
+ case "s":
9681
+ return [{ id: "rule-1", kind: "minutes", every: 1 }];
9682
+ case "m":
9683
+ return n < 60 ? [{ id: "rule-1", kind: "minutes", every: n }] : [{ id: "rule-1", kind: "hours", every: Math.min(23, Math.max(1, Math.round(n / 60))), minute: 0 }];
9684
+ case "h":
9685
+ return n < 24 ? [{ id: "rule-1", kind: "hours", every: n, minute: 0 }] : [{ id: "rule-1", kind: "days", every: Math.min(31, Math.max(1, Math.round(n / 24))), hour: 0, minute: 0 }];
9686
+ default:
9687
+ return [{ id: "rule-1", kind: "days", every: Math.min(31, n), hour: 0, minute: 0 }];
9688
+ }
9689
+ }
9690
+ const expression = interval === "" || interval === "custom" ? explicit : interval;
9691
+ if (!isCronExpression(expression)) return [];
9692
+ const fromCron = cronToRule(expression);
9693
+ return normalizeScheduleRules([fromCron ?? { id: "rule-1", kind: "cron", cron: expression.split(/\s+/).join(" ") }]);
9694
+ }
9695
+ function cronStep(field) {
9696
+ const m = field.match(/^\*\/(\d+)$/);
9697
+ if (!m) return null;
9698
+ const n = parseInt(m[1], 10);
9699
+ return n >= 1 ? n : null;
9700
+ }
9701
+ function cronToRule(expression) {
9702
+ const [min, hour, dom, month, dow] = expression.trim().split(/\s+/);
9703
+ if (month !== "*") return null;
9704
+ const minN = /^\d+$/.test(min) ? parseInt(min, 10) : null;
9705
+ const hourN = /^\d+$/.test(hour) ? parseInt(hour, 10) : null;
9706
+ const stepMin = cronStep(min);
9707
+ const stepHour = cronStep(hour);
9708
+ if (stepMin !== null && hour === "*" && dom === "*" && dow === "*") return { id: "rule-1", kind: "minutes", every: stepMin };
9709
+ if (min === "*" && hour === "*" && dom === "*" && dow === "*") return { id: "rule-1", kind: "minutes", every: 1 };
9710
+ if (minN !== null && stepHour !== null && dom === "*" && dow === "*") return { id: "rule-1", kind: "hours", every: stepHour, minute: minN };
9711
+ if (minN !== null && hour === "*" && dom === "*" && dow === "*") return { id: "rule-1", kind: "hours", every: 1, minute: minN };
9712
+ if (minN !== null && hourN !== null && dom === "*" && dow === "*") return { id: "rule-1", kind: "days", every: 1, hour: hourN, minute: minN };
9713
+ if (minN !== null && hourN !== null && dom === "*" && /^[0-6](,[0-6])*$|^[0-6]-[0-6]$/.test(dow)) {
9714
+ const weekdays = dow.includes("-") ? (() => {
9715
+ const [a, b] = dow.split("-").map(Number);
9716
+ return Array.from({ length: b - a + 1 }, (_, i) => a + i);
9717
+ })() : dow.split(",").map(Number);
9718
+ return { id: "rule-1", kind: "weeks", every: 1, hour: hourN, minute: minN, weekdays };
9719
+ }
9720
+ if (minN !== null && hourN !== null && /^\d+$/.test(dom) && dow === "*") {
9721
+ return { id: "rule-1", kind: "months", every: 1, hour: hourN, minute: minN, dayOfMonth: parseInt(dom, 10) };
9722
+ }
9723
+ return null;
9724
+ }
9725
+ var formatters = /* @__PURE__ */ new Map();
9726
+ var canonicalZone = /* @__PURE__ */ new Map();
9727
+ var MAX_ZONE_SPELLINGS = 1024;
9728
+ function formatterFor(timezone) {
9729
+ const spelled = timezone && timezone.trim() ? timezone.trim() : "UTC";
9730
+ const known = canonicalZone.get(spelled);
9731
+ if (known) return formatters.get(known) ?? null;
9732
+ try {
9733
+ const fmt = new Intl.DateTimeFormat("en-US", {
9734
+ timeZone: spelled,
9735
+ hourCycle: "h23",
9736
+ year: "numeric",
9737
+ month: "2-digit",
9738
+ day: "2-digit",
9739
+ hour: "2-digit",
9740
+ minute: "2-digit"
9741
+ });
9742
+ const canonical = fmt.resolvedOptions().timeZone;
9743
+ if (!formatters.has(canonical)) formatters.set(canonical, fmt);
9744
+ if (canonicalZone.size >= MAX_ZONE_SPELLINGS) canonicalZone.clear();
9745
+ canonicalZone.set(spelled, canonical);
9746
+ return formatters.get(canonical) ?? fmt;
9747
+ } catch {
9748
+ return null;
9749
+ }
9750
+ }
9751
+ function isValidTimezone(value) {
9752
+ return typeof value === "string" && value.trim() !== "" && formatterFor(value) !== null;
9753
+ }
9754
+ function localMinuteKey(local) {
9755
+ return `${local.epochDay}:${local.hour}:${local.minute}`;
9756
+ }
9757
+ function localFromComponents(year, month, day, hour, minute) {
9758
+ const epochDay = Math.floor(Date.UTC(year, month - 1, day) / 864e5);
9759
+ const weekday = (epochDay % 7 + 7 + 4) % 7;
9760
+ return { year, month, day, hour: hour === 24 ? 0 : hour, minute, weekday, epochDay };
9761
+ }
9762
+ function localTimeIn(date, timezone) {
9763
+ const fmt = formatterFor(timezone);
9764
+ if (!fmt) return localFromComponents(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes());
9765
+ const parts = {};
9766
+ for (const p of fmt.formatToParts(date)) {
9767
+ if (p.type === "literal") continue;
9768
+ parts[p.type] = parseInt(p.value, 10);
9769
+ }
9770
+ return localFromComponents(parts.year, parts.month, parts.day, parts.hour, parts.minute);
9771
+ }
9772
+ function timezoneOffsetMinutes(date, timezone) {
9773
+ const local = localTimeIn(date, timezone);
9774
+ const asUtc = Date.UTC(local.year, local.month - 1, local.day, local.hour, local.minute);
9775
+ const truncated = Math.floor(date.getTime() / 6e4) * 6e4;
9776
+ return Math.round((asUtc - truncated) / 6e4);
9777
+ }
9778
+ function daysInMonth(year, month) {
9779
+ return new Date(Date.UTC(year, month, 0)).getUTCDate();
9780
+ }
9781
+ function matchesCronField(field, value, min, max) {
9782
+ if (field === "*") return true;
9783
+ if (field.includes(",")) return field.split(",").some((part) => matchesCronField(part.trim(), value, min, max));
9784
+ if (field.includes("/")) {
9785
+ const [range, step] = field.split("/");
9786
+ const stepNum = parseInt(step, 10);
9787
+ if (Number.isNaN(stepNum) || stepNum <= 0) return false;
9788
+ if (range === "*") return value % stepNum === 0;
9789
+ if (range.includes("-")) {
9790
+ const [start2, end] = parseRange(range);
9791
+ if (start2 === null || end === null) return false;
9792
+ return value >= start2 && value <= end && (value - start2) % stepNum === 0;
9793
+ }
9794
+ const start = parseInt(range, 10);
9795
+ if (Number.isNaN(start)) return false;
9796
+ return value >= start && value <= max && (value - start) % stepNum === 0;
9797
+ }
9798
+ if (field.includes("-")) {
9799
+ const [start, end] = parseRange(field);
9800
+ if (start === null || end === null) return false;
9801
+ return value >= start && value <= end;
9802
+ }
9803
+ const num2 = parseInt(field, 10);
9804
+ return !Number.isNaN(num2) && num2 === value;
9805
+ }
9806
+ function parseRange(range) {
9807
+ const parts = range.split("-");
9808
+ if (parts.length !== 2) return [null, null];
9809
+ const start = parseInt(parts[0], 10);
9810
+ const end = parseInt(parts[1], 10);
9811
+ return [Number.isNaN(start) ? null : start, Number.isNaN(end) ? null : end];
9812
+ }
9813
+ function matchesCron(expression, local) {
9814
+ const fields = expression.trim().split(/\s+/);
9815
+ if (fields.length !== 5) return false;
9816
+ return matchesCronField(fields[0], local.minute, 0, 59) && matchesCronField(fields[1], local.hour, 0, 23) && matchesCronField(fields[2], local.day, 1, 31) && matchesCronField(fields[3], local.month, 1, 12) && (matchesCronField(fields[4], local.weekday, 0, 6) || local.weekday === 0 && matchesCronField(fields[4], 7, 0, 7));
9817
+ }
9818
+ function ruleMatches(rule, local) {
9819
+ const every = Math.max(1, rule.every ?? 1);
9820
+ const minute = rule.minute ?? 0;
9821
+ const hour = rule.hour ?? 0;
9822
+ switch (rule.kind) {
9823
+ case "minutes":
9824
+ return local.minute % every === 0;
9825
+ case "hours":
9826
+ return local.minute === minute && local.hour % every === 0;
9827
+ case "days":
9828
+ return local.minute === minute && local.hour === hour && local.epochDay % every === 0;
9829
+ case "weeks": {
9830
+ const weekIndex = Math.floor((local.epochDay + 3) / 7);
9831
+ return local.minute === minute && local.hour === hour && (rule.weekdays ?? []).includes(local.weekday) && weekIndex % every === 0;
9832
+ }
9833
+ case "months": {
9834
+ const wanted = Math.min(rule.dayOfMonth ?? 1, daysInMonth(local.year, local.month));
9835
+ const monthIndex = local.year * 12 + (local.month - 1);
9836
+ return local.minute === minute && local.hour === hour && local.day === wanted && monthIndex % every === 0;
9837
+ }
9838
+ case "cron":
9839
+ return typeof rule.cron === "string" && matchesCron(rule.cron, local);
9840
+ }
9841
+ }
9842
+ function scheduleMatchesAt(spec, at) {
9843
+ if (spec.rules.length === 0) return false;
9844
+ const local = localTimeIn(at, spec.timezone);
9845
+ return spec.rules.some((rule) => ruleMatches(rule, local));
9846
+ }
9847
+ var OFFSET_SLOT_MS = 15 * 6e4;
9848
+ function scheduleOccurrences(spec, from, until, cap) {
9849
+ const out = [];
9850
+ if (spec.rules.length === 0 || cap <= 0) return out;
9851
+ const rules = spec.rules;
9852
+ let t2 = Math.ceil(from.getTime() / 6e4) * 6e4;
9853
+ const end = until.getTime();
9854
+ let slot = -1;
9855
+ let offset = 0;
9856
+ let lastKey = "";
9857
+ while (t2 <= end && out.length < cap) {
9858
+ const thisSlot = Math.floor(t2 / OFFSET_SLOT_MS);
9859
+ if (thisSlot !== slot) {
9860
+ slot = thisSlot;
9861
+ offset = timezoneOffsetMinutes(new Date(t2), spec.timezone);
9862
+ }
9863
+ const shifted = new Date(t2 + offset * 6e4);
9864
+ const local = localFromComponents(
9865
+ shifted.getUTCFullYear(),
9866
+ shifted.getUTCMonth() + 1,
9867
+ shifted.getUTCDate(),
9868
+ shifted.getUTCHours(),
9869
+ shifted.getUTCMinutes()
9870
+ );
9871
+ if (rules.some((rule) => ruleMatches(rule, local))) {
9872
+ const key = localMinuteKey(local);
9873
+ if (key !== lastKey) out.push(new Date(t2));
9874
+ lastKey = key;
9875
+ }
9876
+ t2 += 6e4;
9877
+ }
9878
+ return out;
9879
+ }
9880
+ var DAY_MS2 = 864e5;
9881
+ function previewHorizonMs(rules) {
9882
+ let longest = 0;
9883
+ for (const rule of rules) {
9884
+ const every = Math.max(1, rule.every ?? 1);
9885
+ const period = rule.kind === "days" ? every * DAY_MS2 : rule.kind === "weeks" ? every * 7 * DAY_MS2 : rule.kind === "months" ? every * 31 * DAY_MS2 : rule.kind === "cron" ? 366 * DAY_MS2 : DAY_MS2;
9886
+ if (period > longest) longest = period;
9887
+ }
9888
+ return Math.min(800 * DAY_MS2, Math.max(62 * DAY_MS2, longest * 2 + DAY_MS2));
9889
+ }
9890
+ function nextScheduleRuns(spec, from, count, horizonMs = previewHorizonMs(spec.rules)) {
9891
+ return scheduleOccurrences(spec, new Date(from.getTime() + 1), new Date(from.getTime() + horizonMs), count);
9892
+ }
9893
+
9287
9894
  // src/scraper-actors.ts
9288
9895
  var SCRAPER_ACTOR_IDS = [
9289
9896
  "content-crawler",
@@ -9325,6 +9932,338 @@ function resolveScraperCreditId(body) {
9325
9932
  return buildScraperCreditId({ actor: raw.actor, mode });
9326
9933
  }
9327
9934
 
9935
+ // src/meta-ads-scrape.ts
9936
+ var META_ADS_SCRAPE_NODE_TYPE = "meta-ads-scrape";
9937
+ var META_ADS_SCRAPE_MODES = ["search", "pages"];
9938
+ var META_ADS_NODE_MODES = [...META_ADS_SCRAPE_MODES, "advertiser"];
9939
+ function metaAdsNodeMode(value) {
9940
+ return typeof value === "string" && META_ADS_NODE_MODES.includes(value) ? value : "search";
9941
+ }
9942
+ var META_ADS_ADVERTISER_MAX_RESULTS = 8;
9943
+ var META_ADS_URL_MAX_LENGTH = 2048;
9944
+ function httpUrlOnHost(value, host) {
9945
+ if (typeof value !== "string" || value.length > META_ADS_URL_MAX_LENGTH) return false;
9946
+ try {
9947
+ const url = new URL(value);
9948
+ return (url.protocol === "https:" || url.protocol === "http:") && host.test(url.hostname);
9949
+ } catch {
9950
+ return false;
9951
+ }
9952
+ }
9953
+ function isFacebookPageUrl(value) {
9954
+ return httpUrlOnHost(value, /(^|\.)facebook\.com$/i);
9955
+ }
9956
+ function isMetaCdnImageUrl(value) {
9957
+ return httpUrlOnHost(value, /(^|\.)(fbcdn\.net|facebook\.com)$/i);
9958
+ }
9959
+ function metaAdsAdvertisersFrom(raw, limit = META_ADS_SCRAPE_MAX_SOURCES) {
9960
+ if (!Array.isArray(raw) || limit < 1) return [];
9961
+ const seen = /* @__PURE__ */ new Set();
9962
+ const out = [];
9963
+ for (const item of raw) {
9964
+ if (!item || typeof item !== "object") continue;
9965
+ const r = item;
9966
+ const pageId = typeof r.pageId === "string" ? r.pageId.trim() : typeof r.pageId === "number" && Number.isFinite(r.pageId) ? String(r.pageId) : "";
9967
+ const name = typeof r.name === "string" ? r.name.trim().slice(0, 120) : "";
9968
+ if (!pageId || !name || !isFacebookPageUrl(r.url) || seen.has(pageId)) continue;
9969
+ seen.add(pageId);
9970
+ out.push({
9971
+ pageId,
9972
+ name,
9973
+ url: r.url,
9974
+ ...isMetaCdnImageUrl(r.imageUrl) ? { imageUrl: r.imageUrl } : {},
9975
+ ...r.verified === true ? { verified: true } : {}
9976
+ });
9977
+ if (out.length >= limit) break;
9978
+ }
9979
+ return out;
9980
+ }
9981
+ var META_ADS_SCRAPE_PERIODS = ["24h", "7d", "30d", "all"];
9982
+ var META_ADS_SCRAPE_STATUSES = ["active", "inactive", "all"];
9983
+ var META_ADS_PLATFORMS = ["FACEBOOK", "INSTAGRAM", "AUDIENCE_NETWORK", "MESSENGER", "WHATSAPP", "THREADS"];
9984
+ function isMetaAdsPlatform(value) {
9985
+ return typeof value === "string" && META_ADS_PLATFORMS.includes(value);
9986
+ }
9987
+ var META_ADS_FORMATS = ["vertical", "square", "horizontal"];
9988
+ function isMetaAdsFormat(value) {
9989
+ return typeof value === "string" && META_ADS_FORMATS.includes(value);
9990
+ }
9991
+ function clampMetaAdsFeaturedIndex(stored, count) {
9992
+ if (count <= 0) return 0;
9993
+ const n = typeof stored === "number" && Number.isFinite(stored) ? Math.trunc(stored) : 0;
9994
+ return Math.min(Math.max(n, 0), count - 1);
9995
+ }
9996
+ function urlStrings(value) {
9997
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string" && v.trim().length > 0) : [];
9998
+ }
9999
+ function featuredMetaAdOutputs(json, featuredIndex) {
10000
+ if (!Array.isArray(json) || json.length === 0) return {};
10001
+ const ad = json[clampMetaAdsFeaturedIndex(featuredIndex, json.length)];
10002
+ if (!ad || typeof ad !== "object") return {};
10003
+ const a = ad;
10004
+ const title = typeof a.title === "string" ? a.title.trim() : "";
10005
+ const body = typeof a.text === "string" ? a.text.trim() : "";
10006
+ const text = [title, body].filter((s) => s.length > 0).join("\n\n");
10007
+ const imageUrl = urlStrings(a.images)[0] ?? urlStrings(a.videoPreviews)[0];
10008
+ const videoUrl = urlStrings(a.videos)[0];
10009
+ return {
10010
+ ...text ? { text } : {},
10011
+ ...imageUrl ? { imageUrl } : {},
10012
+ ...videoUrl ? { videoUrl } : {}
10013
+ };
10014
+ }
10015
+ function classifyCreativeFormat(width, height) {
10016
+ if (typeof width !== "number" || typeof height !== "number" || !Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0) {
10017
+ return "unknown";
10018
+ }
10019
+ const ratio = width / height;
10020
+ if (ratio < 0.95) return "vertical";
10021
+ if (ratio <= 1.05) return "square";
10022
+ return "horizontal";
10023
+ }
10024
+ var META_ADS_SCRAPE_COUNT_OPTIONS = [10, 20, 50, 100];
10025
+ var META_ADS_SCRAPE_DEFAULT_COUNT = 20;
10026
+ var META_ADS_SCRAPE_MAX_COUNT = 100;
10027
+ var META_ADS_SCRAPE_MAX_SOURCES = 5;
10028
+ var META_ADS_SCRAPE_MAX_QUERY_LENGTH = 100;
10029
+ var META_ADS_SCRAPE_DEFAULT_COUNTRY = "ALL";
10030
+ var META_ADS_SCRAPE_TIERS = [10, 20, 50, 100, 200, 500];
10031
+ var META_ADS_ANALYSIS_TIERS = ["economy", "standard", "premium"];
10032
+ var META_ADS_ANALYSIS_CREDITS_PER_AD = { economy: 1, standard: 3, premium: 4 };
10033
+ var META_ADS_ANALYSIS_CREDIT_ID = "meta-ads-analysis";
10034
+ var META_ADS_ANALYSIS_FOCUS_MAX = 500;
10035
+ function metaAdsAnalysisCreditId(tier) {
10036
+ return tier === "standard" ? META_ADS_ANALYSIS_CREDIT_ID : `${META_ADS_ANALYSIS_CREDIT_ID}:${tier}`;
10037
+ }
10038
+ function metaAdsAnalysisTier(modelId) {
10039
+ const id = typeof modelId === "string" && modelId ? modelId : LLM_FEATURE_DEFAULTS["meta-ads-analysis"];
10040
+ return getLlmTier(id);
10041
+ }
10042
+ var strList = (v) => Array.isArray(v) ? v.filter((s) => typeof s === "string" && s.trim().length > 0) : [];
10043
+ var str = (v) => typeof v === "string" ? v : "";
10044
+ function adCreativeAnalysisFrom(raw) {
10045
+ if (!raw || typeof raw !== "object") return null;
10046
+ const r = raw;
10047
+ if (typeof r.summary !== "string" || !r.summary.trim()) return null;
10048
+ const assetType = r.assetType === "static" || r.assetType === "motion" || r.assetType === "carousel" ? r.assetType : "unknown";
10049
+ return {
10050
+ assetType,
10051
+ format: str(r.format),
10052
+ visualHooks: strList(r.visualHooks),
10053
+ audiences: strList(r.audiences),
10054
+ graphicIdentity: str(r.graphicIdentity),
10055
+ copywritingHooks: strList(r.copywritingHooks),
10056
+ usps: strList(r.usps),
10057
+ cta: str(r.cta),
10058
+ summary: r.summary
10059
+ };
10060
+ }
10061
+ function analysisSuffix(tier) {
10062
+ return tier === "standard" ? ":analysis" : `:analysis:${tier}`;
10063
+ }
10064
+ function buildMetaAdsCreditCostTable() {
10065
+ const table = { [META_ADS_SCRAPE_NODE_TYPE]: 20 };
10066
+ for (const tier of META_ADS_ANALYSIS_TIERS) table[metaAdsAnalysisCreditId(tier)] = META_ADS_ANALYSIS_CREDITS_PER_AD[tier];
10067
+ for (const t2 of META_ADS_SCRAPE_TIERS) {
10068
+ table[`${META_ADS_SCRAPE_NODE_TYPE}:${t2}`] = t2;
10069
+ for (const tier of META_ADS_ANALYSIS_TIERS) {
10070
+ table[`${META_ADS_SCRAPE_NODE_TYPE}:${t2}${analysisSuffix(tier)}`] = t2 * (1 + META_ADS_ANALYSIS_CREDITS_PER_AD[tier]);
10071
+ }
10072
+ }
10073
+ return table;
10074
+ }
10075
+ var META_ADS_SCRAPE_CREDIT_COSTS = buildMetaAdsCreditCostTable();
10076
+ var META_ADS_SCRAPE_FALLBACK_CREDIT_ID = "meta-ads-scrape:20";
10077
+ function splitMetaAdsPageUrls(value) {
10078
+ if (Array.isArray(value)) {
10079
+ return value.filter((v) => typeof v === "string").map((v) => v.trim()).filter((v) => v.length > 0);
10080
+ }
10081
+ if (typeof value !== "string") return [];
10082
+ return value.split(/[\n,\s]+/).map((v) => v.trim()).filter((v) => v.length > 0);
10083
+ }
10084
+ function isMetaAdsScrapeMode(value) {
10085
+ return typeof value === "string" && META_ADS_SCRAPE_MODES.includes(value);
10086
+ }
10087
+ function splitMetaAdsAdvertiserNames(value) {
10088
+ const raw = Array.isArray(value) ? value.filter((v) => typeof v === "string") : typeof value === "string" ? value.split(/[\n,]+/) : [];
10089
+ const seen = /* @__PURE__ */ new Set();
10090
+ const out = [];
10091
+ for (const item of raw) {
10092
+ const name = item.trim();
10093
+ if (name.length < 2 || name.length > META_ADS_SCRAPE_MAX_QUERY_LENGTH) continue;
10094
+ const key = name.toLowerCase();
10095
+ if (seen.has(key)) continue;
10096
+ seen.add(key);
10097
+ out.push(name);
10098
+ if (out.length >= META_ADS_SCRAPE_MAX_SOURCES) break;
10099
+ }
10100
+ return out;
10101
+ }
10102
+ function metaAdsScrapeSources(data) {
10103
+ switch (metaAdsNodeMode(data.mode)) {
10104
+ case "pages":
10105
+ return Math.max(1, Math.min(splitMetaAdsPageUrls(data.pageUrls).length, META_ADS_SCRAPE_MAX_SOURCES));
10106
+ case "advertiser":
10107
+ return Math.max(1, metaAdsAdvertisersFrom(data.advertisers).length);
10108
+ default:
10109
+ return 1;
10110
+ }
10111
+ }
10112
+ function metaAdsScrapeWireSources(data, upstream) {
10113
+ const upstreamText = typeof upstream === "string" ? upstream : void 0;
10114
+ switch (metaAdsNodeMode(data.mode)) {
10115
+ case "pages": {
10116
+ const own = splitMetaAdsPageUrls(data.pageUrls);
10117
+ return { mode: "pages", pageUrls: own.length > 0 ? own : splitMetaAdsPageUrls(upstreamText) };
10118
+ }
10119
+ case "advertiser": {
10120
+ const picks = metaAdsAdvertisersFrom(data.advertisers);
10121
+ if (picks.length > 0) return { mode: "pages", pageUrls: picks.map((a) => a.url) };
10122
+ const names = splitMetaAdsAdvertiserNames(upstreamText);
10123
+ return { mode: "pages", pageUrls: [], advertiserNames: names };
10124
+ }
10125
+ default: {
10126
+ const own = typeof data.query === "string" ? data.query : "";
10127
+ return { mode: "search", query: own || upstreamText };
10128
+ }
10129
+ }
10130
+ }
10131
+ function isMetaAdsScrapeCount(value) {
10132
+ return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= META_ADS_SCRAPE_MAX_COUNT;
10133
+ }
10134
+ function metaAdsScrapeTier(requestedTotal) {
10135
+ for (const tier of META_ADS_SCRAPE_TIERS) {
10136
+ if (requestedTotal <= tier) return tier;
10137
+ }
10138
+ return META_ADS_SCRAPE_TIERS[META_ADS_SCRAPE_TIERS.length - 1];
10139
+ }
10140
+ function buildMetaAdsScrapeCreditId(input) {
10141
+ const sources = Math.min(Math.max(Math.trunc(input.sources) || 1, 1), META_ADS_SCRAPE_MAX_SOURCES);
10142
+ const count = Math.min(Math.max(Math.trunc(input.count) || 1, 1), META_ADS_SCRAPE_MAX_COUNT);
10143
+ const base = `${META_ADS_SCRAPE_NODE_TYPE}:${metaAdsScrapeTier(count * sources)}`;
10144
+ return input.analysis ? `${base}${analysisSuffix(input.analysis)}` : base;
10145
+ }
10146
+ function metaAdsAnalysisTierFrom(data) {
10147
+ return data.analyze === true ? metaAdsAnalysisTier(data.analysisModel) : null;
10148
+ }
10149
+ function resolveMetaAdsScrapeCreditId(body) {
10150
+ const raw = body;
10151
+ if (!raw || typeof raw !== "object") return META_ADS_SCRAPE_FALLBACK_CREDIT_ID;
10152
+ const count = raw.count === void 0 ? META_ADS_SCRAPE_DEFAULT_COUNT : raw.count;
10153
+ if (!isMetaAdsScrapeCount(count)) return META_ADS_SCRAPE_FALLBACK_CREDIT_ID;
10154
+ const sources = raw.mode === "pages" ? (Array.isArray(raw.pageUrls) ? raw.pageUrls.length : 0) + (Array.isArray(raw.advertiserNames) ? raw.advertiserNames.length : 0) : 1;
10155
+ if (sources < 1 || sources > META_ADS_SCRAPE_MAX_SOURCES) return META_ADS_SCRAPE_FALLBACK_CREDIT_ID;
10156
+ return buildMetaAdsScrapeCreditId({ count, sources, analysis: metaAdsAnalysisTierFrom(raw) });
10157
+ }
10158
+ function metaAdsScrapeCreditIdFromNode(data) {
10159
+ const count = typeof data.count === "number" ? data.count : META_ADS_SCRAPE_DEFAULT_COUNT;
10160
+ return buildMetaAdsScrapeCreditId({ count, sources: metaAdsScrapeSources(data), analysis: metaAdsAnalysisTierFrom(data) });
10161
+ }
10162
+
10163
+ // src/instagram-scrape.ts
10164
+ var INSTAGRAM_SCRAPE_NODE_TYPE = "instagram-scrape";
10165
+ var INSTAGRAM_SCRAPE_MODES = ["profile", "hashtag"];
10166
+ function isInstagramScrapeMode(value) {
10167
+ return typeof value === "string" && INSTAGRAM_SCRAPE_MODES.includes(value);
10168
+ }
10169
+ function instagramScrapeMode(value) {
10170
+ return isInstagramScrapeMode(value) ? value : "profile";
10171
+ }
10172
+ var INSTAGRAM_SCRAPE_PERIODS = ["24h", "7d", "30d", "all"];
10173
+ var INSTAGRAM_SCRAPE_DEFAULT_COUNT = 20;
10174
+ var INSTAGRAM_SCRAPE_MAX_COUNT = 100;
10175
+ var INSTAGRAM_SCRAPE_MAX_SOURCES = 5;
10176
+ var INSTAGRAM_SCRAPE_MAX_TARGET_LENGTH = 200;
10177
+ var INSTAGRAM_SCRAPE_TIERS = [10, 20, 50, 100, 200, 500];
10178
+ function instagramScrapeTier(requestedTotal) {
10179
+ for (const tier of INSTAGRAM_SCRAPE_TIERS) if (requestedTotal <= tier) return tier;
10180
+ return INSTAGRAM_SCRAPE_TIERS[INSTAGRAM_SCRAPE_TIERS.length - 1];
10181
+ }
10182
+ function instagramAnalysisTierFrom(data) {
10183
+ return data.analyze === true ? metaAdsAnalysisTier(data.analysisModel) : null;
10184
+ }
10185
+ function analysisSuffix2(tier) {
10186
+ return tier === "standard" ? ":analysis" : `:analysis:${tier}`;
10187
+ }
10188
+ var INSTAGRAM_ANALYSIS_CREDIT_ID = "instagram-analysis";
10189
+ function instagramAnalysisCreditId(tier) {
10190
+ return tier === "standard" ? INSTAGRAM_ANALYSIS_CREDIT_ID : `${INSTAGRAM_ANALYSIS_CREDIT_ID}:${tier}`;
10191
+ }
10192
+ function buildInstagramScrapeCreditId(input) {
10193
+ const sources = Math.min(Math.max(Math.trunc(input.sources) || 1, 1), INSTAGRAM_SCRAPE_MAX_SOURCES);
10194
+ const count = Math.min(Math.max(Math.trunc(input.count) || 1, 1), INSTAGRAM_SCRAPE_MAX_COUNT);
10195
+ const base = `${INSTAGRAM_SCRAPE_NODE_TYPE}:${instagramScrapeTier(count * sources)}`;
10196
+ return input.analysis ? `${base}${analysisSuffix2(input.analysis)}` : base;
10197
+ }
10198
+ var INSTAGRAM_SCRAPE_CREDIT_COSTS = (() => {
10199
+ const table = { [INSTAGRAM_SCRAPE_NODE_TYPE]: 20 };
10200
+ for (const tier of META_ADS_ANALYSIS_TIERS) table[instagramAnalysisCreditId(tier)] = META_ADS_ANALYSIS_CREDITS_PER_AD[tier];
10201
+ for (const t2 of INSTAGRAM_SCRAPE_TIERS) {
10202
+ table[`${INSTAGRAM_SCRAPE_NODE_TYPE}:${t2}`] = t2;
10203
+ for (const tier of META_ADS_ANALYSIS_TIERS) {
10204
+ table[`${INSTAGRAM_SCRAPE_NODE_TYPE}:${t2}${analysisSuffix2(tier)}`] = t2 * (1 + META_ADS_ANALYSIS_CREDITS_PER_AD[tier]);
10205
+ }
10206
+ }
10207
+ return table;
10208
+ })();
10209
+ var INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID = "instagram-scrape:20";
10210
+ function isInstagramScrapeCount(value) {
10211
+ return typeof value === "number" && Number.isInteger(value) && value >= 1 && value <= INSTAGRAM_SCRAPE_MAX_COUNT;
10212
+ }
10213
+ function splitInstagramTargets(value) {
10214
+ const raw = Array.isArray(value) ? value.filter((v) => typeof v === "string") : typeof value === "string" ? value.split(/[\n,]+/) : [];
10215
+ const seen = /* @__PURE__ */ new Set();
10216
+ const out = [];
10217
+ for (const item of raw) {
10218
+ const t2 = item.trim().replace(/^[@#]+/, "").trim();
10219
+ if (t2.length < 1 || t2.length > INSTAGRAM_SCRAPE_MAX_TARGET_LENGTH) continue;
10220
+ const key = t2.toLowerCase();
10221
+ if (seen.has(key)) continue;
10222
+ seen.add(key);
10223
+ out.push(t2);
10224
+ if (out.length >= INSTAGRAM_SCRAPE_MAX_SOURCES) break;
10225
+ }
10226
+ return out;
10227
+ }
10228
+ function clampInstagramFeaturedIndex(stored, count) {
10229
+ if (count <= 0) return 0;
10230
+ const n = typeof stored === "number" && Number.isFinite(stored) ? Math.trunc(stored) : 0;
10231
+ return Math.min(Math.max(n, 0), count - 1);
10232
+ }
10233
+ function urlStrings2(value) {
10234
+ return Array.isArray(value) ? value.filter((v) => typeof v === "string" && v.trim().length > 0) : [];
10235
+ }
10236
+ function featuredInstagramOutputs(json, featuredIndex) {
10237
+ if (!Array.isArray(json) || json.length === 0) return {};
10238
+ const post = json[clampInstagramFeaturedIndex(featuredIndex, json.length)];
10239
+ if (!post || typeof post !== "object") return {};
10240
+ const p = post;
10241
+ const text = typeof p.caption === "string" ? p.caption.trim() : "";
10242
+ const imageUrl = urlStrings2(p.images)[0] ?? urlStrings2(p.videoPreviews)[0];
10243
+ const videoUrl = urlStrings2(p.videos)[0];
10244
+ return {
10245
+ ...text ? { text } : {},
10246
+ ...imageUrl ? { imageUrl } : {},
10247
+ ...videoUrl ? { videoUrl } : {}
10248
+ };
10249
+ }
10250
+ function instagramScrapeSources(data) {
10251
+ return Math.max(1, Math.min(splitInstagramTargets(data.targets).length, INSTAGRAM_SCRAPE_MAX_SOURCES));
10252
+ }
10253
+ function instagramScrapeCreditIdFromNode(data) {
10254
+ const count = typeof data.count === "number" ? data.count : INSTAGRAM_SCRAPE_DEFAULT_COUNT;
10255
+ return buildInstagramScrapeCreditId({ count, sources: instagramScrapeSources(data), analysis: instagramAnalysisTierFrom(data) });
10256
+ }
10257
+ function resolveInstagramScrapeCreditId(body) {
10258
+ const raw = body;
10259
+ if (!raw || typeof raw !== "object") return INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID;
10260
+ const count = raw.count === void 0 ? INSTAGRAM_SCRAPE_DEFAULT_COUNT : raw.count;
10261
+ if (!isInstagramScrapeCount(count)) return INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID;
10262
+ const sources = splitInstagramTargets(raw.targets).length;
10263
+ if (sources < 1) return INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID;
10264
+ return buildInstagramScrapeCreditId({ count, sources, analysis: instagramAnalysisTierFrom(raw) });
10265
+ }
10266
+
9328
10267
  // src/condition-variables.ts
9329
10268
  var VARIABLES_HANDLE_ID = "variables";
9330
10269
  function buildConditionVariables(targetNodeId, edges, nodes, extractOutput) {
@@ -9373,11 +10312,11 @@ function spreadJsonArrayIfSingleton(items) {
9373
10312
  if (items.length !== 1) return items;
9374
10313
  const single = items[0];
9375
10314
  if (typeof single !== "string") return items;
9376
- const trimmed = single.trim();
9377
- if (!trimmed.startsWith("[")) return items;
10315
+ const trimmed2 = single.trim();
10316
+ if (!trimmed2.startsWith("[")) return items;
9378
10317
  let parsed;
9379
10318
  try {
9380
- parsed = JSON.parse(trimmed);
10319
+ parsed = JSON.parse(trimmed2);
9381
10320
  } catch {
9382
10321
  return items;
9383
10322
  }
@@ -10633,6 +11572,127 @@ var KINETIC_SET = new Set(KINETIC_CAPTION_STYLES);
10633
11572
  function isKineticCaptionStyle(style) {
10634
11573
  return style !== null && style !== void 0 && KINETIC_SET.has(style);
10635
11574
  }
11575
+ var CAPTION_LOOK_IDS = ["outline", "clean"];
11576
+ var DEFAULT_CAPTION_LOOK = "outline";
11577
+ var DEFAULT_SUBTITLE_LOOK = "clean";
11578
+ var KINETIC_ONLY_CAPTION_LEVER_KEYS = [
11579
+ "highlightColor",
11580
+ "animate"
11581
+ ];
11582
+ function captionRoutesToRemotion(input) {
11583
+ if (input.segments && input.segments.length > 0) return true;
11584
+ if (isKineticCaptionStyle(input.style)) return true;
11585
+ const isSet = (v) => v !== void 0 && v !== null;
11586
+ const hasStylingLever = isSet(input.look) || isSet(input.fontFamily) || isSet(input.fontWeight) || isSet(input.strokeColor) || isSet(input.strokeWidth) || isSet(input.uppercase) || isSet(input.positionY) || isSet(input.maxWordsPerLine);
11587
+ if (hasStylingLever) return true;
11588
+ if (input.transcript !== void 0 && input.transcript !== null) return true;
11589
+ if (input.captions && input.captions.length > 0) return true;
11590
+ if (!input.text) return true;
11591
+ return false;
11592
+ }
11593
+ var CAPTION_MAX_WORDS_PER_LINE_MIN = 1;
11594
+ var CAPTION_MAX_WORDS_PER_LINE_MAX = 20;
11595
+ var CAPTION_LEVER_BOUNDS = {
11596
+ fontSize: { min: 12, max: 200 },
11597
+ strokeWidth: { min: 0, max: 40 },
11598
+ positionY: { min: 0, max: 100 },
11599
+ fontWeight: { min: 100, max: 900 },
11600
+ maxWordsPerLine: { min: CAPTION_MAX_WORDS_PER_LINE_MIN, max: CAPTION_MAX_WORDS_PER_LINE_MAX }
11601
+ };
11602
+ var CAPTION_NUMERIC_LEVER_KEYS = Object.keys(CAPTION_LEVER_BOUNDS);
11603
+ function normalizeCaptionNumericLevers(input) {
11604
+ const out = { ...input };
11605
+ for (const key of CAPTION_NUMERIC_LEVER_KEYS) {
11606
+ if (!(key in out) || out[key] === void 0) continue;
11607
+ if (out[key] === null) {
11608
+ delete out[key];
11609
+ continue;
11610
+ }
11611
+ const raw = typeof out[key] === "string" && out[key].trim() !== "" ? Number(out[key]) : out[key];
11612
+ if (typeof raw !== "number" || !Number.isFinite(raw)) {
11613
+ delete out[key];
11614
+ continue;
11615
+ }
11616
+ const { min, max } = CAPTION_LEVER_BOUNDS[key];
11617
+ const shaped = key === "fontWeight" ? Math.round(raw / 100) * 100 : key === "maxWordsPerLine" ? Math.round(raw) : raw;
11618
+ out[key] = Math.min(max, Math.max(min, shaped));
11619
+ }
11620
+ return out;
11621
+ }
11622
+ function autoStrokeWidth(fontSize) {
11623
+ return Math.max(2, Math.round(fontSize * 0.1));
11624
+ }
11625
+ var CAPTION_LOOKS = {
11626
+ // The TikTok / CapCut read: heavy geometric sans, caps, white on a thick black
11627
+ // outline, yellow spoken word.
11628
+ outline: (fs) => ({
11629
+ fontFamily: "Montserrat",
11630
+ fontWeight: 900,
11631
+ uppercase: true,
11632
+ color: "#ffffff",
11633
+ strokeColor: "#000000",
11634
+ strokeWidth: autoStrokeWidth(fs),
11635
+ highlightColor: "#FFE600"
11636
+ }),
11637
+ // The pre-look lever set with the face pinned (it never was): per-style weight,
11638
+ // soft shadow only, no casing, no outline.
11639
+ clean: () => ({ fontFamily: "Inter", color: "#ffffff" })
11640
+ };
11641
+ function resolveCaptionLook(look, explicit, fontSize) {
11642
+ const preset = CAPTION_LOOKS[look ?? DEFAULT_CAPTION_LOOK] ?? CAPTION_LOOKS[DEFAULT_CAPTION_LOOK];
11643
+ const out = { ...preset(fontSize) };
11644
+ for (const k of Object.keys(explicit)) {
11645
+ if (explicit[k] !== void 0) out[k] = explicit[k];
11646
+ }
11647
+ return out;
11648
+ }
11649
+ function resolveCaptionLevers(style, look, explicit, fontSize) {
11650
+ const effective = look ?? (isKineticCaptionStyle(style) ? DEFAULT_CAPTION_LOOK : DEFAULT_SUBTITLE_LOOK);
11651
+ return resolveCaptionLook(effective, explicit, fontSize);
11652
+ }
11653
+
11654
+ // src/transcribe-preflight.ts
11655
+ function transcribeWordTimestampsRefusal(provider) {
11656
+ const lane = provider || DEFAULT_TRANSCRIBE_NODE_PROVIDER;
11657
+ if (transcribeLaneSupportsWordTimestamps(lane)) return null;
11658
+ return `the "${lane}" engine does not return word timings \u2014 pick ${transcribeProvidersWithWordTimestamps().join(" or ")}`;
11659
+ }
11660
+ var TRANSCRIBE_JSON_OUT = "json";
11661
+ var TRANSCRIPT_IN = "transcript";
11662
+ var APPLY_EDL_JSON_OUT = "json";
11663
+ function findWordlessTranscriptFeeds(nodes, edges) {
11664
+ const byId = new Map(nodes.map((n) => [n.id, n]));
11665
+ const isSkipped = (n) => !n || n.data?.skipped === true;
11666
+ const out = [];
11667
+ for (const node of nodes) {
11668
+ if (node.type !== "transcribe" || isSkipped(node)) continue;
11669
+ const provider = typeof node.data?.provider === "string" && node.data.provider || DEFAULT_TRANSCRIBE_NODE_PROVIDER;
11670
+ const refusal = transcribeWordTimestampsRefusal(provider);
11671
+ if (!refusal) continue;
11672
+ const seen = /* @__PURE__ */ new Set();
11673
+ const frontier = [{ id: node.id, outHandle: TRANSCRIBE_JSON_OUT }];
11674
+ while (frontier.length > 0) {
11675
+ const { id, outHandle } = frontier.pop();
11676
+ for (const e of edges) {
11677
+ if (e.source !== id || (e.sourceHandle ?? null) !== outHandle || e.targetHandle !== TRANSCRIPT_IN) continue;
11678
+ const target = byId.get(e.target);
11679
+ if (isSkipped(target)) continue;
11680
+ if (target.type === "add-captions") {
11681
+ out.push({
11682
+ transcribeNodeId: node.id,
11683
+ consumerNodeId: target.id,
11684
+ provider,
11685
+ message: `Captions need word timings, but ${refusal}.`
11686
+ });
11687
+ } else if (target.type === "apply-edl" && !seen.has(target.id)) {
11688
+ seen.add(target.id);
11689
+ frontier.push({ id: target.id, outHandle: APPLY_EDL_JSON_OUT });
11690
+ }
11691
+ }
11692
+ }
11693
+ }
11694
+ return out;
11695
+ }
10636
11696
 
10637
11697
  // src/i18n/types.ts
10638
11698
  var LANGUAGES = [
@@ -10784,6 +11844,9 @@ var EXECUTION_DATA_KEYS = /* @__PURE__ */ new Set([
10784
11844
  "__listTotal",
10785
11845
  "__listCompleted",
10786
11846
  "__listResults",
11847
+ // Row-aligned twin of __listResults (Extract Field, List output) — read only
11848
+ // by the fan-out so two lists cut from one array pair by row.
11849
+ "__alignedListResults",
10787
11850
  // List fan-out window flag (abandon-guard exemption). Set/cleared by
10788
11851
  // executeNodeForList — purely execution-related, never user-edited.
10789
11852
  "__listRunning",
@@ -10812,7 +11875,26 @@ var EXECUTION_DATA_KEYS = /* @__PURE__ */ new Set([
10812
11875
  // Collect (fan-in) execution snapshot.
10813
11876
  "lastInputs",
10814
11877
  "lastMeta",
10815
- "__upstreamCount"
11878
+ "__upstreamCount",
11879
+ // Video URL node — the download's live percent/phase, written on every
11880
+ // progress tick (~2/s). Pure run-state; also in TRANSIENT_RUNTIME_KEYS below.
11881
+ "downloadPercent",
11882
+ "downloadPhase",
11883
+ // Webhook Output's delivery receipt. A webhook target may reflect the
11884
+ // request back (httpbin, RequestBin, an API that 400s with "headers
11885
+ // received: …"), so `webhookResponseBody` can carry whatever the request
11886
+ // carried — with an attached credential, the secret itself. Listing the three
11887
+ // here is what keeps the receipt out of template exports (GENERATED_FIELDS
11888
+ // derives from this set), out of node presets, and out of undo history.
11889
+ "webhookSuccess",
11890
+ "webhookStatusCode",
11891
+ "webhookResponseBody",
11892
+ // When the editor's "Clear results" last emptied this node (ISO time). Not a
11893
+ // result and not config: bookkeeping that tells the load-time recovery lanes
11894
+ // "this node is empty ON PURPOSE" — without it, every reload reads an empty
11895
+ // node as "ran while the editor was closed" and paints the last run back.
11896
+ // Persisted (never transient): the reload is exactly when it is read.
11897
+ "resultsClearedAt"
10816
11898
  ]);
10817
11899
  var TRANSIENT_RUNTIME_KEYS = /* @__PURE__ */ new Set([
10818
11900
  "executionStatus",
@@ -10825,7 +11907,13 @@ var TRANSIENT_RUNTIME_KEYS = /* @__PURE__ */ new Set([
10825
11907
  "__listCompleted",
10826
11908
  "__listRunning",
10827
11909
  "_upstreamRefresh",
10828
- "__upstreamCount"
11910
+ "__upstreamCount",
11911
+ // Video URL node download ticks. They used to dirty the workflow twice a
11912
+ // second for the length of the download — the same phantom-save chain the
11913
+ // job-progress keys above were moved here to stop. What SURVIVES a reload is
11914
+ // `downloadStatus` + `downloadId`; the percent is re-read from the server.
11915
+ "downloadPercent",
11916
+ "downloadPhase"
10829
11917
  ]);
10830
11918
  function stripTransientRuntimeData(nodes) {
10831
11919
  return nodes.map((node) => {
@@ -10854,6 +11942,10 @@ var GENERATED_FIELDS = [
10854
11942
  "assetId"
10855
11943
  ];
10856
11944
  var NODE_EXTRA_FIELDS = {
11945
+ // A template must never import ARMED: the switch is the importer's to flip
11946
+ // (a schedule starts paused), and the rules themselves are config that
11947
+ // travels.
11948
+ "schedule-trigger": ["active"],
10857
11949
  character: ["expressions", "poses", "lightingVariations", "angles", "customVariations"],
10858
11950
  object: ["angles", "materials", "variations", "customVariations"],
10859
11951
  creature: ["angles", "poses", "variations", "customVariations"],
@@ -10877,8 +11969,27 @@ var NODE_EXTRA_FIELDS = {
10877
11969
  // unlinked rather than dangling at the exporter's workflow.
10878
11970
  "sub-workflow": ["referencedWorkflowId"]
10879
11971
  };
10880
- function stripExportContent(nodes) {
11972
+ var UNOWNED_REF_FIELDS = {
11973
+ "webhook-output": ["credentialId"],
11974
+ ...Object.fromEntries([...SOCIAL_POST_NODE_TYPES].map((type) => [type, ["connectionId"]]))
11975
+ };
11976
+ function stripUnownedRefs(nodes) {
10881
11977
  return nodes.map((node) => {
11978
+ const fields = UNOWNED_REF_FIELDS[node.type];
11979
+ if (!fields || !node.data) return node;
11980
+ const data = { ...node.data };
11981
+ let changed = false;
11982
+ for (const field of fields) {
11983
+ if (field in data) {
11984
+ delete data[field];
11985
+ changed = true;
11986
+ }
11987
+ }
11988
+ return changed ? { ...node, data } : node;
11989
+ });
11990
+ }
11991
+ function stripExportContent(nodes) {
11992
+ return stripUnownedRefs(nodes).map((node) => {
10882
11993
  const data = { ...node.data };
10883
11994
  for (const field of GENERATED_FIELDS) delete data[field];
10884
11995
  const extras = NODE_EXTRA_FIELDS[node.type] ?? [];
@@ -13408,6 +14519,81 @@ var SUNO_TRACK_SOURCE_TYPES = /* @__PURE__ */ new Set([
13408
14519
  "suno-upload-extend"
13409
14520
  ]);
13410
14521
 
14522
+ // src/video-link.ts
14523
+ var SOCIAL_VIDEO_HOSTS = [
14524
+ "youtube.com",
14525
+ "youtu.be",
14526
+ "tiktok.com",
14527
+ "instagram.com",
14528
+ "twitter.com",
14529
+ "x.com",
14530
+ "facebook.com",
14531
+ "fb.watch",
14532
+ "fb.com"
14533
+ ];
14534
+ var YOUTUBE_HOSTS = ["youtube.com", "youtu.be"];
14535
+ var INSTAGRAM_HOSTS = ["instagram.com"];
14536
+ var TIKTOK_HOSTS = ["tiktok.com"];
14537
+ var TWITTER_HOSTS = ["twitter.com", "x.com"];
14538
+ var FACEBOOK_HOSTS = ["facebook.com", "fb.watch", "fb.com"];
14539
+ function hostnameMatchesAllowlist(hostname, domains) {
14540
+ const h = hostname.toLowerCase().replace(/\.$/, "");
14541
+ return domains.some((d) => {
14542
+ const dom = d.toLowerCase();
14543
+ return h === dom || h.endsWith("." + dom);
14544
+ });
14545
+ }
14546
+ function hasUrlParserHazard(url) {
14547
+ for (let i = 0; i < url.length; i++) {
14548
+ const code = url.charCodeAt(i);
14549
+ if (code === 92 || code <= 31 || code === 127) return true;
14550
+ }
14551
+ return false;
14552
+ }
14553
+ function isSocialVideoUrl(url, domains = SOCIAL_VIDEO_HOSTS) {
14554
+ if (hasUrlParserHazard(url)) return false;
14555
+ try {
14556
+ const parsed = new URL(url);
14557
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false;
14558
+ return hostnameMatchesAllowlist(parsed.hostname, domains);
14559
+ } catch {
14560
+ return false;
14561
+ }
14562
+ }
14563
+ function detectVideoLinkPlatform(url) {
14564
+ if (isSocialVideoUrl(url, YOUTUBE_HOSTS)) return "youtube";
14565
+ if (isSocialVideoUrl(url, FACEBOOK_HOSTS)) return "facebook";
14566
+ if (isSocialVideoUrl(url, TIKTOK_HOSTS)) return "tiktok";
14567
+ if (isSocialVideoUrl(url, INSTAGRAM_HOSTS)) return "instagram";
14568
+ if (isSocialVideoUrl(url, TWITTER_HOSTS)) return "twitter";
14569
+ return "unknown";
14570
+ }
14571
+ var VIDEO_LINK_TOLERANT_CONSUMER_TYPES = /* @__PURE__ */ new Set([
14572
+ "suno-cover",
14573
+ "transcribe",
14574
+ "dubbing"
14575
+ ]);
14576
+ function trimmed(value) {
14577
+ if (typeof value !== "string") return void 0;
14578
+ const t2 = value.trim();
14579
+ return t2 === "" ? void 0 : t2;
14580
+ }
14581
+ function videoLinkDownloadedFile(data) {
14582
+ const file = trimmed(data.downloadedVideoUrl);
14583
+ if (!file) return void 0;
14584
+ const from = trimmed(data.downloadedFromUrl);
14585
+ if (from && from !== trimmed(data.youtubeUrl)) return void 0;
14586
+ return file;
14587
+ }
14588
+ function resolveVideoLinkOutput(data) {
14589
+ return videoLinkDownloadedFile(data) ?? trimmed(data.youtubeUrl);
14590
+ }
14591
+ function videoLinkNeedsDownload(data) {
14592
+ const url = trimmed(data.youtubeUrl);
14593
+ if (!url || !isSocialVideoUrl(url)) return false;
14594
+ return videoLinkDownloadedFile(data) === void 0;
14595
+ }
14596
+
13411
14597
  // src/voice-changer-models.ts
13412
14598
  var VOICE_CHANGER_MODELS = [
13413
14599
  {
@@ -14471,6 +15657,12 @@ var AGGREGATE_LANE_EFFECTIVE_TYPE = {
14471
15657
  "out-audio": "upload-audio",
14472
15658
  "out-text": "list"
14473
15659
  };
15660
+ var SCRAPER_HANDLE_EFFECTIVE_TYPE = {
15661
+ text: "combine-text",
15662
+ image: "upload-image",
15663
+ video: "upload-video"
15664
+ };
15665
+ var SCRAPER_SOURCE_TYPES = /* @__PURE__ */ new Set(["meta-ads-scrape", "instagram-scrape"]);
14474
15666
  function resolveEffectiveSourceType(rawSourceType, sourceHandleId) {
14475
15667
  if (sourceHandleId === "image" && ENTITY_IMAGE_HANDLE_TYPES.has(rawSourceType ?? "")) {
14476
15668
  return "upload-image";
@@ -14479,6 +15671,10 @@ function resolveEffectiveSourceType(rawSourceType, sourceHandleId) {
14479
15671
  const effective = AGGREGATE_LANE_EFFECTIVE_TYPE[sourceHandleId ?? ""];
14480
15672
  if (effective) return effective;
14481
15673
  }
15674
+ if (SCRAPER_SOURCE_TYPES.has(rawSourceType ?? "")) {
15675
+ const effective = SCRAPER_HANDLE_EFFECTIVE_TYPE[sourceHandleId ?? ""];
15676
+ if (effective) return effective;
15677
+ }
14482
15678
  return rawSourceType ?? "";
14483
15679
  }
14484
15680
  function sourceRefKey(nodeId, sourceHandleId, rawSourceType) {
@@ -14689,7 +15885,21 @@ var entitySlotSchema = zod.z.object({
14689
15885
  */
14690
15886
  refRejectedReason: zod.z.string().optional(),
14691
15887
  /** NON-default looks only; present only when at least one exists. */
14692
- variations: zod.z.array(slotVariationSchema).max(VIDEO_ANALYSIS_MAX_VARIATIONS).optional()
15888
+ variations: zod.z.array(slotVariationSchema).max(VIDEO_ANALYSIS_MAX_VARIATIONS).optional(),
15889
+ /**
15890
+ * WHOSE THIS OBJECT IS (2026-09-17). An object slot that is worn, held,
15891
+ * carried, driven or ridden by a cast person or creature names that slot
15892
+ * here, with the relation as a short passive phrase ending in "by" ("worn
15893
+ * by", "held by", "driven by"). The link says the object slot IS the one on
15894
+ * that person — not a second one: a recast that saw "Man in Blue Silk
15895
+ * Shirt" AND "Blue Silk Shirt" as unrelated slots rendered two shirts.
15896
+ * Object slots only; a free-standing prop, the product on a table, a place
15897
+ * or a person never carries it. Optional/additive: producers may omit it.
15898
+ */
15899
+ owner: zod.z.object({
15900
+ slotId: zod.z.string().min(1).regex(/^[a-z0-9-]+$/),
15901
+ relation: zod.z.string().min(1)
15902
+ }).optional()
14693
15903
  });
14694
15904
  var VIDEO_ANALYSIS_AUDIO_MODES = ["speech", "music", "sfx", "ambience"];
14695
15905
  var audioLayerSchema = zod.z.object({
@@ -15064,21 +16274,6 @@ function bucketSecondsFromAuditCreditId(id) {
15064
16274
  return m ? Number(m[1]) : null;
15065
16275
  }
15066
16276
 
15067
- // src/video-ui-defaults.ts
15068
- function uiAspectRatioFill(provider) {
15069
- return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider) ? "adaptive" : void 0;
15070
- }
15071
- function uiResolutionFill(provider) {
15072
- if (isWan3Provider(provider)) return PRICING_DEFAULT_RESOLUTION[provider];
15073
- if (isSeedance2Provider(provider)) return MODEL_CATALOG[provider]?.resolutions?.[0];
15074
- return void 0;
15075
- }
15076
- function uiDurationFill(provider) {
15077
- if (isWan3Provider(provider)) return 5;
15078
- if (isGeminiOmniProvider(provider)) return 8;
15079
- return void 0;
15080
- }
15081
-
15082
16277
  // src/smart-cut-windows.ts
15083
16278
  var SMART_CUT_WINDOW_MAX = 24;
15084
16279
  var SMART_CUT_WINDOW_MIN = 1;
@@ -17495,6 +18690,765 @@ function unavailable(engine) {
17495
18690
  }
17496
18691
  var SCENE3D_BASIC_SCHEMA_VERSION = SCENE3D_SCHEMA_VERSION;
17497
18692
 
18693
+ // src/video-output-canvas.ts
18694
+ var VIDEO_OUTPUT_CANVAS = {
18695
+ "seedance-2-5": {
18696
+ "480p": { "16:9": [854, 480], "9:16": [480, 854] },
18697
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280], "1:1": [960, 960] },
18698
+ "1080p": { "16:9": [1920, 1080] }
18699
+ },
18700
+ // The 2.0 family is NOT the same as 2.5 at 480p — 864x496 vs 854x480.
18701
+ "seedance-2": {
18702
+ "480p": { "16:9": [864, 496], "9:16": [496, 864] },
18703
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] }
18704
+ },
18705
+ "seedance-2-fast": {
18706
+ "480p": { "16:9": [864, 496], "9:16": [496, 864] },
18707
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] }
18708
+ },
18709
+ "seedance-2-mini": {
18710
+ "480p": { "16:9": [864, 496], "9:16": [496, 864] },
18711
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] }
18712
+ },
18713
+ "gemini-omni-video": {
18714
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] },
18715
+ "1080p": { "16:9": [1920, 1080] }
18716
+ },
18717
+ "gemini-omni-flash": {
18718
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] }
18719
+ },
18720
+ "veo3.1": {
18721
+ "720p": { "9:16": [720, 1280] },
18722
+ "1080p": { "16:9": [1920, 1080] }
18723
+ },
18724
+ "wan-3": {
18725
+ "480p": { "16:9": [832, 480] },
18726
+ "720p": { "16:9": [1280, 720], "9:16": [720, 1280] }
18727
+ },
18728
+ "wan-3-prime": {
18729
+ "720p": { "16:9": [1280, 720] }
18730
+ },
18731
+ // 768P's "9:16" is 0.5714, not 0.5625 — the single clearest reason this table
18732
+ // exists.
18733
+ "minimax-h3": {
18734
+ "768p": { "9:16": [768, 1344] },
18735
+ "2k": { "16:9": [2560, 1440], "9:16": [1440, 2560] }
18736
+ },
18737
+ seedance: {
18738
+ "1080p": {
18739
+ "16:9": [1920, 1080],
18740
+ "9:16": [1080, 1920],
18741
+ "1:1": [1440, 1440],
18742
+ "3:4": [1248, 1664]
18743
+ }
18744
+ }
18745
+ };
18746
+ function resolveOutputCanvas(provider, resolution, aspect) {
18747
+ if (!provider || !resolution || !aspect) return void 0;
18748
+ return VIDEO_OUTPUT_CANVAS[provider]?.[resolution.toLowerCase()]?.[aspect];
18749
+ }
18750
+ function measuredCanvasCombinations() {
18751
+ const out = [];
18752
+ for (const [provider, byResolution] of Object.entries(VIDEO_OUTPUT_CANVAS)) {
18753
+ for (const [resolution, byAspect] of Object.entries(byResolution)) {
18754
+ for (const [aspect, canvas] of Object.entries(byAspect)) {
18755
+ out.push({ provider, resolution, aspect, canvas });
18756
+ }
18757
+ }
18758
+ }
18759
+ return out;
18760
+ }
18761
+
18762
+ // src/video-frame-fit.ts
18763
+ var FRAME_FITS = ["original", "ratio", "resolution"];
18764
+ var DEFAULT_FRAME_FIT = "resolution";
18765
+ var FRAME_DELIVERIES = ["auto", "frame", "reference"];
18766
+ var DEFAULT_FRAME_DELIVERY = "auto";
18767
+ var FRAME_FIT_STRETCH_TOLERANCE = 0.05;
18768
+ var FRAME_DELIVERY_BY_PROVIDER = {
18769
+ "seedance-2": "reference",
18770
+ "seedance-2-fast": "reference",
18771
+ "seedance-2-mini": "reference"
18772
+ };
18773
+ var OPEN_ASPECT_TOKENS = /* @__PURE__ */ new Set(["adaptive", "auto"]);
18774
+ function parseAspectToken(token) {
18775
+ if (!token) return void 0;
18776
+ const m = /^(\d+(?:\.\d+)?)\s*[:x/]\s*(\d+(?:\.\d+)?)$/.exec(token.trim());
18777
+ if (!m) return void 0;
18778
+ const w = Number(m[1]);
18779
+ const h = Number(m[2]);
18780
+ if (!(w > 0) || !(h > 0)) return void 0;
18781
+ return w / h;
18782
+ }
18783
+ function resolveFrameFitAspect(args) {
18784
+ const requested = args.requestedAspect?.trim();
18785
+ if (requested && !OPEN_ASPECT_TOKENS.has(requested.toLowerCase())) return requested;
18786
+ const ratios = args.provider ? getModel(args.provider)?.aspectRatios : void 0;
18787
+ if (!ratios?.length || !(args.sourceWidth > 0) || !(args.sourceHeight > 0)) return void 0;
18788
+ const source = args.sourceWidth / args.sourceHeight;
18789
+ let best;
18790
+ for (const token of ratios) {
18791
+ const value = parseAspectToken(token);
18792
+ if (value === void 0) continue;
18793
+ const gap = Math.abs(Math.log(value / source));
18794
+ if (!best || gap < best.gap) best = { token, gap };
18795
+ }
18796
+ return best?.token;
18797
+ }
18798
+ function even(value) {
18799
+ return Math.max(2, Math.round(value / 2) * 2);
18800
+ }
18801
+ function minimalRatioDimensions(width, height, aspect) {
18802
+ const current = width / height;
18803
+ if (current > aspect) {
18804
+ return { width: even(width), height: even(width / aspect) };
18805
+ }
18806
+ return { width: even(height * aspect), height: even(height) };
18807
+ }
18808
+ function centreCropToAspect(width, height, aspect) {
18809
+ const current = width / height;
18810
+ if (current > aspect) {
18811
+ const w = even(height * aspect);
18812
+ return { left: Math.max(0, Math.round((width - w) / 2)), top: 0, width: Math.min(width, w), height };
18813
+ }
18814
+ const h = even(width / aspect);
18815
+ return { left: 0, top: Math.max(0, Math.round((height - h) / 2)), width, height: Math.min(height, h) };
18816
+ }
18817
+ function computeFrameFitPlan(args) {
18818
+ const { fit, sourceWidth, sourceHeight } = args;
18819
+ if (fit === "original") return null;
18820
+ if (!(sourceWidth > 0) || !(sourceHeight > 0)) return null;
18821
+ const aspectToken = resolveFrameFitAspect({
18822
+ provider: args.provider,
18823
+ requestedAspect: args.aspect,
18824
+ sourceWidth,
18825
+ sourceHeight
18826
+ });
18827
+ const canvas = fit === "resolution" ? args.canvas ?? resolveOutputCanvas(args.provider, args.resolution, aspectToken) : void 0;
18828
+ const targetAspect = canvas ? canvas[0] / canvas[1] : parseAspectToken(aspectToken);
18829
+ if (targetAspect === void 0 || !(targetAspect > 0)) return null;
18830
+ const sourceAspect = sourceWidth / sourceHeight;
18831
+ const gap = Math.abs(sourceAspect - targetAspect) / targetAspect;
18832
+ const tolerance = args.tolerance ?? FRAME_FIT_STRETCH_TOLERANCE;
18833
+ const crop = gap > tolerance ? centreCropToAspect(sourceWidth, sourceHeight, targetAspect) : void 0;
18834
+ const target = canvas ? { width: canvas[0], height: canvas[1] } : minimalRatioDimensions(
18835
+ crop ? crop.width : sourceWidth,
18836
+ crop ? crop.height : sourceHeight,
18837
+ targetAspect
18838
+ );
18839
+ const unchanged = target.width === sourceWidth && target.height === sourceHeight && !crop;
18840
+ if (unchanged) return null;
18841
+ return {
18842
+ width: target.width,
18843
+ height: target.height,
18844
+ ...crop ? { crop } : {},
18845
+ reason: canvas ? "resolution" : "ratio"
18846
+ };
18847
+ }
18848
+ function resolveFrameDelivery(args) {
18849
+ const requested = args.requested ?? DEFAULT_FRAME_DELIVERY;
18850
+ const wanted = requested === "auto" ? args.provider ? FRAME_DELIVERY_BY_PROVIDER[args.provider] ?? "frame" : "frame" : requested;
18851
+ if (wanted === "reference" && !args.supportsReferenceImages) return "frame";
18852
+ return wanted;
18853
+ }
18854
+
18855
+ // src/edl-multicam.ts
18856
+ var hasOwn = (o, k) => Object.prototype.hasOwnProperty.call(o, k);
18857
+ var isFiniteNumber = (v) => typeof v === "number" && Number.isFinite(v);
18858
+ function mergeEdlSourceOffsets(edl, offsets, opts) {
18859
+ const sources = Array.isArray(edl?.sources) ? edl.sources : [];
18860
+ const rows = offsets && typeof offsets === "object" ? offsets : {};
18861
+ const byId = /* @__PURE__ */ new Map();
18862
+ for (const s of sources) if (s && typeof s === "object" && !byId.has(s.id)) byId.set(s.id, s);
18863
+ let anchor;
18864
+ if (opts?.anchor !== void 0) {
18865
+ if (!byId.has(opts.anchor)) {
18866
+ return { edl: { ...edl }, applied: [], ignored: [{ sourceId: opts.anchor, reason: "anchor-unknown" }] };
18867
+ }
18868
+ anchor = opts.anchor;
18869
+ } else {
18870
+ const masters = sources.filter((s) => s && typeof s === "object" && s.role === "master-audio");
18871
+ if (masters.length === 1) anchor = masters[0].id;
18872
+ }
18873
+ let reference = 0;
18874
+ if (anchor !== void 0 && hasOwn(rows, anchor)) {
18875
+ const a = rows[anchor];
18876
+ if (!isFiniteNumber(a)) {
18877
+ return { edl: { ...edl }, anchor, applied: [], ignored: [{ sourceId: anchor, reason: "anchor-not-finite" }] };
18878
+ }
18879
+ reference = a;
18880
+ }
18881
+ const anchorOffsetMs = anchor !== void 0 ? byId.get(anchor)?.offsetMs ?? 0 : 0;
18882
+ const next = /* @__PURE__ */ new Map();
18883
+ const applied = [];
18884
+ const ignored = [];
18885
+ for (const sourceId of Object.keys(rows)) {
18886
+ if (sourceId === anchor) continue;
18887
+ if (!byId.has(sourceId)) {
18888
+ ignored.push({ sourceId, reason: "unknown-source" });
18889
+ continue;
18890
+ }
18891
+ const measured = rows[sourceId];
18892
+ const offsetMs = isFiniteNumber(measured) ? Math.round(anchor !== void 0 ? anchorOffsetMs + measured - reference : measured) : Number.NaN;
18893
+ if (!Number.isFinite(offsetMs)) {
18894
+ ignored.push({ sourceId, reason: "not-finite" });
18895
+ continue;
18896
+ }
18897
+ next.set(sourceId, offsetMs);
18898
+ applied.push(sourceId);
18899
+ }
18900
+ const merged = Array.isArray(edl?.sources) ? { ...edl, sources: edl.sources.map((s) => s && typeof s === "object" && next.has(s.id) ? { ...s, offsetMs: next.get(s.id) } : s) } : { ...edl };
18901
+ return { edl: merged, ...anchor !== void 0 ? { anchor } : {}, applied, ignored };
18902
+ }
18903
+ var EDL_FULL_FRAME = Object.freeze({ x: 0, y: 0, w: 1, h: 1 });
18904
+ function isInFrameRegion(r) {
18905
+ if (!r || typeof r !== "object") return false;
18906
+ const { x, y, w, h } = r;
18907
+ for (const v of [x, y, w, h]) if (!isFiniteNumber(v) || v < 0 || v > 1) return false;
18908
+ const box = r;
18909
+ return box.w > 0 && box.h > 0 && box.x + box.w <= 1 + 1e-9 && box.y + box.h <= 1 + 1e-9;
18910
+ }
18911
+ function resolveEdlSegmentSlots(edl, segment, opts) {
18912
+ if (!segment || typeof segment !== "object") return [];
18913
+ const sources = Array.isArray(edl?.sources) ? edl.sources : [];
18914
+ const layoutSlots = Array.isArray(segment.layout?.slots) ? segment.layout.slots : [];
18915
+ const slots = layoutSlots.length > 0 ? layoutSlots : typeof segment.video === "string" && segment.video ? [{ source: segment.video }] : [];
18916
+ const single = slots.length === 1;
18917
+ const out = [];
18918
+ for (const slot of slots) {
18919
+ if (!slot || typeof slot !== "object") continue;
18920
+ const source = slot.source;
18921
+ const speaker = slot.speaker ?? (single ? segment.speaker : void 0);
18922
+ const rungs = [
18923
+ ["slot", () => slot.region],
18924
+ ["segment", () => single ? segment.region : void 0],
18925
+ ["resolver", () => opts?.regionFor?.({ segment, source, ...speaker !== void 0 ? { speaker } : {} })],
18926
+ ["speaker", () => speaker === void 0 ? void 0 : Array.isArray(opts?.speakerRegions) ? opts.speakerRegions.find((row) => row && row.source === source && row.speaker === speaker)?.region : void 0],
18927
+ ["source", () => sources.find((s) => s && typeof s === "object" && s.id === source)?.region]
18928
+ ];
18929
+ let region = EDL_FULL_FRAME;
18930
+ let regionFrom = "full";
18931
+ for (const [from, read] of rungs) {
18932
+ const candidate = read();
18933
+ if (isInFrameRegion(candidate)) {
18934
+ region = candidate;
18935
+ regionFrom = from;
18936
+ break;
18937
+ }
18938
+ }
18939
+ out.push({
18940
+ source,
18941
+ region,
18942
+ regionFrom,
18943
+ ...speaker !== void 0 ? { speaker } : {},
18944
+ ...slot.weight !== void 0 ? { weight: slot.weight } : {}
18945
+ });
18946
+ }
18947
+ return out;
18948
+ }
18949
+
18950
+ // src/speaker-layouts.ts
18951
+ var EDL_TARGET_ASPECTS = ["16:9", "9:16", "1:1", "4:5"];
18952
+ var TARGET_ASPECT_SET = new Set(EDL_TARGET_ASPECTS);
18953
+ function isEdlTargetAspect(v) {
18954
+ return typeof v === "string" && TARGET_ASPECT_SET.has(v);
18955
+ }
18956
+ var SPEAKER_LAYOUTS = [
18957
+ { id: "single", minSlots: 1, maxSlots: 1, aspects: EDL_TARGET_ASPECTS },
18958
+ { id: "side-by-side", minSlots: 2, maxSlots: 2, aspects: ["16:9", "1:1"] },
18959
+ { id: "stacked", minSlots: 2, maxSlots: 2, aspects: ["9:16", "4:5", "1:1"] },
18960
+ { id: "grid", minSlots: 2, maxSlots: 6, aspects: EDL_TARGET_ASPECTS },
18961
+ { id: "pip", minSlots: 2, maxSlots: 2, aspects: EDL_TARGET_ASPECTS }
18962
+ ];
18963
+ var SPEAKER_LAYOUT_IDS = SPEAKER_LAYOUTS.map((l) => l.id);
18964
+ var LAYOUTS_BY_ID = new Map(SPEAKER_LAYOUTS.map((l) => [l.id, l]));
18965
+ function getSpeakerLayout(id) {
18966
+ return LAYOUTS_BY_ID.get(id);
18967
+ }
18968
+ function speakerLayoutAllows(sheet, q) {
18969
+ if (q.aspect !== void 0 && !sheet.aspects.includes(q.aspect)) return false;
18970
+ if (q.slotCount !== void 0 && !(q.slotCount >= sheet.minSlots && q.slotCount <= sheet.maxSlots)) return false;
18971
+ return true;
18972
+ }
18973
+ var XFADE_SWITCH_PREFIX = "xfade:";
18974
+ function speakerSwitchOverlaps(type) {
18975
+ return typeof type === "string" && type.startsWith(XFADE_SWITCH_PREFIX);
18976
+ }
18977
+ var switchSheet = (id, requiresSameSource) => ({
18978
+ id,
18979
+ overlaps: speakerSwitchOverlaps(id),
18980
+ requiresSameSource
18981
+ });
18982
+ var SPEAKER_SWITCHES = [
18983
+ switchSheet("cut", false),
18984
+ switchSheet("pan", true),
18985
+ switchSheet("zoom", false),
18986
+ ...COMBINE_TRANSITIONS.filter((t2) => t2.xfade !== null).map((t2) => switchSheet(XFADE_SWITCH_PREFIX + t2.id, false))
18987
+ ];
18988
+ var SPEAKER_SWITCH_IDS = SPEAKER_SWITCHES.map((s) => s.id);
18989
+ var SWITCHES_BY_ID = new Map(SPEAKER_SWITCHES.map((s) => [s.id, s]));
18990
+ function getSpeakerSwitch(id) {
18991
+ return SWITCHES_BY_ID.get(id);
18992
+ }
18993
+ var SPEAKER_EMPHASIS_STYLES = ["none", "scale", "border", "dim"];
18994
+ var EMPHASIS_STYLE_SET = new Set(SPEAKER_EMPHASIS_STYLES);
18995
+ function parseSpeakerEmphasisStyle(style) {
18996
+ if (typeof style !== "string") return [];
18997
+ return style.split("+").map((atom) => atom.trim()).filter((atom) => atom.length > 0);
18998
+ }
18999
+ function isKnownSpeakerEmphasisStyle(style) {
19000
+ const atoms = parseSpeakerEmphasisStyle(style);
19001
+ if (atoms.length === 0 || !atoms.every((atom) => EMPHASIS_STYLE_SET.has(atom))) return false;
19002
+ if (new Set(atoms).size !== atoms.length) return false;
19003
+ return !(atoms.includes("none") && atoms.length > 1);
19004
+ }
19005
+ var isObject = (v) => !!v && typeof v === "object";
19006
+ function speakerPresentationWarnings(edl) {
19007
+ const warnings = [];
19008
+ if (!isObject(edl)) return warnings;
19009
+ const safe = {
19010
+ ...edl,
19011
+ sources: Array.isArray(edl.sources) ? edl.sources : [],
19012
+ segments: Array.isArray(edl.segments) ? edl.segments : []
19013
+ };
19014
+ const rawAspect = isObject(safe.meta) ? safe.meta.targetAspect : void 0;
19015
+ const aspect = isEdlTargetAspect(rawAspect) ? rawAspect : void 0;
19016
+ if (rawAspect != null && aspect === void 0) {
19017
+ warnings.push(`meta.targetAspect "${String(rawAspect)}" is not a known target aspect (known: ${EDL_TARGET_ASPECTS.join(", ")})`);
19018
+ }
19019
+ safe.segments.forEach((seg, i) => {
19020
+ if (!isObject(seg) || !isObject(seg.layout)) return;
19021
+ const at = `segment[${i}] "${seg.id}"`;
19022
+ const layout = seg.layout;
19023
+ const sheet = typeof layout.mode === "string" ? getSpeakerLayout(layout.mode) : void 0;
19024
+ if (!sheet) {
19025
+ warnings.push(`${at}: unknown layout mode "${String(layout.mode)}" (known: ${SPEAKER_LAYOUT_IDS.join(", ")})`);
19026
+ } else {
19027
+ const slotCount = Array.isArray(layout.slots) ? layout.slots.length : 0;
19028
+ if (slotCount > 0 && !speakerLayoutAllows(sheet, { slotCount })) {
19029
+ const range = sheet.minSlots === sheet.maxSlots ? `${sheet.minSlots}` : `${sheet.minSlots}\u2013${sheet.maxSlots}`;
19030
+ warnings.push(`${at}: layout "${sheet.id}" takes ${range} slot(s), got ${slotCount}`);
19031
+ }
19032
+ if (aspect !== void 0 && !speakerLayoutAllows(sheet, { aspect })) {
19033
+ warnings.push(`${at}: layout "${sheet.id}" is not drawn for targetAspect ${aspect} (drawn for: ${sheet.aspects.join(", ")})`);
19034
+ }
19035
+ }
19036
+ if (isObject(layout.transition)) {
19037
+ const type = layout.transition.type;
19038
+ const sw = typeof type === "string" ? getSpeakerSwitch(type) : void 0;
19039
+ if (!sw) {
19040
+ warnings.push(`${at}: unknown layout transition "${String(type)}" (known: ${SPEAKER_SWITCHES.filter((s) => !s.overlaps).map((s) => s.id).join(", ")}, or ${XFADE_SWITCH_PREFIX}<id> for a combine-videos transition that is a real ffmpeg xfade \u2014 never ${XFADE_SWITCH_PREFIX}cut)`);
19041
+ } else if (sw.requiresSameSource && i > 0) {
19042
+ const prev = safe.segments[i - 1];
19043
+ const cur = resolveEdlSegmentSlots(safe, seg);
19044
+ const before = isObject(prev) ? resolveEdlSegmentSlots(safe, prev) : [];
19045
+ if (cur.length === 1 && before.length === 1 && cur[0].source !== before[0].source) {
19046
+ warnings.push(`${at}: switch "${sw.id}" moves within ONE picture source, but the previous segment shows "${before[0].source}" and this one "${cur[0].source}"`);
19047
+ }
19048
+ }
19049
+ }
19050
+ if (isObject(layout.emphasis) && !isKnownSpeakerEmphasisStyle(layout.emphasis.style)) {
19051
+ const style = String(layout.emphasis.style);
19052
+ const atoms = parseSpeakerEmphasisStyle(layout.emphasis.style);
19053
+ warnings.push(atoms.length > 0 && atoms.every((a) => EMPHASIS_STYLE_SET.has(a)) ? `${at}: emphasis style "${style}" \u2014 "none" must stand alone and no style may repeat` : `${at}: unknown emphasis style "${style}" (a "+"-joined set of: ${SPEAKER_EMPHASIS_STYLES.join(", ")})`);
19054
+ }
19055
+ });
19056
+ return warnings;
19057
+ }
19058
+
19059
+ // src/edl.ts
19060
+ var EDL_VERSION = 1;
19061
+ var EDL_SOURCE_ROLES = ["master-audio", "camera", "wide", "screen"];
19062
+ var KNOWN_SOURCE_ROLES = new Set(EDL_SOURCE_ROLES);
19063
+ function transcriptDurationSec(transcript) {
19064
+ if (!transcript || typeof transcript !== "object") return void 0;
19065
+ const t2 = transcript;
19066
+ let maxEndMs = 0;
19067
+ const scan = (rows) => {
19068
+ if (!Array.isArray(rows)) return;
19069
+ for (const row of rows) {
19070
+ const endMs = row?.endMs;
19071
+ if (typeof endMs === "number" && Number.isFinite(endMs) && endMs > maxEndMs) {
19072
+ maxEndMs = endMs;
19073
+ }
19074
+ }
19075
+ };
19076
+ scan(t2.words);
19077
+ scan(t2.segments);
19078
+ return maxEndMs > 0 ? maxEndMs / 1e3 : void 0;
19079
+ }
19080
+ function segmentTransitionOverlaps(t2) {
19081
+ return !!t2 && t2.type === "crossfade" && (t2.durationMs ?? 0) > 0;
19082
+ }
19083
+ function layoutTransitionOverlaps(t2) {
19084
+ return !!t2 && speakerSwitchOverlaps(t2.type) && (t2.durationMs ?? 0) > 0;
19085
+ }
19086
+ function overlapMsInto(seg) {
19087
+ if (segmentTransitionOverlaps(seg.transition)) return seg.transition.durationMs ?? 0;
19088
+ if (layoutTransitionOverlaps(seg.layout?.transition)) return seg.layout.transition.durationMs ?? 0;
19089
+ return 0;
19090
+ }
19091
+ function edlDurationMs(edl) {
19092
+ const starts = segmentOutputStarts(edl);
19093
+ if (starts.length === 0) return 0;
19094
+ const last = edl.segments[edl.segments.length - 1];
19095
+ return Math.max(0, Math.round(starts[starts.length - 1] + Math.max(0, last.outMs - last.inMs)));
19096
+ }
19097
+ function segmentOutputStarts(edl) {
19098
+ const starts = [];
19099
+ let cursor = 0;
19100
+ edl.segments.forEach((seg, i) => {
19101
+ if (i > 0) cursor -= overlapMsInto(seg);
19102
+ starts.push(Math.max(0, Math.round(cursor)));
19103
+ cursor += Math.max(0, seg.outMs - seg.inMs);
19104
+ });
19105
+ return starts;
19106
+ }
19107
+ var inRange = (v, lo = 0, hi = 1) => v >= lo && v <= hi;
19108
+ function regionIssues(r, where) {
19109
+ const out = [];
19110
+ for (const [k, v] of Object.entries(r)) {
19111
+ if (!Number.isFinite(v) || !inRange(v)) out.push(`${where}: region.${k}=${v} out of 0..1`);
19112
+ }
19113
+ if (r.w <= 0 || r.h <= 0) out.push(`${where}: region has non-positive w/h`);
19114
+ if (r.x + r.w > 1 + 1e-9) out.push(`${where}: region extends past right edge (x+w>1)`);
19115
+ if (r.y + r.h > 1 + 1e-9) out.push(`${where}: region extends past bottom edge (y+h>1)`);
19116
+ return out;
19117
+ }
19118
+ function validateEdl(edl) {
19119
+ const issues = [];
19120
+ const warnings = [];
19121
+ if (!Array.isArray(edl.segments) || !Array.isArray(edl.sources)) {
19122
+ edl = {
19123
+ ...edl,
19124
+ sources: Array.isArray(edl.sources) ? edl.sources : [],
19125
+ segments: Array.isArray(edl.segments) ? edl.segments : []
19126
+ };
19127
+ }
19128
+ if (edl.version !== EDL_VERSION) issues.push(`version must be ${EDL_VERSION}`);
19129
+ if (edl.clock !== "master" && edl.clock !== "output") issues.push(`clock must be "master" or "output"`);
19130
+ const sourceIds = /* @__PURE__ */ new Set();
19131
+ let masterAudioCount = 0;
19132
+ for (const s of edl.sources) {
19133
+ if (sourceIds.has(s.id)) issues.push(`duplicate source id "${s.id}"`);
19134
+ sourceIds.add(s.id);
19135
+ if (!s.url || !s.url.trim()) issues.push(`source "${s.id}": url is empty (media resolves from url)`);
19136
+ if (s.role === "master-audio") masterAudioCount++;
19137
+ else if (s.role != null && !KNOWN_SOURCE_ROLES.has(s.role)) {
19138
+ warnings.push(`source "${s.id}": unknown role "${s.role}" (known: ${EDL_SOURCE_ROLES.join(", ")})`);
19139
+ }
19140
+ if (s.region) issues.push(...regionIssues(s.region, `source "${s.id}"`));
19141
+ if (s.offsetMs !== void 0 && !Number.isFinite(s.offsetMs)) issues.push(`source "${s.id}": offsetMs not finite`);
19142
+ }
19143
+ if (masterAudioCount > 1) issues.push(`more than one source has role:"master-audio" (${masterAudioCount})`);
19144
+ if (edl.segments.length === 0) issues.push("segments is empty");
19145
+ edl.segments.forEach((seg, i) => {
19146
+ const at = `segment[${i}] "${seg.id}"`;
19147
+ if (!(seg.outMs > seg.inMs)) issues.push(`${at}: outMs (${seg.outMs}) must be > inMs (${seg.inMs})`);
19148
+ if (seg.inMs < 0) issues.push(`${at}: inMs negative`);
19149
+ if (seg.video && !sourceIds.has(seg.video)) issues.push(`${at}: video source "${seg.video}" not in sources`);
19150
+ else if (seg.video) {
19151
+ const vs = edl.sources.find((s) => s.id === seg.video);
19152
+ if (vs && vs.kind !== "video") issues.push(`${at}: video source "${seg.video}" is kind:"${vs.kind}", must be video`);
19153
+ }
19154
+ if (seg.audio && !sourceIds.has(seg.audio)) issues.push(`${at}: audio source "${seg.audio}" not in sources`);
19155
+ if (!seg.audio && masterAudioCount === 0 && !seg.video) {
19156
+ issues.push(`${at}: no audio source and no master-audio/video fallback`);
19157
+ }
19158
+ if (i === 0 && (seg.transition || seg.layout?.transition)) {
19159
+ issues.push(`${at}: segments[0] cannot have a transition ("into this segment" has no predecessor)`);
19160
+ }
19161
+ if (seg.transition && seg.layout?.transition) {
19162
+ issues.push(`${at}: both EdlSegment.transition and EdlLayout.transition set (pick one)`);
19163
+ }
19164
+ const ov = overlapMsInto(seg);
19165
+ if (ov > 0 && i > 0) {
19166
+ const prev = edl.segments[i - 1];
19167
+ const minAdj = Math.min(seg.outMs - seg.inMs, prev.outMs - prev.inMs);
19168
+ if (ov > 0.9 * minAdj + 1e-9) {
19169
+ issues.push(`${at}: overlap transition durationMs (${ov}) exceeds 0.9\xB7min(adjacent segment)=${(0.9 * minAdj).toFixed(1)} \u2014 ffmpeg xfade would error / be clamped`);
19170
+ }
19171
+ }
19172
+ if (seg.region) {
19173
+ issues.push(...regionIssues(seg.region, at));
19174
+ if (seg.layout?.slots && seg.layout.slots.length > 1) {
19175
+ issues.push(`${at}: segment.region is invalid when the layout has >1 slot (put the region on the slot)`);
19176
+ }
19177
+ }
19178
+ for (const slot of seg.layout?.slots ?? []) {
19179
+ if (!sourceIds.has(slot.source)) issues.push(`${at}: slot source "${slot.source}" not in sources`);
19180
+ else {
19181
+ const src = edl.sources.find((s) => s.id === slot.source);
19182
+ if (src && src.kind !== "video") issues.push(`${at}: slot source "${slot.source}" is kind:"${src.kind}", slots must be video`);
19183
+ }
19184
+ if (slot.weight !== void 0 && !inRange(slot.weight)) issues.push(`${at}: slot.weight=${slot.weight} out of 0..1`);
19185
+ if (slot.region) issues.push(...regionIssues(slot.region, `${at} slot "${slot.source}"`));
19186
+ }
19187
+ });
19188
+ for (const d of edl.dropped ?? []) {
19189
+ if (!(d.outMs > d.inMs)) issues.push(`dropped range [${d.inMs},${d.outMs}) is not positive`);
19190
+ for (const seg of edl.segments) {
19191
+ if (seg.inMs < d.outMs && d.inMs < seg.outMs) {
19192
+ issues.push(`dropped range [${d.inMs},${d.outMs}) overlaps kept segment "${seg.id}" [${seg.inMs},${seg.outMs})`);
19193
+ break;
19194
+ }
19195
+ }
19196
+ }
19197
+ warnings.push(...speakerPresentationWarnings(edl));
19198
+ return { ok: issues.length === 0, issues, warnings };
19199
+ }
19200
+ function validateEdlClipSet(set) {
19201
+ const issues = [];
19202
+ const warnings = [];
19203
+ if (set.version !== EDL_VERSION) issues.push(`clipset version must be ${EDL_VERSION}`);
19204
+ if (set.clips.length === 0) issues.push("clipset has no clips");
19205
+ set.clips.forEach((clip, i) => {
19206
+ const r = validateEdl(clip);
19207
+ if (!r.ok) issues.push(...r.issues.map((m) => `clip[${i}]: ${m}`));
19208
+ warnings.push(...r.warnings.map((m) => `clip[${i}]: ${m}`));
19209
+ });
19210
+ return { ok: issues.length === 0, issues, warnings };
19211
+ }
19212
+ function offsetFor(edl, sourceId) {
19213
+ if (!sourceId) return 0;
19214
+ return edl.sources.find((s) => s.id === sourceId)?.offsetMs ?? 0;
19215
+ }
19216
+ function remapMsThroughEdl(edl, sourceMs, sourceId) {
19217
+ const masterMs = sourceMs + offsetFor(edl, sourceId);
19218
+ const starts = segmentOutputStarts(edl);
19219
+ for (let i = 0; i < edl.segments.length; i++) {
19220
+ const seg = edl.segments[i];
19221
+ if (masterMs >= seg.inMs && masterMs < seg.outMs) {
19222
+ return Math.round(starts[i] + (masterMs - seg.inMs));
19223
+ }
19224
+ }
19225
+ return null;
19226
+ }
19227
+ function remapTranscriptThroughEdl(edl, transcript) {
19228
+ const off = offsetFor(edl, transcript.sourceId);
19229
+ const starts = segmentOutputStarts(edl);
19230
+ const mapWord = (w) => {
19231
+ const startMaster = w.startMs + off;
19232
+ const endMaster = w.endMs + off;
19233
+ if (startMaster === endMaster) {
19234
+ for (let i = 0; i < edl.segments.length; i++) {
19235
+ const seg = edl.segments[i];
19236
+ if (startMaster >= seg.inMs && startMaster < seg.outMs) {
19237
+ const out = Math.round(starts[i] + (startMaster - seg.inMs));
19238
+ return { ...w, startMs: out, endMs: out };
19239
+ }
19240
+ }
19241
+ return null;
19242
+ }
19243
+ for (let i = 0; i < edl.segments.length; i++) {
19244
+ const seg = edl.segments[i];
19245
+ const lo = Math.max(startMaster, seg.inMs);
19246
+ const hi = Math.min(endMaster, seg.outMs);
19247
+ if (lo < hi) {
19248
+ return {
19249
+ ...w,
19250
+ startMs: Math.round(starts[i] + (lo - seg.inMs)),
19251
+ endMs: Math.round(starts[i] + (hi - seg.inMs))
19252
+ };
19253
+ }
19254
+ }
19255
+ return null;
19256
+ };
19257
+ const words = [];
19258
+ for (const w of transcript.words) {
19259
+ const mapped = mapWord(w);
19260
+ if (mapped) words.push(mapped);
19261
+ }
19262
+ const mapSegment = (s) => {
19263
+ const startMaster = s.startMs + off;
19264
+ const endMaster = s.endMs + off;
19265
+ let outLo = null;
19266
+ let outHi = null;
19267
+ for (let i = 0; i < edl.segments.length; i++) {
19268
+ const seg = edl.segments[i];
19269
+ const lo = Math.max(startMaster, seg.inMs);
19270
+ const hi = Math.min(endMaster, seg.outMs);
19271
+ if (lo < hi) {
19272
+ const a = Math.round(starts[i] + (lo - seg.inMs));
19273
+ const b = Math.round(starts[i] + (hi - seg.inMs));
19274
+ if (outLo === null || a < outLo) outLo = a;
19275
+ if (outHi === null || b > outHi) outHi = b;
19276
+ }
19277
+ }
19278
+ if (outLo === null || outHi === null) return null;
19279
+ return { ...s, startMs: outLo, endMs: outHi };
19280
+ };
19281
+ const segments = transcript.segments?.map(mapSegment).filter((s) => s !== null);
19282
+ return { ...transcript, words, ...segments ? { segments } : {} };
19283
+ }
19284
+ function speakerTurns(transcript, opts) {
19285
+ const turns = [];
19286
+ for (const w of transcript.words) {
19287
+ const speaker = w.speaker ?? "spk";
19288
+ const last = turns[turns.length - 1];
19289
+ if (last && last.speaker === speaker && w.startMs - last.endMs <= opts.mergeGapMs) {
19290
+ last.endMs = Math.max(last.endMs, w.endMs);
19291
+ } else {
19292
+ turns.push({ speaker, startMs: w.startMs, endMs: w.endMs });
19293
+ }
19294
+ }
19295
+ return turns.filter((t2) => t2.endMs - t2.startMs >= opts.minTurnMs);
19296
+ }
19297
+ var num = (v, fallback = 0) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
19298
+ var clamp012 = (v) => Math.min(1, Math.max(0, v));
19299
+ var str2 = (v) => typeof v === "string" ? v : void 0;
19300
+ function normalizeRegion(r) {
19301
+ if (!r || typeof r !== "object") return void 0;
19302
+ const o = r;
19303
+ if (["x", "y", "w", "h"].some((k) => typeof o[k] !== "number")) return void 0;
19304
+ const x = clamp012(num(o.x));
19305
+ const y = clamp012(num(o.y));
19306
+ const w = Math.min(clamp012(num(o.w)), 1 - x);
19307
+ const h = Math.min(clamp012(num(o.h)), 1 - y);
19308
+ if (w <= 0 || h <= 0) return void 0;
19309
+ return { x, y, w, h };
19310
+ }
19311
+ function normalizeEdl(input) {
19312
+ const o = input && typeof input === "object" ? input : {};
19313
+ const sources = Array.isArray(o.sources) ? o.sources.map((raw, i) => {
19314
+ const s = raw ?? {};
19315
+ const src = {
19316
+ id: str2(s.id) ?? `src-${i}`,
19317
+ url: str2(s.url) ?? "",
19318
+ kind: s.kind === "audio" ? "audio" : "video",
19319
+ ...s.offsetMs !== void 0 ? { offsetMs: Math.round(num(s.offsetMs)) } : {},
19320
+ ...str2(s.role) ? { role: s.role } : {},
19321
+ ...Array.isArray(s.speakers) ? { speakers: s.speakers.filter((x) => typeof x === "string") } : {},
19322
+ ...normalizeRegion(s.region) ? { region: normalizeRegion(s.region) } : {}
19323
+ };
19324
+ return src;
19325
+ }) : [];
19326
+ const segments = Array.isArray(o.segments) ? o.segments.map((raw, i) => {
19327
+ const s = raw ?? {};
19328
+ const region = normalizeRegion(s.region);
19329
+ const isFirst = i === 0;
19330
+ const t2 = isFirst ? void 0 : s.transition;
19331
+ const layout = normalizeLayout(s.layout, isFirst);
19332
+ const seg = {
19333
+ id: str2(s.id) ?? `seg-${i}`,
19334
+ inMs: Math.round(num(s.inMs)),
19335
+ outMs: Math.round(num(s.outMs)),
19336
+ ...str2(s.video) ? { video: str2(s.video) } : {},
19337
+ ...str2(s.audio) ? { audio: str2(s.audio) } : {},
19338
+ ...str2(s.speaker) ? { speaker: str2(s.speaker) } : {},
19339
+ ...t2 && (t2.type === "cut" || t2.type === "crossfade") ? { transition: { type: t2.type, durationMs: t2.type === "cut" ? 0 : Math.round(num(t2.durationMs)) } } : {},
19340
+ ...region ? { region } : {},
19341
+ ...layout ? { layout } : {},
19342
+ ...Array.isArray(s.labels) ? { labels: s.labels.filter((x) => typeof x === "string") } : {}
19343
+ };
19344
+ return seg;
19345
+ }) : [];
19346
+ const dropped = Array.isArray(o.dropped) ? o.dropped.map((raw) => {
19347
+ const d = raw ?? {};
19348
+ return { inMs: Math.round(num(d.inMs)), outMs: Math.round(num(d.outMs)), reason: str2(d.reason) ?? "manual" };
19349
+ }) : void 0;
19350
+ const meta = o.meta && typeof o.meta === "object" ? o.meta : void 0;
19351
+ return {
19352
+ version: EDL_VERSION,
19353
+ clock: o.clock === "output" ? "output" : "master",
19354
+ sources,
19355
+ segments,
19356
+ ...dropped ? { dropped } : {},
19357
+ ...o.derivedFrom && typeof o.derivedFrom === "object" ? { derivedFrom: { edlId: str2(o.derivedFrom.edlId) ?? "", clock: "output" } } : {},
19358
+ ...meta ? { meta } : {}
19359
+ };
19360
+ }
19361
+ function normalizeLayout(input, dropTransition = false) {
19362
+ if (!input || typeof input !== "object") return void 0;
19363
+ const o = input;
19364
+ const mode = str2(o.mode) || "single";
19365
+ const slots = Array.isArray(o.slots) ? o.slots.map((raw) => {
19366
+ const s = raw ?? {};
19367
+ const source = str2(s.source);
19368
+ if (!source) return null;
19369
+ const region = normalizeRegion(s.region);
19370
+ return {
19371
+ source,
19372
+ ...region ? { region } : {},
19373
+ ...str2(s.speaker) ? { speaker: str2(s.speaker) } : {},
19374
+ ...s.weight !== void 0 ? { weight: clamp012(num(s.weight)) } : {}
19375
+ };
19376
+ }).filter((x) => x !== null) : void 0;
19377
+ const emphasis = o.emphasis && typeof o.emphasis === "object" ? { style: str2(o.emphasis.style) ?? "none", durationMs: Math.round(num(o.emphasis.durationMs)) } : void 0;
19378
+ const transition = !dropTransition && o.transition && typeof o.transition === "object" ? { type: str2(o.transition.type) ?? "cut", durationMs: Math.round(num(o.transition.durationMs)) } : void 0;
19379
+ return {
19380
+ mode,
19381
+ ...slots ? { slots } : {},
19382
+ ...emphasis ? { emphasis } : {},
19383
+ ...transition ? { transition } : {}
19384
+ };
19385
+ }
19386
+ function normalizeTranscript(input) {
19387
+ const o = input && typeof input === "object" ? input : {};
19388
+ const words = Array.isArray(o.words) ? o.words.map((raw) => {
19389
+ const w = raw ?? {};
19390
+ const startMs = Math.round(num(w.startMs));
19391
+ return {
19392
+ text: str2(w.text) ?? "",
19393
+ startMs,
19394
+ // Never inverted: an endMs < startMs (garbage upstream) would be
19395
+ // silently dropped at remap; clamp it to a non-negative width.
19396
+ endMs: Math.max(startMs, Math.round(num(w.endMs))),
19397
+ ...str2(w.speaker) ? { speaker: str2(w.speaker) } : {},
19398
+ ...typeof w.confidence === "number" ? { confidence: w.confidence } : {}
19399
+ };
19400
+ }) : [];
19401
+ const segments = Array.isArray(o.segments) ? o.segments.map((raw) => {
19402
+ const s = raw ?? {};
19403
+ const startMs = Math.round(num(s.startMs));
19404
+ return { startMs, endMs: Math.max(startMs, Math.round(num(s.endMs))), text: str2(s.text) ?? "", ...str2(s.speaker) ? { speaker: str2(s.speaker) } : {} };
19405
+ }) : void 0;
19406
+ return {
19407
+ version: EDL_VERSION,
19408
+ ...str2(o.sourceId) ? { sourceId: str2(o.sourceId) } : {},
19409
+ ...str2(o.language) ? { language: str2(o.language) } : {},
19410
+ words,
19411
+ ...segments ? { segments } : {}
19412
+ };
19413
+ }
19414
+
19415
+ // src/edit-plan-contract.ts
19416
+ var EDIT_PLAN_MODES = ["tighten", "clips", "chapters"];
19417
+ var EDIT_PLAN_TIERS = ["economy", "standard", "premium"];
19418
+ var EDIT_PLAN_BUCKET_MINUTES = [15, 30, 60, 90, 120, 180];
19419
+ var EDIT_PLAN_MAX_MINUTES = 180;
19420
+ var EDIT_PLAN_DEFAULT_CLIP_COUNT = 8;
19421
+ var EDIT_PLAN_MAX_CLIP_COUNT = 50;
19422
+ function clampEditPlanClipCount(count) {
19423
+ if (typeof count !== "number" || !Number.isFinite(count) || count <= 0) return void 0;
19424
+ return Math.min(EDIT_PLAN_MAX_CLIP_COUNT, Math.max(1, Math.floor(count)));
19425
+ }
19426
+ var EDIT_PLAN_BASE_CREDIT_ID = "edit-plan";
19427
+ function editPlanBucketMinutes(durationSec) {
19428
+ const secs = typeof durationSec === "number" && Number.isFinite(durationSec) ? durationSec : EDIT_PLAN_MAX_MINUTES * 60;
19429
+ const mins = Math.max(1, Math.ceil(secs / 60));
19430
+ const capped = Math.min(mins, EDIT_PLAN_MAX_MINUTES);
19431
+ for (const b of EDIT_PLAN_BUCKET_MINUTES) if (capped <= b) return b;
19432
+ return EDIT_PLAN_BUCKET_MINUTES[EDIT_PLAN_BUCKET_MINUTES.length - 1];
19433
+ }
19434
+ function buildEditPlanCreditId(mode, tier, durationSec) {
19435
+ return `edit-plan:${mode}:${tier}:${editPlanBucketMinutes(durationSec)}m`;
19436
+ }
19437
+ function asEditPlanMode(v) {
19438
+ return v === "clips" || v === "chapters" ? v : "tighten";
19439
+ }
19440
+ function asEditPlanTier(v) {
19441
+ return v === "economy" || v === "premium" ? v : "standard";
19442
+ }
19443
+ function unwrapEditPlanOutput(outputData) {
19444
+ if (!outputData || typeof outputData !== "object") return outputData;
19445
+ const o = outputData;
19446
+ if (Array.isArray(o.clips)) return o.clips;
19447
+ if (Array.isArray(o.chapters)) return { version: EDL_VERSION, chapters: o.chapters };
19448
+ const { viaNodaroCloud: _viaNodaroCloud, ...rest } = o;
19449
+ return rest;
19450
+ }
19451
+
17498
19452
  exports.ACCESS_LEVELS = ACCESS_LEVELS;
17499
19453
  exports.ACTIVE_SCENE_HELPERS = ACTIVE_SCENE_HELPERS;
17500
19454
  exports.ADVANCED_MODE_UNAVAILABLE_REASON = ADVANCED_MODE_UNAVAILABLE_REASON;
@@ -17532,6 +19486,11 @@ exports.BOARD_TO_COLUMN = BOARD_TO_COLUMN;
17532
19486
  exports.BOARD_VARIANTS = BOARD_VARIANTS;
17533
19487
  exports.BridgeToNextSceneInputSchema = BridgeToNextSceneInputSchema;
17534
19488
  exports.BridgeToNextSceneResultSchema = BridgeToNextSceneResultSchema;
19489
+ exports.CAPTION_LEVER_BOUNDS = CAPTION_LEVER_BOUNDS;
19490
+ exports.CAPTION_LOOKS = CAPTION_LOOKS;
19491
+ exports.CAPTION_LOOK_IDS = CAPTION_LOOK_IDS;
19492
+ exports.CAPTION_MAX_WORDS_PER_LINE_MAX = CAPTION_MAX_WORDS_PER_LINE_MAX;
19493
+ exports.CAPTION_MAX_WORDS_PER_LINE_MIN = CAPTION_MAX_WORDS_PER_LINE_MIN;
17535
19494
  exports.CATEGORY_DURATION_DEFAULTS = CATEGORY_DURATION_DEFAULTS;
17536
19495
  exports.CHARACTER_ASPECT_DEFAULTS = CHARACTER_ASPECT_DEFAULTS;
17537
19496
  exports.CHARACTER_ASPECT_OPTIONS = CHARACTER_ASPECT_OPTIONS;
@@ -17578,10 +19537,13 @@ exports.CharacterMetadataSchema = CharacterMetadataSchema;
17578
19537
  exports.ChatTurnResponseSchema = ChatTurnResponseSchema;
17579
19538
  exports.CriticIssueSchema = CriticIssueSchema;
17580
19539
  exports.DEFAULT_AUDIO_CROSSFADE_CURVE_ID = DEFAULT_AUDIO_CROSSFADE_CURVE_ID;
19540
+ exports.DEFAULT_CAPTION_LOOK = DEFAULT_CAPTION_LOOK;
17581
19541
  exports.DEFAULT_CARRIED_FRACTION = DEFAULT_CARRIED_FRACTION;
17582
19542
  exports.DEFAULT_CHARACTER_ANGLE_COUNT = DEFAULT_CHARACTER_ANGLE_COUNT;
17583
19543
  exports.DEFAULT_CHARACTER_EXPRESSION_COUNT = DEFAULT_CHARACTER_EXPRESSION_COUNT;
17584
19544
  exports.DEFAULT_CHARACTER_FACET = DEFAULT_CHARACTER_FACET;
19545
+ exports.DEFAULT_FRAME_DELIVERY = DEFAULT_FRAME_DELIVERY;
19546
+ exports.DEFAULT_FRAME_FIT = DEFAULT_FRAME_FIT;
17585
19547
  exports.DEFAULT_LABEL_BY_SOURCE = DEFAULT_LABEL_BY_SOURCE;
17586
19548
  exports.DEFAULT_LOCATION_USAGE_MODE = DEFAULT_LOCATION_USAGE_MODE;
17587
19549
  exports.DEFAULT_OVERLAY_QR = DEFAULT_OVERLAY_QR;
@@ -17590,8 +19552,11 @@ exports.DEFAULT_OVERLAY_TEXT = DEFAULT_OVERLAY_TEXT;
17590
19552
  exports.DEFAULT_PANEL_COUNT = DEFAULT_PANEL_COUNT;
17591
19553
  exports.DEFAULT_REF_IMAGE_MAX = DEFAULT_REF_IMAGE_MAX;
17592
19554
  exports.DEFAULT_SECTIONS = DEFAULT_SECTIONS;
19555
+ exports.DEFAULT_SUBTITLE_LOOK = DEFAULT_SUBTITLE_LOOK;
17593
19556
  exports.DEFAULT_SUNO_MODEL = DEFAULT_SUNO_MODEL;
17594
19557
  exports.DEFAULT_TEMPLATE_CATEGORY = DEFAULT_TEMPLATE_CATEGORY;
19558
+ exports.DEFAULT_TRANSCRIBE_NODE_PROVIDER = DEFAULT_TRANSCRIBE_NODE_PROVIDER;
19559
+ exports.DEFAULT_TRANSCRIBE_PROVIDER = DEFAULT_TRANSCRIBE_PROVIDER;
17595
19560
  exports.DEFAULT_USAGE_MODE = DEFAULT_USAGE_MODE;
17596
19561
  exports.DEFAULT_VIDEO_ANALYSIS_MODEL = DEFAULT_VIDEO_ANALYSIS_MODEL;
17597
19562
  exports.DEFAULT_VIDEO_ANALYSIS_TIER = DEFAULT_VIDEO_ANALYSIS_TIER;
@@ -17604,6 +19569,17 @@ exports.DETAIL_VARIANTS = DETAIL_VARIANTS;
17604
19569
  exports.DURATION_PRICED_PROVIDERS = DURATION_PRICED_PROVIDERS;
17605
19570
  exports.DYNAMIC_PRODUCER_TYPES = DYNAMIC_PRODUCER_TYPES;
17606
19571
  exports.DetectionResultSchema = DetectionResultSchema;
19572
+ exports.EDIT_PLAN_BASE_CREDIT_ID = EDIT_PLAN_BASE_CREDIT_ID;
19573
+ exports.EDIT_PLAN_BUCKET_MINUTES = EDIT_PLAN_BUCKET_MINUTES;
19574
+ exports.EDIT_PLAN_DEFAULT_CLIP_COUNT = EDIT_PLAN_DEFAULT_CLIP_COUNT;
19575
+ exports.EDIT_PLAN_MAX_CLIP_COUNT = EDIT_PLAN_MAX_CLIP_COUNT;
19576
+ exports.EDIT_PLAN_MAX_MINUTES = EDIT_PLAN_MAX_MINUTES;
19577
+ exports.EDIT_PLAN_MODES = EDIT_PLAN_MODES;
19578
+ exports.EDIT_PLAN_TIERS = EDIT_PLAN_TIERS;
19579
+ exports.EDL_FULL_FRAME = EDL_FULL_FRAME;
19580
+ exports.EDL_SOURCE_ROLES = EDL_SOURCE_ROLES;
19581
+ exports.EDL_TARGET_ASPECTS = EDL_TARGET_ASPECTS;
19582
+ exports.EDL_VERSION = EDL_VERSION;
17607
19583
  exports.EFFORT_TIER_BUMP = EFFORT_TIER_BUMP;
17608
19584
  exports.EMOTIONAL_BEAT = EMOTIONAL_BEAT;
17609
19585
  exports.ENTITY_ASPECT_DEFAULTS = ENTITY_ASPECT_DEFAULTS;
@@ -17634,6 +19610,10 @@ exports.FILM_BASE_CREDITS = FILM_BASE_CREDITS;
17634
19610
  exports.FLEXIBLE_INPUT_LIP_SYNC_PROVIDERS = FLEXIBLE_INPUT_LIP_SYNC_PROVIDERS;
17635
19611
  exports.FLUX2_RES_MP = FLUX2_RES_MP;
17636
19612
  exports.FLUX_LORA_CHARACTER_MODEL_ID = FLUX_LORA_CHARACTER_MODEL_ID;
19613
+ exports.FRAME_DELIVERIES = FRAME_DELIVERIES;
19614
+ exports.FRAME_DELIVERY_BY_PROVIDER = FRAME_DELIVERY_BY_PROVIDER;
19615
+ exports.FRAME_FITS = FRAME_FITS;
19616
+ exports.FRAME_FIT_STRETCH_TOLERANCE = FRAME_FIT_STRETCH_TOLERANCE;
17637
19617
  exports.FRAME_MODE_ADAPTIVE_ONLY_ASPECT = FRAME_MODE_ADAPTIVE_ONLY_ASPECT;
17638
19618
  exports.FRAME_TARGET_HANDLES = FRAME_TARGET_HANDLES;
17639
19619
  exports.FREECUT_EXPORT_COMPLETE = FREECUT_EXPORT_COMPLETE;
@@ -17683,8 +19663,20 @@ exports.IMAGE_REF_TYPES = IMAGE_REF_TYPES;
17683
19663
  exports.IMAGE_TO_VIDEO_PROVIDERS = IMAGE_TO_VIDEO_PROVIDERS;
17684
19664
  exports.INPUT_FIELD_MAP = INPUT_FIELD_MAP2;
17685
19665
  exports.INPUT_NODE_TYPES = INPUT_NODE_TYPES;
19666
+ exports.INSTAGRAM_ANALYSIS_CREDIT_ID = INSTAGRAM_ANALYSIS_CREDIT_ID;
17686
19667
  exports.INSTAGRAM_CAROUSEL_MAX_ITEMS = INSTAGRAM_CAROUSEL_MAX_ITEMS;
17687
19668
  exports.INSTAGRAM_CAROUSEL_MIN_ITEMS = INSTAGRAM_CAROUSEL_MIN_ITEMS;
19669
+ exports.INSTAGRAM_HOSTS = INSTAGRAM_HOSTS;
19670
+ exports.INSTAGRAM_SCRAPE_CREDIT_COSTS = INSTAGRAM_SCRAPE_CREDIT_COSTS;
19671
+ exports.INSTAGRAM_SCRAPE_DEFAULT_COUNT = INSTAGRAM_SCRAPE_DEFAULT_COUNT;
19672
+ exports.INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID = INSTAGRAM_SCRAPE_FALLBACK_CREDIT_ID;
19673
+ exports.INSTAGRAM_SCRAPE_MAX_COUNT = INSTAGRAM_SCRAPE_MAX_COUNT;
19674
+ exports.INSTAGRAM_SCRAPE_MAX_SOURCES = INSTAGRAM_SCRAPE_MAX_SOURCES;
19675
+ exports.INSTAGRAM_SCRAPE_MAX_TARGET_LENGTH = INSTAGRAM_SCRAPE_MAX_TARGET_LENGTH;
19676
+ exports.INSTAGRAM_SCRAPE_MODES = INSTAGRAM_SCRAPE_MODES;
19677
+ exports.INSTAGRAM_SCRAPE_NODE_TYPE = INSTAGRAM_SCRAPE_NODE_TYPE;
19678
+ exports.INSTAGRAM_SCRAPE_PERIODS = INSTAGRAM_SCRAPE_PERIODS;
19679
+ exports.INSTAGRAM_SCRAPE_TIERS = INSTAGRAM_SCRAPE_TIERS;
17688
19680
  exports.ITER_CLONE_PATTERN = ITER_CLONE_PATTERN;
17689
19681
  exports.ImageCriticIssueSchema = ImageCriticIssueSchema;
17690
19682
  exports.ImageCriticResultSchema = ImageCriticResultSchema;
@@ -17693,6 +19685,7 @@ exports.ImprovePromptInputSchema = ImprovePromptInputSchema;
17693
19685
  exports.ImprovePromptResultSchema = ImprovePromptResultSchema;
17694
19686
  exports.KEYFRAME_CREDITS_PER_SHOT = KEYFRAME_CREDITS_PER_SHOT;
17695
19687
  exports.KINETIC_CAPTION_STYLES = KINETIC_CAPTION_STYLES;
19688
+ exports.KINETIC_ONLY_CAPTION_LEVER_KEYS = KINETIC_ONLY_CAPTION_LEVER_KEYS;
17696
19689
  exports.LANGUAGES = LANGUAGES;
17697
19690
  exports.LEGACY_LOTTIE_HOST_REMAP = LEGACY_LOTTIE_HOST_REMAP;
17698
19691
  exports.LEGACY_TEMPLATE_CATEGORIES = LEGACY_TEMPLATE_CATEGORIES;
@@ -17731,6 +19724,27 @@ exports.MAX_PANELS_PER_SHEET = MAX_PANELS_PER_SHEET;
17731
19724
  exports.MAX_TTS_CHARS_BY_PROVIDER = MAX_TTS_CHARS_BY_PROVIDER;
17732
19725
  exports.MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER = MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER;
17733
19726
  exports.MEMBER_STATUSES = MEMBER_STATUSES;
19727
+ exports.META_ADS_ADVERTISER_MAX_RESULTS = META_ADS_ADVERTISER_MAX_RESULTS;
19728
+ exports.META_ADS_ANALYSIS_CREDITS_PER_AD = META_ADS_ANALYSIS_CREDITS_PER_AD;
19729
+ exports.META_ADS_ANALYSIS_CREDIT_ID = META_ADS_ANALYSIS_CREDIT_ID;
19730
+ exports.META_ADS_ANALYSIS_FOCUS_MAX = META_ADS_ANALYSIS_FOCUS_MAX;
19731
+ exports.META_ADS_ANALYSIS_TIERS = META_ADS_ANALYSIS_TIERS;
19732
+ exports.META_ADS_FORMATS = META_ADS_FORMATS;
19733
+ exports.META_ADS_NODE_MODES = META_ADS_NODE_MODES;
19734
+ exports.META_ADS_PLATFORMS = META_ADS_PLATFORMS;
19735
+ exports.META_ADS_SCRAPE_COUNT_OPTIONS = META_ADS_SCRAPE_COUNT_OPTIONS;
19736
+ exports.META_ADS_SCRAPE_CREDIT_COSTS = META_ADS_SCRAPE_CREDIT_COSTS;
19737
+ exports.META_ADS_SCRAPE_DEFAULT_COUNT = META_ADS_SCRAPE_DEFAULT_COUNT;
19738
+ exports.META_ADS_SCRAPE_DEFAULT_COUNTRY = META_ADS_SCRAPE_DEFAULT_COUNTRY;
19739
+ exports.META_ADS_SCRAPE_FALLBACK_CREDIT_ID = META_ADS_SCRAPE_FALLBACK_CREDIT_ID;
19740
+ exports.META_ADS_SCRAPE_MAX_COUNT = META_ADS_SCRAPE_MAX_COUNT;
19741
+ exports.META_ADS_SCRAPE_MAX_QUERY_LENGTH = META_ADS_SCRAPE_MAX_QUERY_LENGTH;
19742
+ exports.META_ADS_SCRAPE_MAX_SOURCES = META_ADS_SCRAPE_MAX_SOURCES;
19743
+ exports.META_ADS_SCRAPE_MODES = META_ADS_SCRAPE_MODES;
19744
+ exports.META_ADS_SCRAPE_NODE_TYPE = META_ADS_SCRAPE_NODE_TYPE;
19745
+ exports.META_ADS_SCRAPE_PERIODS = META_ADS_SCRAPE_PERIODS;
19746
+ exports.META_ADS_SCRAPE_STATUSES = META_ADS_SCRAPE_STATUSES;
19747
+ exports.META_ADS_SCRAPE_TIERS = META_ADS_SCRAPE_TIERS;
17734
19748
  exports.MINIMAX_H3_DEFAULT_RESOLUTION = MINIMAX_H3_DEFAULT_RESOLUTION;
17735
19749
  exports.MINIMAX_H3_PROVIDERS = MINIMAX_H3_PROVIDERS;
17736
19750
  exports.MODELS_WITH_REFERENCE_IMAGE_SUPPORT = MODELS_WITH_REFERENCE_IMAGE_SUPPORT;
@@ -17756,6 +19770,7 @@ exports.NODE_MAPPABLE_FIELDS = NODE_MAPPABLE_FIELDS;
17756
19770
  exports.NODE_PRESET_EXPORT_KIND = NODE_PRESET_EXPORT_KIND;
17757
19771
  exports.NODE_REF_PATTERN = NODE_REF_PATTERN;
17758
19772
  exports.NON_EN_LOCALE_IDS = NON_EN_LOCALE_IDS;
19773
+ exports.NON_PROMPT_TEXT_LANES = NON_PROMPT_TEXT_LANES;
17759
19774
  exports.NO_SPLIT_DELIMITER = NO_SPLIT_DELIMITER;
17760
19775
  exports.OBJECT_ASPECT_DEFAULTS = OBJECT_ASPECT_DEFAULTS;
17761
19776
  exports.OBJECT_ASPECT_OPTIONS = OBJECT_ASPECT_OPTIONS;
@@ -17828,6 +19843,7 @@ exports.PRO3D_RENDER_PROMPT_MAX = PRO3D_RENDER_PROMPT_MAX;
17828
19843
  exports.PRO3D_RENDER_QUALITY_PROFILES = PRO3D_RENDER_QUALITY_PROFILES;
17829
19844
  exports.PRO3D_RENDER_SOURCE_KINDS = PRO3D_RENDER_SOURCE_KINDS;
17830
19845
  exports.PRO3D_RENDER_STYLES = PRO3D_RENDER_STYLES;
19846
+ exports.PROJECTED_TRIGGER_NODE_TYPES = PROJECTED_TRIGGER_NODE_TYPES;
17831
19847
  exports.PROMPT_HARD_CEILING = PROMPT_HARD_CEILING;
17832
19848
  exports.PROMPT_PREFIX_KEY = PROMPT_PREFIX_KEY;
17833
19849
  exports.PROMPT_SUFFIX_KEY = PROMPT_SUFFIX_KEY;
@@ -17846,6 +19862,7 @@ exports.PipelineStateSchema = PipelineStateSchema;
17846
19862
  exports.PipelineStatusSchema = PipelineStatusSchema;
17847
19863
  exports.PresetSettingsSchema = PresetSettingsSchema;
17848
19864
  exports.QA_CHECK_PROVIDERS = QA_CHECK_PROVIDERS;
19865
+ exports.REASONING_OUTPUT_FLOOR = REASONING_OUTPUT_FLOOR;
17849
19866
  exports.REDUCE_STRATEGIES = REDUCE_STRATEGIES;
17850
19867
  exports.REDUCE_STRATEGY_IDS = REDUCE_STRATEGY_IDS;
17851
19868
  exports.REFERENCE_BOARD_PROVIDERS = REFERENCE_BOARD_PROVIDERS;
@@ -17908,6 +19925,9 @@ exports.SCENE3D_V2_LIMITS = SCENE3D_V2_LIMITS;
17908
19925
  exports.SCENE3D_V2_OVERRIDE_OPERATION_VERSION = SCENE3D_V2_OVERRIDE_OPERATION_VERSION;
17909
19926
  exports.SCENE3D_V2_PRIMITIVES = SCENE3D_V2_PRIMITIVES;
17910
19927
  exports.SCENE_HELPER_NAMES = SCENE_HELPER_NAMES;
19928
+ exports.SCHEDULE_EVERY_LIMITS = SCHEDULE_EVERY_LIMITS;
19929
+ exports.SCHEDULE_RULE_KINDS = SCHEDULE_RULE_KINDS;
19930
+ exports.SCHEDULE_TRIGGER_NODE_TYPE = SCHEDULE_TRIGGER_NODE_TYPE;
17911
19931
  exports.SCRAPER_ACTOR_LABELS = SCRAPER_ACTOR_LABELS;
17912
19932
  exports.SCRAPER_CREDIT_COSTS = SCRAPER_CREDIT_COSTS;
17913
19933
  exports.SCRAPER_OUTPUT_FIELDS = SCRAPER_OUTPUT_FIELDS;
@@ -17923,6 +19943,8 @@ exports.SEEDANCE_2_R2V_MAX_AUDIO_SEC_BY_PROVIDER = SEEDANCE_2_R2V_MAX_AUDIO_SEC_
17923
19943
  exports.SEEDANCE_2_R2V_MIN_REF_VIDEO_SEC = SEEDANCE_2_R2V_MIN_REF_VIDEO_SEC;
17924
19944
  exports.SEEDANCE_2_REF_LIMITS = SEEDANCE_2_REF_LIMITS;
17925
19945
  exports.SEEDANCE_LIP_SYNC_PROVIDERS = SEEDANCE_LIP_SYNC_PROVIDERS;
19946
+ exports.SEEDANCE_VIDEO_EDIT_PROVIDERS = SEEDANCE_VIDEO_EDIT_PROVIDERS;
19947
+ exports.SEEDANCE_VIDEO_EDIT_SHAPE = SEEDANCE_VIDEO_EDIT_SHAPE;
17926
19948
  exports.SEED_SUPPORT = SEED_SUPPORT;
17927
19949
  exports.SEPARATOR_DISPLAY = SEPARATOR_DISPLAY;
17928
19950
  exports.SEPARATOR_PRESETS = SEPARATOR_PRESETS;
@@ -17939,6 +19961,12 @@ exports.SMART_CUT_WINDOW_DEFAULT = SMART_CUT_WINDOW_DEFAULT;
17939
19961
  exports.SMART_CUT_WINDOW_MAX = SMART_CUT_WINDOW_MAX;
17940
19962
  exports.SMART_CUT_WINDOW_MIN = SMART_CUT_WINDOW_MIN;
17941
19963
  exports.SOCIAL_POST_NODE_TYPES = SOCIAL_POST_NODE_TYPES;
19964
+ exports.SOCIAL_VIDEO_HOSTS = SOCIAL_VIDEO_HOSTS;
19965
+ exports.SPEAKER_EMPHASIS_STYLES = SPEAKER_EMPHASIS_STYLES;
19966
+ exports.SPEAKER_LAYOUTS = SPEAKER_LAYOUTS;
19967
+ exports.SPEAKER_LAYOUT_IDS = SPEAKER_LAYOUT_IDS;
19968
+ exports.SPEAKER_SWITCHES = SPEAKER_SWITCHES;
19969
+ exports.SPEAKER_SWITCH_IDS = SPEAKER_SWITCH_IDS;
17942
19970
  exports.STAGE_PATCH_SCHEMA = STAGE_PATCH_SCHEMA;
17943
19971
  exports.STATIC_CAPTION_STYLES = STATIC_CAPTION_STYLES;
17944
19972
  exports.STRUCTURAL_SECTIONS = STRUCTURAL_SECTIONS;
@@ -17979,6 +20007,7 @@ exports.StyleDirectivesSchema = StyleDirectivesSchema;
17979
20007
  exports.SubGateNameSchema = SubGateNameSchema;
17980
20008
  exports.T2I_TO_I2I_VARIANT = T2I_TO_I2I_VARIANT;
17981
20009
  exports.TASK_CHAINED_EDIT_PROVIDERS = TASK_CHAINED_EDIT_PROVIDERS;
20010
+ exports.TELEGRAM_TRIGGER_NODE_TYPE = TELEGRAM_TRIGGER_NODE_TYPE;
17982
20011
  exports.TEMPLATE_CATEGORIES = TEMPLATE_CATEGORIES;
17983
20012
  exports.TEXT_TO_AUDIO_PROVIDERS = TEXT_TO_AUDIO_PROVIDERS;
17984
20013
  exports.TEXT_TO_VIDEO_PROVIDERS = TEXT_TO_VIDEO_PROVIDERS;
@@ -17987,7 +20016,9 @@ exports.TIER_PIPELINE_PARALLELISM = TIER_PIPELINE_PARALLELISM;
17987
20016
  exports.TILT_CARRIED_FRACTION = TILT_CARRIED_FRACTION;
17988
20017
  exports.TOPAZ_DEFAULT_UPSCALE_FACTOR = TOPAZ_DEFAULT_UPSCALE_FACTOR;
17989
20018
  exports.TOPAZ_UPSCALE_FACTORS = TOPAZ_UPSCALE_FACTORS;
20019
+ exports.TRANSCRIBE_LANES = TRANSCRIBE_LANES;
17990
20020
  exports.TRANSCRIBE_PROVIDERS = TRANSCRIBE_PROVIDERS;
20021
+ exports.TRANSCRIBE_PROVIDER_CAPABILITIES = TRANSCRIBE_PROVIDER_CAPABILITIES;
17991
20022
  exports.TRANSIENT_RUNTIME_KEYS = TRANSIENT_RUNTIME_KEYS;
17992
20023
  exports.TTS_PROVIDERS = TTS_PROVIDERS;
17993
20024
  exports.TTS_TEXT_MAX = TTS_TEXT_MAX;
@@ -18036,19 +20067,23 @@ exports.VIDEO_CRITIC_FRAME_MODES = VIDEO_CRITIC_FRAME_MODES;
18036
20067
  exports.VIDEO_CRITIC_MAX_RETRIES = VIDEO_CRITIC_MAX_RETRIES;
18037
20068
  exports.VIDEO_CRITIC_METADATA_KEYS = VIDEO_CRITIC_METADATA_KEYS;
18038
20069
  exports.VIDEO_CRITIC_MIN_ADHERENCE_SCORE = VIDEO_CRITIC_MIN_ADHERENCE_SCORE;
20070
+ exports.VIDEO_DURATION_AUTO = VIDEO_DURATION_AUTO;
18039
20071
  exports.VIDEO_DURATION_TIERS = VIDEO_DURATION_TIERS;
18040
20072
  exports.VIDEO_GEN_COLLAPSED_T2V_IDS = VIDEO_GEN_COLLAPSED_T2V_IDS;
18041
20073
  exports.VIDEO_GEN_PROVIDERS = VIDEO_GEN_PROVIDERS;
18042
20074
  exports.VIDEO_INPUT_LIP_SYNC_PROVIDERS = VIDEO_INPUT_LIP_SYNC_PROVIDERS;
20075
+ exports.VIDEO_LINK_TOLERANT_CONSUMER_TYPES = VIDEO_LINK_TOLERANT_CONSUMER_TYPES;
18043
20076
  exports.VIDEO_MODEL_CAPS = VIDEO_MODEL_CAPS;
18044
20077
  exports.VIDEO_MODE_ALIASES = VIDEO_MODE_ALIASES;
18045
20078
  exports.VIDEO_ONLY_PARAMETER_NODE_TYPES = VIDEO_ONLY_PARAMETER_NODE_TYPES;
20079
+ exports.VIDEO_OUTPUT_CANVAS = VIDEO_OUTPUT_CANVAS;
18046
20080
  exports.VIDEO_PRODUCER_TYPES = VIDEO_PRODUCER_TYPES;
18047
20081
  exports.VIDEO_PROMPT_MAX = VIDEO_PROMPT_MAX;
18048
20082
  exports.VIDEO_PROVIDERS_REQUIRING_IMAGE = VIDEO_PROVIDERS_REQUIRING_IMAGE;
18049
20083
  exports.VIDEO_PROVIDERS_WITHOUT_DISPATCH = VIDEO_PROVIDERS_WITHOUT_DISPATCH;
18050
20084
  exports.VIDEO_REF_LIMITS_BY_PROVIDER = VIDEO_REF_LIMITS_BY_PROVIDER;
18051
20085
  exports.VIDEO_REF_VIDEO_DURATION_LIMITS = VIDEO_REF_VIDEO_DURATION_LIMITS;
20086
+ exports.VIDEO_TO_VIDEO_NODE_PROVIDERS = VIDEO_TO_VIDEO_NODE_PROVIDERS;
18052
20087
  exports.VIDEO_TO_VIDEO_PROVIDERS = VIDEO_TO_VIDEO_PROVIDERS;
18053
20088
  exports.VIDEO_UPSCALE_PROVIDERS = VIDEO_UPSCALE_PROVIDERS;
18054
20089
  exports.VIDEO_UTIL_PRICING = VIDEO_UTIL_PRICING;
@@ -18066,13 +20101,17 @@ exports.WARDROBE_VARIANTS = WARDROBE_VARIANTS;
18066
20101
  exports.WEAPONS = WEAPONS;
18067
20102
  exports.WEAPON_SUBCATEGORY_LABELS = WEAPON_SUBCATEGORY_LABELS;
18068
20103
  exports.WEAPON_SUBCATEGORY_ORDER = WEAPON_SUBCATEGORY_ORDER;
20104
+ exports.WEBHOOK_TRIGGER_NODE_TYPE = WEBHOOK_TRIGGER_NODE_TYPE;
18069
20105
  exports.WORKFLOW_VISIBILITIES = WORKFLOW_VISIBILITIES;
18070
20106
  exports.WORKSPACE_HEADER = WORKSPACE_HEADER;
18071
20107
  exports.WORKSPACE_HEADER_LOWER = WORKSPACE_HEADER_LOWER;
18072
20108
  exports.WORKSPACE_ROLES = WORKSPACE_ROLES;
18073
20109
  exports.WorkspaceSettingsSchema = WorkspaceSettingsSchema;
20110
+ exports.YOUTUBE_HOSTS = YOUTUBE_HOSTS;
20111
+ exports.adCreativeAnalysisFrom = adCreativeAnalysisFrom;
18074
20112
  exports.aggregateByType = aggregateByType;
18075
20113
  exports.aiAvatarReserveCreditId = aiAvatarReserveCreditId;
20114
+ exports.alignedFieldList = alignedFieldList;
18076
20115
  exports.analyzedSceneSchema = analyzedSceneSchema;
18077
20116
  exports.applyDefaultVideoSelection = applyDefaultVideoSelection;
18078
20117
  exports.applyHandleInputOverride = applyHandleInputOverride;
@@ -18083,11 +20122,14 @@ exports.applyScene3DV2EditOperations = applyScene3DV2EditOperations;
18083
20122
  exports.applySlots = applySlots;
18084
20123
  exports.applyVideoAudioToggle = applyVideoAudioToggle;
18085
20124
  exports.applyVideoNegativePrompt = applyVideoNegativePrompt;
20125
+ exports.asEditPlanMode = asEditPlanMode;
20126
+ exports.asEditPlanTier = asEditPlanTier;
18086
20127
  exports.aspectRatioFromDims = aspectRatioFromDims;
18087
20128
  exports.aspectRatioOptionsByKind = aspectRatioOptionsByKind;
18088
20129
  exports.aspectRatioToNumber = aspectRatioToNumber;
18089
20130
  exports.assembleNarratedVideoCredits = assembleNarratedVideoCredits;
18090
20131
  exports.assertCanvasExecutionAllowed = assertCanvasExecutionAllowed;
20132
+ exports.autoStrokeWidth = autoStrokeWidth;
18091
20133
  exports.availableReasoningEfforts = availableReasoningEfforts;
18092
20134
  exports.bucketSecondsFromAuditCreditId = bucketSecondsFromAuditCreditId;
18093
20135
  exports.bucketSecondsFromCreditId = bucketSecondsFromCreditId;
@@ -18095,9 +20137,13 @@ exports.buildBoardPrompt = buildBoardPrompt;
18095
20137
  exports.buildChildrenByParent = buildChildrenByParent;
18096
20138
  exports.buildConditionVariables = buildConditionVariables;
18097
20139
  exports.buildCreditModelIdentifier = buildCreditModelIdentifier;
20140
+ exports.buildEditPlanCreditId = buildEditPlanCreditId;
18098
20141
  exports.buildExpressionFromVisual = buildExpressionFromVisual;
20142
+ exports.buildFeedMaps = buildFeedMaps;
20143
+ exports.buildInstagramScrapeCreditId = buildInstagramScrapeCreditId;
18099
20144
  exports.buildLipSyncCreditId = buildLipSyncCreditId;
18100
20145
  exports.buildLlmCreditIdentifier = buildLlmCreditIdentifier;
20146
+ exports.buildMetaAdsScrapeCreditId = buildMetaAdsScrapeCreditId;
18101
20147
  exports.buildModelMenu = buildModelMenu;
18102
20148
  exports.buildModelTree = buildModelTree;
18103
20149
  exports.buildMotionCreditModelIdentifier = buildMotionCreditModelIdentifier;
@@ -18116,6 +20162,8 @@ exports.calculateMonetizedCost = calculateMonetizedCost;
18116
20162
  exports.calculateProgress = calculateProgress;
18117
20163
  exports.canonicalScene3DPlanV2Json = canonicalScene3DPlanV2Json;
18118
20164
  exports.canonicalVarName = canonicalVarName;
20165
+ exports.captionRoutesToRemotion = captionRoutesToRemotion;
20166
+ exports.centreCropToAspect = centreCropToAspect;
18119
20167
  exports.characterBoardItems = characterBoardItems;
18120
20168
  exports.characterBucketDisplayRank = characterBucketDisplayRank;
18121
20169
  exports.characterMentionSlug = characterMentionSlug;
@@ -18125,7 +20173,11 @@ exports.characterVariantAssetArrays = characterVariantAssetArrays;
18125
20173
  exports.checkRefVideoDurations = checkRefVideoDurations;
18126
20174
  exports.cinematicCreditId = cinematicCreditId;
18127
20175
  exports.clampCinematicDuration = clampCinematicDuration;
20176
+ exports.clampEditPlanClipCount = clampEditPlanClipCount;
20177
+ exports.clampInstagramFeaturedIndex = clampInstagramFeaturedIndex;
20178
+ exports.clampMetaAdsFeaturedIndex = clampMetaAdsFeaturedIndex;
18128
20179
  exports.clampSmartCutWindow = clampSmartCutWindow;
20180
+ exports.classifyCreativeFormat = classifyCreativeFormat;
18129
20181
  exports.classifyRefToken = classifyRefToken;
18130
20182
  exports.cleanOrphanedItems = cleanOrphanedItems;
18131
20183
  exports.clearImageCriticMetadata = clearImageCriticMetadata;
@@ -18133,7 +20185,9 @@ exports.clearVideoCriticMetadata = clearVideoCriticMetadata;
18133
20185
  exports.clipLookSchema = clipLookSchema;
18134
20186
  exports.collectAncestorRefs = collectAncestorRefs;
18135
20187
  exports.combineSameLabelRefs = combineSameLabelRefs;
20188
+ exports.compactWithRows = compactWithRows;
18136
20189
  exports.computeAggregateLanes = computeAggregateLanes;
20190
+ exports.computeFrameFitPlan = computeFrameFitPlan;
18137
20191
  exports.computeScene3DPlanV2ContentHash = computeScene3DPlanV2ContentHash;
18138
20192
  exports.countRefModalityEdges = countRefModalityEdges;
18139
20193
  exports.creditRangesAll = creditRangesAll;
@@ -18150,9 +20204,13 @@ exports.describeEdgeBehavior = describeEdgeBehavior;
18150
20204
  exports.describeMaskRegion = describeMaskRegion;
18151
20205
  exports.describeNodeAdjustments = describeNodeAdjustments;
18152
20206
  exports.describeSlotControl = describeSlotControl;
20207
+ exports.detectVideoLinkPlatform = detectVideoLinkPlatform;
18153
20208
  exports.dropUnknownBindings = dropUnknownBindings;
18154
20209
  exports.dropUnknownSpeakers = dropUnknownSpeakers;
18155
20210
  exports.durationsByMode = durationsByMode;
20211
+ exports.editPlanBucketMinutes = editPlanBucketMinutes;
20212
+ exports.editPlanSourceDurationSec = editPlanSourceDurationSec;
20213
+ exports.edlDurationMs = edlDurationMs;
18156
20214
  exports.effectiveReasoningEffort = effectiveReasoningEffort;
18157
20215
  exports.encodeProviderItem = encodeProviderItem;
18158
20216
  exports.ensureLocaleCatalogLoaded = ensureLocaleCatalogLoaded;
@@ -18181,6 +20239,9 @@ exports.extractGeneratedJsonAsList = extractGeneratedJsonAsList;
18181
20239
  exports.extractPresetData = extractPresetData;
18182
20240
  exports.extractReferencedLabels = extractReferencedLabels;
18183
20241
  exports.extractVideoDurationFromNode = extractVideoDurationFromNode;
20242
+ exports.fanOutTextFeedsPrompt = fanOutTextFeedsPrompt;
20243
+ exports.featuredInstagramOutputs = featuredInstagramOutputs;
20244
+ exports.featuredMetaAdOutputs = featuredMetaAdOutputs;
18184
20245
  exports.fieldKeyFromHandle = fieldKeyFromHandle;
18185
20246
  exports.filterCloneNodes = filterCloneNodes;
18186
20247
  exports.findCharacterMentionTokens = findCharacterMentionTokens;
@@ -18188,6 +20249,7 @@ exports.findEntityMentionTokens = findEntityMentionTokens;
18188
20249
  exports.findImageMentionTokens = findImageMentionTokens;
18189
20250
  exports.findLocationMentionTokens = findLocationMentionTokens;
18190
20251
  exports.findSeedance2AudioOverLimit = findSeedance2AudioOverLimit;
20252
+ exports.findWordlessTranscriptFeeds = findWordlessTranscriptFeeds;
18191
20253
  exports.firstSightExtraRole = firstSightExtraRole;
18192
20254
  exports.flattenItems = flattenItems;
18193
20255
  exports.getAnimal = getAnimal;
@@ -18227,6 +20289,8 @@ exports.getParameterValue = getParameterValue;
18227
20289
  exports.getQualityOptions = getQualityOptions;
18228
20290
  exports.getResolutionOptions = getResolutionOptions;
18229
20291
  exports.getRouteReachableNodeIds = getRouteReachableNodeIds;
20292
+ exports.getSpeakerLayout = getSpeakerLayout;
20293
+ exports.getSpeakerSwitch = getSpeakerSwitch;
18230
20294
  exports.getStrategy = getStrategy;
18231
20295
  exports.getTargetField = getTargetField;
18232
20296
  exports.getValidValues = getValidValues;
@@ -18241,7 +20305,9 @@ exports.groupHandleId = groupHandleId;
18241
20305
  exports.groupLlmModelsByVendor = groupLlmModelsByVendor;
18242
20306
  exports.hasContiguousSegmentDurations = hasContiguousSegmentDurations;
18243
20307
  exports.hasFeature = hasFeature;
20308
+ exports.hasUrlParserHazard = hasUrlParserHazard;
18244
20309
  exports.hexToRgbaArray = hexToRgbaArray;
20310
+ exports.hostnameMatchesAllowlist = hostnameMatchesAllowlist;
18245
20311
  exports.humanizeSlotSid = humanizeSlotSid;
18246
20312
  exports.imageMentionSlug = imageMentionSlug;
18247
20313
  exports.imageMentionSlugForRef = imageMentionSlugForRef;
@@ -18249,19 +20315,38 @@ exports.imageOverlayBillableVariants = imageOverlayBillableVariants;
18249
20315
  exports.imageOverlayCredits = imageOverlayCredits;
18250
20316
  exports.imageReferenceLimit = imageReferenceLimit;
18251
20317
  exports.inferMusicVideo = inferMusicVideo;
20318
+ exports.instagramAnalysisCreditId = instagramAnalysisCreditId;
20319
+ exports.instagramAnalysisTierFrom = instagramAnalysisTierFrom;
20320
+ exports.instagramScrapeCreditIdFromNode = instagramScrapeCreditIdFromNode;
20321
+ exports.instagramScrapeMode = instagramScrapeMode;
20322
+ exports.instagramScrapeSources = instagramScrapeSources;
20323
+ exports.instagramScrapeTier = instagramScrapeTier;
18252
20324
  exports.isAggregateableType = isAggregateableType;
20325
+ exports.isAutoVideoDuration = isAutoVideoDuration;
18253
20326
  exports.isCharacterAspectRatio = isCharacterAspectRatio;
18254
20327
  exports.isCollectInEdge = isCollectInEdge;
20328
+ exports.isCronExpression = isCronExpression;
18255
20329
  exports.isDefaultSelectorConfig = isDefaultSelectorConfig;
20330
+ exports.isEdlTargetAspect = isEdlTargetAspect;
18256
20331
  exports.isExpandedClone = isExpandedClone;
20332
+ exports.isFacebookPageUrl = isFacebookPageUrl;
20333
+ exports.isFanOutUrlItem = isFanOutUrlItem;
18257
20334
  exports.isFlux2Model = isFlux2Model;
18258
20335
  exports.isGeminiOmniProvider = isGeminiOmniProvider;
18259
20336
  exports.isGvpSupportedProvider = isGvpSupportedProvider;
18260
20337
  exports.isHandleInputWired = isHandleInputWired;
20338
+ exports.isInstagramScrapeCount = isInstagramScrapeCount;
20339
+ exports.isInstagramScrapeMode = isInstagramScrapeMode;
18261
20340
  exports.isKineticCaptionStyle = isKineticCaptionStyle;
18262
20341
  exports.isKnownScene3DEngine = isKnownScene3DEngine;
20342
+ exports.isKnownSpeakerEmphasisStyle = isKnownSpeakerEmphasisStyle;
18263
20343
  exports.isLegacySunoModel = isLegacySunoModel;
18264
20344
  exports.isLocationUsageMode = isLocationUsageMode;
20345
+ exports.isMetaAdsFormat = isMetaAdsFormat;
20346
+ exports.isMetaAdsPlatform = isMetaAdsPlatform;
20347
+ exports.isMetaAdsScrapeCount = isMetaAdsScrapeCount;
20348
+ exports.isMetaAdsScrapeMode = isMetaAdsScrapeMode;
20349
+ exports.isMetaCdnImageUrl = isMetaCdnImageUrl;
18265
20350
  exports.isMinimaxH3Provider = isMinimaxH3Provider;
18266
20351
  exports.isObjectAspectRatio = isObjectAspectRatio;
18267
20352
  exports.isOversizedScene = isOversizedScene;
@@ -18270,6 +20355,7 @@ exports.isPerSecondLipSyncProvider = isPerSecondLipSyncProvider;
18270
20355
  exports.isPro3DRenderJobOutput = isPro3DRenderJobOutput;
18271
20356
  exports.isPro3DRenderQuote = isPro3DRenderQuote;
18272
20357
  exports.isPro3DRenderRenderOnly = isPro3DRenderRenderOnly;
20358
+ exports.isProjectedTriggerNodeType = isProjectedTriggerNodeType;
18273
20359
  exports.isRtlText = isRtlText;
18274
20360
  exports.isScene3DAuthoringEngine = isScene3DAuthoringEngine;
18275
20361
  exports.isScene3DCameraTrack = isScene3DCameraTrack;
@@ -18281,9 +20367,12 @@ exports.isScene3DReviewUnavailableReason = isScene3DReviewUnavailableReason;
18281
20367
  exports.isScene3DSchemaVersionSupported = isScene3DSchemaVersionSupported;
18282
20368
  exports.isScraperActor = isScraperActor;
18283
20369
  exports.isSeedance2Provider = isSeedance2Provider;
20370
+ exports.isSeedanceVideoEditProvider = isSeedanceVideoEditProvider;
20371
+ exports.isSocialVideoUrl = isSocialVideoUrl;
18284
20372
  exports.isTemplateCategory = isTemplateCategory;
18285
20373
  exports.isTiltDirection = isTiltDirection;
18286
20374
  exports.isUsageMode = isUsageMode;
20375
+ exports.isValidTimezone = isValidTimezone;
18287
20376
  exports.isVeoProvider = isVeoProvider;
18288
20377
  exports.isVideoAnalysisMixedTier = isVideoAnalysisMixedTier;
18289
20378
  exports.isVideoAnalysisTier = isVideoAnalysisTier;
@@ -18291,10 +20380,14 @@ exports.isWan3Provider = isWan3Provider;
18291
20380
  exports.jsonResultToList = jsonResultToList;
18292
20381
  exports.knownEntitySlugsFromRefs = knownEntitySlugsFromRefs;
18293
20382
  exports.knownImageSlugsFromRefs = knownImageSlugsFromRefs;
20383
+ exports.legacyScheduleToRules = legacyScheduleToRules;
18294
20384
  exports.listBoardTemplates = listBoardTemplates;
18295
20385
  exports.listModels = listModels;
18296
20386
  exports.listSlotSids = listSlotSids;
20387
+ exports.liveRowColumn = liveRowColumn;
18297
20388
  exports.llmRouteDefaults = llmRouteDefaults;
20389
+ exports.localMinuteKey = localMinuteKey;
20390
+ exports.localTimeIn = localTimeIn;
18298
20391
  exports.locationMentionSlug = locationMentionSlug;
18299
20392
  exports.locationReferencePhotoKindLabel = locationReferencePhotoKindLabel;
18300
20393
  exports.locationUsageModeLabel = locationUsageModeLabel;
@@ -18302,27 +20395,50 @@ exports.mapAspectRatio = mapAspectRatio;
18302
20395
  exports.mapQuality = mapQuality;
18303
20396
  exports.mapShotIntentToProviderDirectives = mapShotIntentToProviderDirectives;
18304
20397
  exports.matchVariant = matchVariant;
20398
+ exports.matchesCron = matchesCron;
20399
+ exports.matchesCronField = matchesCronField;
18305
20400
  exports.maxSegmentSecFor = maxSegmentSecFor;
18306
20401
  exports.maxSegmentsFor = maxSegmentsFor;
20402
+ exports.maxVideoDurationSec = maxVideoDurationSec;
20403
+ exports.measuredCanvasCombinations = measuredCanvasCombinations;
18307
20404
  exports.mergeClipLook = mergeClipLook;
20405
+ exports.mergeEdlSourceOffsets = mergeEdlSourceOffsets;
18308
20406
  exports.mergeExposedSettings = mergeExposedSettings;
20407
+ exports.mergeNodeInputOverrides = mergeNodeInputOverrides;
20408
+ exports.metaAdsAdvertisersFrom = metaAdsAdvertisersFrom;
20409
+ exports.metaAdsAnalysisCreditId = metaAdsAnalysisCreditId;
20410
+ exports.metaAdsAnalysisTier = metaAdsAnalysisTier;
20411
+ exports.metaAdsAnalysisTierFrom = metaAdsAnalysisTierFrom;
20412
+ exports.metaAdsNodeMode = metaAdsNodeMode;
20413
+ exports.metaAdsScrapeCreditIdFromNode = metaAdsScrapeCreditIdFromNode;
20414
+ exports.metaAdsScrapeSources = metaAdsScrapeSources;
20415
+ exports.metaAdsScrapeTier = metaAdsScrapeTier;
20416
+ exports.metaAdsScrapeWireSources = metaAdsScrapeWireSources;
18309
20417
  exports.migrateEdgeOutputMode = migrateEdgeOutputMode;
18310
20418
  exports.migrateToItems = migrateToItems;
18311
20419
  exports.minSegmentSecFor = minSegmentSecFor;
20420
+ exports.minimalRatioDimensions = minimalRatioDimensions;
18312
20421
  exports.modelIdsByKindMode = modelIdsByKindMode;
18313
20422
  exports.modelToNodeTarget = modelToNodeTarget;
18314
20423
  exports.modelsForInputMode = modelsForInputMode;
18315
20424
  exports.modelsWithFeature = modelsWithFeature;
18316
20425
  exports.motionGraphicsFeature = motionGraphicsFeature;
18317
20426
  exports.newScene3DRevisionId = newScene3DRevisionId;
20427
+ exports.nextScheduleRuns = nextScheduleRuns;
20428
+ exports.nodeFeedsAnything = nodeFeedsAnything;
18318
20429
  exports.nodeStateMayCarryOutput = nodeStateMayCarryOutput;
20430
+ exports.normalizeCaptionNumericLevers = normalizeCaptionNumericLevers;
20431
+ exports.normalizeEdl = normalizeEdl;
18319
20432
  exports.normalizeLottieLayers = normalizeLottieLayers;
18320
20433
  exports.normalizeMinimaxH3Resolution = normalizeMinimaxH3Resolution;
18321
20434
  exports.normalizeModelInput = normalizeModelInput;
18322
20435
  exports.normalizeNodeModelParams = normalizeNodeModelParams;
18323
20436
  exports.normalizePinterestUrl = normalizePinterestUrl;
18324
20437
  exports.normalizeRoleSlug = normalizeRoleSlug;
20438
+ exports.normalizeScheduleRule = normalizeScheduleRule;
20439
+ exports.normalizeScheduleRules = normalizeScheduleRules;
18325
20440
  exports.normalizeTemplateCategory = normalizeTemplateCategory;
20441
+ exports.normalizeTranscript = normalizeTranscript;
18326
20442
  exports.normalizeVideoRequestParams = normalizeVideoRequestParams;
18327
20443
  exports.normalizeWan3Resolution = normalizeWan3Resolution;
18328
20444
  exports.orderedLlmModels = orderedLlmModels;
@@ -18336,6 +20452,7 @@ exports.overlayStrokeSchema = overlayStrokeSchema;
18336
20452
  exports.overlayTextStyleSchema = overlayTextStyleSchema;
18337
20453
  exports.overlayVariantHandle = overlayVariantHandle;
18338
20454
  exports.overlayVariantIdFromHandle = overlayVariantIdFromHandle;
20455
+ exports.parseAspectToken = parseAspectToken;
18339
20456
  exports.parseAttributedDialogue = parseAttributedDialogue;
18340
20457
  exports.parseCharacterMentionToken = parseCharacterMentionToken;
18341
20458
  exports.parseEntityMentionToken = parseEntityMentionToken;
@@ -18348,11 +20465,13 @@ exports.parseNodePresetExport = parseNodePresetExport;
18348
20465
  exports.parseNodeRef = parseNodeRef;
18349
20466
  exports.parseScene3DCameraTrackJson = parseScene3DCameraTrackJson;
18350
20467
  exports.parseScene3DPlanV2Json = parseScene3DPlanV2Json;
20468
+ exports.parseSpeakerEmphasisStyle = parseSpeakerEmphasisStyle;
18351
20469
  exports.pickAiAvatarBucket = pickAiAvatarBucket;
18352
20470
  exports.pickIds = pickIds;
18353
20471
  exports.pickLipSyncBucket = pickLipSyncBucket;
18354
20472
  exports.pickSwitchXFrameTier = pickSwitchXFrameTier;
18355
20473
  exports.pickVideoAnalysisBucket = pickVideoAnalysisBucket;
20474
+ exports.planFanOut = planFanOut;
18356
20475
  exports.planSheetGeneration = planSheetGeneration;
18357
20476
  exports.planSheetPanels = planSheetPanels;
18358
20477
  exports.preferredInputModeForModel = preferredInputModeForModel;
@@ -18360,6 +20479,7 @@ exports.presentTypes = presentTypes;
18360
20479
  exports.presetApplyClearKeys = presetApplyClearKeys;
18361
20480
  exports.presetDataMatches = presetDataMatches;
18362
20481
  exports.presetEntries = presetEntries;
20482
+ exports.previewHorizonMs = previewHorizonMs;
18363
20483
  exports.pricedOutputDurationSec = pricedOutputDurationSec;
18364
20484
  exports.pricedVideoSelection = pricedVideoSelection;
18365
20485
  exports.pro3DRenderCoreOutputSchema = pro3DRenderCoreOutputSchema;
@@ -18373,11 +20493,14 @@ exports.pro3DRenderShotStills = pro3DRenderShotStills;
18373
20493
  exports.pro3DRenderTimingOverrides = pro3DRenderTimingOverrides;
18374
20494
  exports.qualityOptionsByKind = qualityOptionsByKind;
18375
20495
  exports.readPromptAffixes = readPromptAffixes;
20496
+ exports.reasoningOutputFloor = reasoningOutputFloor;
18376
20497
  exports.refHandleCategory = refHandleCategory;
18377
20498
  exports.referenceModalityForHandle = referenceModalityForHandle;
18378
20499
  exports.referenceSheetCreditId = referenceSheetCreditId;
18379
20500
  exports.registerCatalogSidecars = registerCatalogSidecars;
18380
20501
  exports.registerSidecarLoaders = registerSidecarLoaders;
20502
+ exports.remapMsThroughEdl = remapMsThroughEdl;
20503
+ exports.remapTranscriptThroughEdl = remapTranscriptThroughEdl;
18381
20504
  exports.renderAnalyzedScene = renderAnalyzedScene;
18382
20505
  exports.renderVideoCreditId = renderVideoCreditId;
18383
20506
  exports.requiresSequenceExecution = requiresSequenceExecution;
@@ -18385,28 +20508,37 @@ exports.resetCatalogSidecars = resetCatalogSidecars;
18385
20508
  exports.resolutionOptionsByKind = resolutionOptionsByKind;
18386
20509
  exports.resolveAiAvatarCreditId = resolveAiAvatarCreditId;
18387
20510
  exports.resolveAudioCrossfadeCurve = resolveAudioCrossfadeCurve;
20511
+ exports.resolveCaptionLevers = resolveCaptionLevers;
20512
+ exports.resolveCaptionLook = resolveCaptionLook;
18388
20513
  exports.resolveCharacterAspectRatio = resolveCharacterAspectRatio;
18389
20514
  exports.resolveCinematicCreditId = resolveCinematicCreditId;
18390
20515
  exports.resolveConditionValue = resolveConditionValue;
18391
20516
  exports.resolveDefaultRole = resolveDefaultRole;
18392
20517
  exports.resolveDescription = resolveDescription;
18393
20518
  exports.resolveDialogueVoices = resolveDialogueVoices;
20519
+ exports.resolveEdlSegmentSlots = resolveEdlSegmentSlots;
18394
20520
  exports.resolveEffectiveSourceType = resolveEffectiveSourceType;
18395
20521
  exports.resolveEffectiveTier = resolveEffectiveTier;
18396
20522
  exports.resolveEntityAspect = resolveEntityAspect;
18397
20523
  exports.resolveFieldMappings = resolveFieldMappings;
20524
+ exports.resolveFrameDelivery = resolveFrameDelivery;
20525
+ exports.resolveFrameFitAspect = resolveFrameFitAspect;
18398
20526
  exports.resolveGvpAnchorWire = resolveGvpAnchorWire;
18399
20527
  exports.resolveImageGenCreditIdentifier = resolveImageGenCreditIdentifier;
18400
20528
  exports.resolveIndex = resolveIndex;
20529
+ exports.resolveInstagramScrapeCreditId = resolveInstagramScrapeCreditId;
18401
20530
  exports.resolveLabel = resolveLabel;
18402
20531
  exports.resolveListExpression = resolveListExpression;
20532
+ exports.resolveListFanOut = resolveListFanOut;
18403
20533
  exports.resolveLlmCreditId = resolveLlmCreditId;
18404
20534
  exports.resolveLocationFields = resolveLocationFields;
18405
20535
  exports.resolveLocationPresetCatalog = resolveLocationPresetCatalog;
18406
20536
  exports.resolveLottieOverlaySrc = resolveLottieOverlaySrc;
20537
+ exports.resolveMetaAdsScrapeCreditId = resolveMetaAdsScrapeCreditId;
18407
20538
  exports.resolveNodeRefs = resolveNodeRefs;
18408
20539
  exports.resolveNormalizedImageGen = resolveNormalizedImageGen;
18409
20540
  exports.resolveObjectAspectRatio = resolveObjectAspectRatio;
20541
+ exports.resolveOutputCanvas = resolveOutputCanvas;
18410
20542
  exports.resolvePipelineModel = resolvePipelineModel;
18411
20543
  exports.resolveRelativeWindowToken = resolveRelativeWindowToken;
18412
20544
  exports.resolveScene3DAuthoringEngine = resolveScene3DAuthoringEngine;
@@ -18421,6 +20553,7 @@ exports.resolveSwitchXCreditId = resolveSwitchXCreditId;
18421
20553
  exports.resolveTemplateCategory = resolveTemplateCategory;
18422
20554
  exports.resolveTopazUpscale = resolveTopazUpscale;
18423
20555
  exports.resolveVideoAnalysisModel = resolveVideoAnalysisModel;
20556
+ exports.resolveVideoLinkOutput = resolveVideoLinkOutput;
18424
20557
  exports.resolveVideoModeForInputs = resolveVideoModeForInputs;
18425
20558
  exports.resolveVideoProviderForMode = resolveVideoProviderForMode;
18426
20559
  exports.resolveXfadeName = resolveXfadeName;
@@ -18430,6 +20563,7 @@ exports.rewriteSpeakerSlots = rewriteSpeakerSlots;
18430
20563
  exports.rgbaArrayToHex = rgbaArrayToHex;
18431
20564
  exports.roleToPhrase = roleToPhrase;
18432
20565
  exports.rotationVec3Schema = rotationVec3Schema;
20566
+ exports.ruleMatches = ruleMatches;
18433
20567
  exports.runSelector = runSelector;
18434
20568
  exports.safetyRetryPolicy = safetyRetryPolicy;
18435
20569
  exports.sanitizeRole = sanitizeRole;
@@ -18508,8 +20642,11 @@ exports.scene3DV2OverrideInputSchema = scene3DV2OverrideInputSchema;
18508
20642
  exports.scene3DV2ResourceUsage = scene3DV2ResourceUsage;
18509
20643
  exports.scene3DVersionTokenSchema = scene3DVersionTokenSchema;
18510
20644
  exports.scene3DZodIssues = scene3DZodIssues;
20645
+ exports.scheduleMatchesAt = scheduleMatchesAt;
20646
+ exports.scheduleOccurrences = scheduleOccurrences;
18511
20647
  exports.searchModelVariants = searchModelVariants;
18512
20648
  exports.seedance2AudioLimitSec = seedance2AudioLimitSec;
20649
+ exports.seedanceVideoEditCreditId = seedanceVideoEditCreditId;
18513
20650
  exports.segmentDurationsFor = segmentDurationsFor;
18514
20651
  exports.selectByModulo = selectByModulo;
18515
20652
  exports.selectByNamedKey = selectByNamedKey;
@@ -18524,31 +20661,46 @@ exports.slotVariationSchema = slotVariationSchema;
18524
20661
  exports.sortCharacterEntriesForDisplay = sortCharacterEntriesForDisplay;
18525
20662
  exports.sortListItems = sortListItems;
18526
20663
  exports.sourceRefKey = sourceRefKey;
20664
+ exports.speakerLayoutAllows = speakerLayoutAllows;
20665
+ exports.speakerPresentationWarnings = speakerPresentationWarnings;
20666
+ exports.speakerSwitchOverlaps = speakerSwitchOverlaps;
20667
+ exports.speakerTurns = speakerTurns;
18527
20668
  exports.spliceDelimitedRows = spliceDelimitedRows;
18528
20669
  exports.splitByLoopDelimiter = splitByLoopDelimiter;
18529
20670
  exports.splitGeneratedItems = splitGeneratedItems;
20671
+ exports.splitInstagramTargets = splitInstagramTargets;
20672
+ exports.splitMetaAdsAdvertiserNames = splitMetaAdsAdvertiserNames;
20673
+ exports.splitMetaAdsPageUrls = splitMetaAdsPageUrls;
18530
20674
  exports.spreadJsonArrayIfSingleton = spreadJsonArrayIfSingleton;
18531
20675
  exports.stringifyPathResults = stringifyPathResults;
18532
20676
  exports.stripDerivedAnalysisFields = stripDerivedAnalysisFields;
18533
20677
  exports.stripExportContent = stripExportContent;
18534
20678
  exports.stripStudioTransientSettings = stripStudioTransientSettings;
18535
20679
  exports.stripTransientRuntimeData = stripTransientRuntimeData;
20680
+ exports.stripUnownedRefs = stripUnownedRefs;
18536
20681
  exports.summarizeScene3DOperations = summarizeScene3DOperations;
18537
20682
  exports.sunoCreditType = sunoCreditType;
18538
20683
  exports.sunoModelHonoursDuration = sunoModelHonoursDuration;
18539
20684
  exports.supportedDefaultDimensions = supportedDefaultDimensions;
18540
20685
  exports.supportsAdvancedMode = supportsAdvancedMode;
20686
+ exports.supportsAutoVideoDuration = supportsAutoVideoDuration;
18541
20687
  exports.supportsEndAnchor = supportsEndAnchor;
18542
20688
  exports.supportsExtendRender = supportsExtendRender;
18543
20689
  exports.templateCategoryStoredValues = templateCategoryStoredValues;
20690
+ exports.timezoneOffsetMinutes = timezoneOffsetMinutes;
18544
20691
  exports.toConnectedReference = toConnectedReference;
18545
20692
  exports.toConnectedReferences = toConnectedReferences;
18546
20693
  exports.togglePick = togglePick;
20694
+ exports.transcribeLaneSupportsWordTimestamps = transcribeLaneSupportsWordTimestamps;
20695
+ exports.transcribeProvidersWithWordTimestamps = transcribeProvidersWithWordTimestamps;
20696
+ exports.transcribeWordTimestampsRefusal = transcribeWordTimestampsRefusal;
20697
+ exports.transcriptDurationSec = transcriptDurationSec;
18547
20698
  exports.tryParseJson = tryParseJson;
18548
20699
  exports.uiAspectRatioFill = uiAspectRatioFill;
18549
20700
  exports.uiDurationFill = uiDurationFill;
18550
20701
  exports.uiResolutionFill = uiResolutionFill;
18551
20702
  exports.unresolvedRefTokens = unresolvedRefTokens;
20703
+ exports.unwrapEditPlanOutput = unwrapEditPlanOutput;
18552
20704
  exports.unwrapUnresolvedTokens = unwrapUnresolvedTokens;
18553
20705
  exports.usageModeDirective = usageModeDirective;
18554
20706
  exports.usageModeIncludesName = usageModeIncludesName;
@@ -18557,6 +20709,8 @@ exports.usdToCredits = usdToCredits;
18557
20709
  exports.validateAiAvatarPayload = validateAiAvatarPayload;
18558
20710
  exports.validateCinematicAvatarPayload = validateCinematicAvatarPayload;
18559
20711
  exports.validateDurationForFormat = validateDurationForFormat;
20712
+ exports.validateEdl = validateEdl;
20713
+ exports.validateEdlClipSet = validateEdlClipSet;
18560
20714
  exports.validateModeActivation = validateModeActivation;
18561
20715
  exports.validateModelInput = validateModelInput;
18562
20716
  exports.validateNoNestedGroups = validateNoNestedGroups;
@@ -18570,6 +20724,8 @@ exports.videoAnalysisCreditSegment = videoAnalysisCreditSegment;
18570
20724
  exports.videoAnalysisNumWindows = videoAnalysisNumWindows;
18571
20725
  exports.videoAnalysisResultSchema = videoAnalysisResultSchema;
18572
20726
  exports.videoAuditCreditsForBucket = videoAuditCreditsForBucket;
20727
+ exports.videoLinkDownloadedFile = videoLinkDownloadedFile;
20728
+ exports.videoLinkNeedsDownload = videoLinkNeedsDownload;
18573
20729
  exports.videoModelCanSpeakDialogue = videoModelCanSpeakDialogue;
18574
20730
  exports.videoModelSupportsAudio = videoModelSupportsAudio;
18575
20731
  exports.videoNegativeSuffix = videoNegativeSuffix;