@nodaro/shared 2.19.0 → 2.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +548 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1043 -386
- package/dist/index.d.ts +1043 -386
- package/dist/index.js +529 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +133 -0
- package/src/__tests__/image-pricing-catalog-coverage.test.ts +139 -0
- package/src/__tests__/normalize-node-params.test.ts +36 -0
- package/src/__tests__/organizations-types.test.ts +29 -1
- package/src/__tests__/prompt-length-limits.test.ts +36 -0
- package/src/__tests__/safety-retry-policy.test.ts +47 -0
- package/src/__tests__/suno-credit-type.test.ts +54 -0
- package/src/__tests__/topaz-upscale.test.ts +132 -0
- package/src/__tests__/unresolved-ref-tokens.test.ts +66 -0
- package/src/__tests__/video-analysis-brief.test.ts +61 -0
- package/src/__tests__/video-analysis.test.ts +83 -0
- package/src/__tests__/video-audio-capability.test.ts +38 -4
- package/src/__tests__/video-catalog-totality.test.ts +85 -0
- package/src/__tests__/video-collapse-parity.test.ts +76 -0
- package/src/__tests__/video-ref-video-duration-limits.test.ts +69 -0
- package/src/__tests__/video-request-normalize.test.ts +239 -0
- package/src/credit-identifiers.ts +264 -20
- package/src/index.ts +30 -2
- package/src/model-catalog.ts +287 -6
- package/src/model-constants.ts +185 -13
- package/src/node-refs.ts +82 -0
- package/src/node-runtime-keys.ts +5 -0
- package/src/normalize-node-params.ts +8 -0
- package/src/organizations/types.ts +12 -0
- package/src/organizations/views.ts +114 -0
- package/src/safety-retry-policy.ts +37 -0
- package/src/topaz-upscale.ts +163 -0
- package/src/video-analysis.ts +115 -5
package/dist/index.cjs
CHANGED
|
@@ -55,7 +55,7 @@ var MODEL_RECOMMENDATIONS = [
|
|
|
55
55
|
{ intent: "cheapest realistic image", modelIds: ["z-image", "qwen", "imagen4-fast"], note: "Z-Image is the cheapest. Qwen / Imagen4 Fast for slightly higher quality." },
|
|
56
56
|
{ intent: "highest fidelity image", modelIds: ["nano-banana-pro", "imagen4-ultra", "flux-flex"], note: "Pick by family preference; all three are premium tiers." },
|
|
57
57
|
{ intent: "image edit / restyle", modelIds: ["flux-kontext", "ideogram-remix", "seedream-5-pro-i2i"], note: "Flux Kontext preserves identity; Ideogram Remix is character-aware; Seedream 5 Pro for instruction-based edits (5 Lite is the budget option)." },
|
|
58
|
-
{ intent: "highest-resolution image
|
|
58
|
+
{ intent: "highest-resolution image", modelIds: ["topaz-image-upscale", "nano-banana-pro", "gpt-image-2"], note: "Generate at the model's top tier, then Topaz upscale 4x (Topaz's only lever is the 1x/2x/4x factor)." },
|
|
59
59
|
{ intent: "background removal / cutout", modelIds: ["recraft-remove-bg"], note: "Cheap, no prompt needed." },
|
|
60
60
|
// video
|
|
61
61
|
{ intent: "best cinematic video", modelIds: ["veo3", "kling-3.0", "seedance-2"], note: "VEO 3.1 Quality for premium narrative; Kling 3.0 for music-synced motion; Seedance 2 for reference-driven consistency." },
|
|
@@ -398,7 +398,8 @@ var IMAGE_MODELS = {
|
|
|
398
398
|
{ identifier: "gpt-image-2", credits: 15, note: "1K default" },
|
|
399
399
|
{ identifier: "gpt-image-2:2K", credits: 30, note: "2K" },
|
|
400
400
|
{ identifier: "gpt-image-2:4K", credits: 60, note: "4K" }
|
|
401
|
-
]
|
|
401
|
+
],
|
|
402
|
+
safetyFilter: { stochastic: true, fallback: "nano-banana-pro" }
|
|
402
403
|
},
|
|
403
404
|
"gpt-image-2-i2i": {
|
|
404
405
|
id: "gpt-image-2-i2i",
|
|
@@ -818,14 +819,15 @@ var IMAGE_MODELS = {
|
|
|
818
819
|
family: "Topaz",
|
|
819
820
|
label: "Topaz Image Upscale",
|
|
820
821
|
series: "Topaz",
|
|
821
|
-
description: "High-quality image upscale
|
|
822
|
+
description: "High-quality image upscale at 1x (enhance only), 2x or 4x. Best for production-ready output.",
|
|
822
823
|
useCases: ["upscale", "high-res", "premium"],
|
|
823
824
|
features: ["reference-image"],
|
|
824
|
-
resolutions
|
|
825
|
+
// No `resolutions`: the provider's only quality lever is `upscale_factor`
|
|
826
|
+
// (1/2/4) — see resolveTopazUpscale. The 2K/4K/8K menu this used to
|
|
827
|
+
// advertise had no provider parameter behind it.
|
|
825
828
|
pricing: [
|
|
826
|
-
{ identifier: "topaz-image-upscale", credits: 25, note: "
|
|
827
|
-
{ identifier: "topaz-image-upscale:4K", credits: 50, note: "
|
|
828
|
-
{ identifier: "topaz-image-upscale:8K", credits: 100, note: "8K" }
|
|
829
|
+
{ identifier: "topaz-image-upscale", credits: 25, note: "1x / 2x" },
|
|
830
|
+
{ identifier: "topaz-image-upscale:4K", credits: 50, note: "4x (legacy identifier)" }
|
|
829
831
|
]
|
|
830
832
|
}
|
|
831
833
|
};
|
|
@@ -856,6 +858,7 @@ var VIDEO_MODELS = {
|
|
|
856
858
|
// docs.kie.ai/market/minimax-h3/{text,image,reference}-to-video.
|
|
857
859
|
"minimax-h3": {
|
|
858
860
|
id: "minimax-h3",
|
|
861
|
+
unlistedResolutionRendersAs: "2K",
|
|
859
862
|
kind: "video",
|
|
860
863
|
modes: ["i2v", "t2v"],
|
|
861
864
|
family: "MiniMax",
|
|
@@ -1341,6 +1344,7 @@ var VIDEO_MODELS = {
|
|
|
1341
1344
|
// declared explicitly in PRICING_DEFAULT_RESOLUTION, never by array position.
|
|
1342
1345
|
"wan-3": {
|
|
1343
1346
|
id: "wan-3",
|
|
1347
|
+
unlistedResolutionRendersAs: "720p",
|
|
1344
1348
|
kind: "video",
|
|
1345
1349
|
modes: ["i2v", "t2v"],
|
|
1346
1350
|
family: "Alibaba",
|
|
@@ -1365,6 +1369,7 @@ var VIDEO_MODELS = {
|
|
|
1365
1369
|
},
|
|
1366
1370
|
"wan-3-prime": {
|
|
1367
1371
|
id: "wan-3-prime",
|
|
1372
|
+
unlistedResolutionRendersAs: "720p",
|
|
1368
1373
|
kind: "video",
|
|
1369
1374
|
modes: ["i2v", "t2v"],
|
|
1370
1375
|
family: "Alibaba",
|
|
@@ -1533,6 +1538,76 @@ var VIDEO_MODELS = {
|
|
|
1533
1538
|
{ identifier: "wan-2.7-t2v", credits: 188, note: "5s 720p default" }
|
|
1534
1539
|
]
|
|
1535
1540
|
},
|
|
1541
|
+
// Lightricks LTX 2.3 (Replicate, not KIE). Both variants run one endpoint per
|
|
1542
|
+
// variant and switch behaviour with a `task` discriminator, so t2v and i2v are
|
|
1543
|
+
// the SAME id — no VIDEO_MODE_ALIASES row. `extend` / `retake` are separate
|
|
1544
|
+
// priced ops on the same model (ids below) but are NOT listed in `modes`:
|
|
1545
|
+
// they are driven by the Extend Video / Video Retake nodes' own pickers, and
|
|
1546
|
+
// adding the mode here would duplicate LTX in those menus.
|
|
1547
|
+
// Bands are lowercase to match LTX_DURATION_TIERS' keys in credit-identifiers.ts
|
|
1548
|
+
// and QUALITY_MAP in node-default-mappings.ts.
|
|
1549
|
+
"ltx-2.3-pro": {
|
|
1550
|
+
id: "ltx-2.3-pro",
|
|
1551
|
+
kind: "video",
|
|
1552
|
+
modes: ["i2v", "t2v"],
|
|
1553
|
+
family: "Lightricks",
|
|
1554
|
+
label: "LTX 2.3 Pro",
|
|
1555
|
+
series: "LTX",
|
|
1556
|
+
description: "Lightricks LTX 2.3 Pro \u2014 text/image/audio\u2192video up to 4K, 6/8/10s, end-frame interpolation.",
|
|
1557
|
+
useCases: ["premium", "high-res", "narrative"],
|
|
1558
|
+
features: ["end-frame"],
|
|
1559
|
+
aspectRatios: ["16:9", "9:16"],
|
|
1560
|
+
resolutions: ["1080p", "2k", "4k"],
|
|
1561
|
+
durations: [6, 8, 10],
|
|
1562
|
+
pricing: [
|
|
1563
|
+
{ identifier: "ltx-2.3-pro", credits: 240, note: "default 1080p 6s" },
|
|
1564
|
+
{ identifier: "ltx-2.3-pro:1080p:6s", credits: 240 },
|
|
1565
|
+
{ identifier: "ltx-2.3-pro:1080p:8s", credits: 320 },
|
|
1566
|
+
{ identifier: "ltx-2.3-pro:1080p:10s", credits: 400 },
|
|
1567
|
+
{ identifier: "ltx-2.3-pro:2k:6s", credits: 480 },
|
|
1568
|
+
{ identifier: "ltx-2.3-pro:2k:8s", credits: 640 },
|
|
1569
|
+
{ identifier: "ltx-2.3-pro:2k:10s", credits: 800 },
|
|
1570
|
+
{ identifier: "ltx-2.3-pro:4k:6s", credits: 960 },
|
|
1571
|
+
{ identifier: "ltx-2.3-pro:4k:8s", credits: 1280 },
|
|
1572
|
+
{ identifier: "ltx-2.3-pro:4k:10s", credits: 1600 },
|
|
1573
|
+
{ identifier: "ltx-2.3-pro-extend:per-second", credits: 40, note: "extend, per second of new footage" },
|
|
1574
|
+
{ identifier: "ltx-2.3-pro-retake:per-second", credits: 40, note: "retake, per second re-rendered" }
|
|
1575
|
+
]
|
|
1576
|
+
},
|
|
1577
|
+
"ltx-2.3-fast": {
|
|
1578
|
+
id: "ltx-2.3-fast",
|
|
1579
|
+
kind: "video",
|
|
1580
|
+
modes: ["i2v", "t2v"],
|
|
1581
|
+
family: "Lightricks",
|
|
1582
|
+
label: "LTX 2.3 Fast",
|
|
1583
|
+
series: "LTX",
|
|
1584
|
+
description: "Lightricks LTX 2.3 Fast \u2014 text/image\u2192video up to 20s at 1080p (6/8/10s at 2K and 4K). No audio input, no extend.",
|
|
1585
|
+
useCases: ["long-form", "fast", "narrative"],
|
|
1586
|
+
features: ["end-frame"],
|
|
1587
|
+
aspectRatios: ["16:9", "9:16"],
|
|
1588
|
+
resolutions: ["1080p", "2k", "4k"],
|
|
1589
|
+
// Flat union across bands — 12–20s exist only at 1080p (LTX_DURATION_TIERS
|
|
1590
|
+
// in credit-identifiers.ts is the per-band authority and snaps a 2k/4k
|
|
1591
|
+
// request back onto 6/8/10s, so the reservation is always a real tier).
|
|
1592
|
+
durations: [6, 8, 10, 12, 14, 16, 18, 20],
|
|
1593
|
+
pricing: [
|
|
1594
|
+
{ identifier: "ltx-2.3-fast", credits: 180, note: "default 1080p 6s" },
|
|
1595
|
+
{ identifier: "ltx-2.3-fast:1080p:6s", credits: 180 },
|
|
1596
|
+
{ identifier: "ltx-2.3-fast:1080p:8s", credits: 240 },
|
|
1597
|
+
{ identifier: "ltx-2.3-fast:1080p:10s", credits: 300 },
|
|
1598
|
+
{ identifier: "ltx-2.3-fast:1080p:12s", credits: 360 },
|
|
1599
|
+
{ identifier: "ltx-2.3-fast:1080p:14s", credits: 420 },
|
|
1600
|
+
{ identifier: "ltx-2.3-fast:1080p:16s", credits: 480 },
|
|
1601
|
+
{ identifier: "ltx-2.3-fast:1080p:18s", credits: 540 },
|
|
1602
|
+
{ identifier: "ltx-2.3-fast:1080p:20s", credits: 600 },
|
|
1603
|
+
{ identifier: "ltx-2.3-fast:2k:6s", credits: 360 },
|
|
1604
|
+
{ identifier: "ltx-2.3-fast:2k:8s", credits: 480 },
|
|
1605
|
+
{ identifier: "ltx-2.3-fast:2k:10s", credits: 600 },
|
|
1606
|
+
{ identifier: "ltx-2.3-fast:4k:6s", credits: 720 },
|
|
1607
|
+
{ identifier: "ltx-2.3-fast:4k:8s", credits: 960 },
|
|
1608
|
+
{ identifier: "ltx-2.3-fast:4k:10s", credits: 1200 }
|
|
1609
|
+
]
|
|
1610
|
+
},
|
|
1536
1611
|
// ── HappyHorse (1.1 — ids kept version-less; repointed in place when KIE
|
|
1537
1612
|
// delisted 1.0, same param surface, so saved workflows keep working) ──
|
|
1538
1613
|
"happyhorse": {
|
|
@@ -2384,6 +2459,105 @@ function normalizeModelInput(modelId, input) {
|
|
|
2384
2459
|
}
|
|
2385
2460
|
return out;
|
|
2386
2461
|
}
|
|
2462
|
+
var PASSTHROUGH_ASPECT_TOKENS = /* @__PURE__ */ new Set(["auto", "adaptive"]);
|
|
2463
|
+
var RESOLUTION_BAND_PIXELS = {
|
|
2464
|
+
"2k": 1440,
|
|
2465
|
+
"4k": 2160,
|
|
2466
|
+
"8k": 4320
|
|
2467
|
+
};
|
|
2468
|
+
function bandPixels(token) {
|
|
2469
|
+
const t2 = token.trim().toLowerCase();
|
|
2470
|
+
if (RESOLUTION_BAND_PIXELS[t2] !== void 0) return RESOLUTION_BAND_PIXELS[t2];
|
|
2471
|
+
const m = /^(\d+)p$/.exec(t2);
|
|
2472
|
+
return m ? Number(m[1]) : void 0;
|
|
2473
|
+
}
|
|
2474
|
+
function nearestResolutionBand(token, allowed) {
|
|
2475
|
+
let highest = allowed[allowed.length - 1];
|
|
2476
|
+
let highestPx = -Infinity;
|
|
2477
|
+
for (const a of allowed) {
|
|
2478
|
+
const px = bandPixels(a);
|
|
2479
|
+
if (px !== void 0 && px > highestPx) {
|
|
2480
|
+
highestPx = px;
|
|
2481
|
+
highest = a;
|
|
2482
|
+
}
|
|
2483
|
+
}
|
|
2484
|
+
const want = bandPixels(token);
|
|
2485
|
+
if (want === void 0) return highest;
|
|
2486
|
+
let best = highest;
|
|
2487
|
+
let bestDist = Infinity;
|
|
2488
|
+
for (const a of allowed) {
|
|
2489
|
+
const px = bandPixels(a);
|
|
2490
|
+
if (px === void 0) continue;
|
|
2491
|
+
const d = Math.abs(px - want);
|
|
2492
|
+
if (d < bestDist) {
|
|
2493
|
+
bestDist = d;
|
|
2494
|
+
best = a;
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
return best;
|
|
2498
|
+
}
|
|
2499
|
+
function nearestAspectRatio(token, allowed) {
|
|
2500
|
+
const [w, h] = token.split(":").map(Number);
|
|
2501
|
+
if (!w || !h) return void 0;
|
|
2502
|
+
const target = Math.log(w / h);
|
|
2503
|
+
let best;
|
|
2504
|
+
let bestDist = Infinity;
|
|
2505
|
+
for (const c of allowed) {
|
|
2506
|
+
const [cw, ch] = c.split(":").map(Number);
|
|
2507
|
+
if (!cw || !ch) continue;
|
|
2508
|
+
const d = Math.abs(Math.log(cw / ch) - target);
|
|
2509
|
+
if (d < bestDist) {
|
|
2510
|
+
bestDist = d;
|
|
2511
|
+
best = c;
|
|
2512
|
+
}
|
|
2513
|
+
}
|
|
2514
|
+
return best;
|
|
2515
|
+
}
|
|
2516
|
+
function readOptionToken(value) {
|
|
2517
|
+
if (value === void 0 || value === null) return void 0;
|
|
2518
|
+
const s = (typeof value === "string" ? value : String(value)).trim();
|
|
2519
|
+
return s === "" ? void 0 : s;
|
|
2520
|
+
}
|
|
2521
|
+
function normalizeVideoRequestParams(modelId, input) {
|
|
2522
|
+
const m = MODEL_CATALOG[modelId];
|
|
2523
|
+
const aspect = readOptionToken(input.aspectRatio);
|
|
2524
|
+
const res = readOptionToken(input.resolution);
|
|
2525
|
+
const out = { aspectRatio: aspect, resolution: res, adjustments: [] };
|
|
2526
|
+
if (!m) return out;
|
|
2527
|
+
if (m.aspectRatios?.length && aspect && !PASSTHROUGH_ASPECT_TOKENS.has(aspect.toLowerCase())) {
|
|
2528
|
+
const allowed = m.aspectRatios;
|
|
2529
|
+
const exact = allowed.find((a) => a === aspect) ?? allowed.find((a) => a.toLowerCase() === aspect.toLowerCase());
|
|
2530
|
+
if (exact !== void 0) {
|
|
2531
|
+
out.aspectRatio = exact;
|
|
2532
|
+
} else {
|
|
2533
|
+
const next = nearestAspectRatio(aspect, allowed.filter((a) => !PASSTHROUGH_ASPECT_TOKENS.has(a.toLowerCase()))) ?? allowed[0];
|
|
2534
|
+
out.adjustments.push({
|
|
2535
|
+
field: "aspectRatio",
|
|
2536
|
+
from: aspect,
|
|
2537
|
+
to: next,
|
|
2538
|
+
reason: `${m.label} does not support aspect ratio "${aspect}" \u2014 using "${next}" instead. Supported: ${allowed.join(", ")}.`
|
|
2539
|
+
});
|
|
2540
|
+
out.aspectRatio = next;
|
|
2541
|
+
}
|
|
2542
|
+
}
|
|
2543
|
+
if (m.resolutions?.length && res) {
|
|
2544
|
+
const allowed = m.resolutions;
|
|
2545
|
+
const exact = allowed.find((a) => a === res) ?? allowed.find((a) => a.toLowerCase() === res.toLowerCase());
|
|
2546
|
+
if (exact !== void 0) {
|
|
2547
|
+
out.resolution = exact;
|
|
2548
|
+
} else {
|
|
2549
|
+
const next = m.unlistedResolutionRendersAs ?? nearestResolutionBand(res, allowed);
|
|
2550
|
+
out.adjustments.push({
|
|
2551
|
+
field: "resolution",
|
|
2552
|
+
from: res,
|
|
2553
|
+
to: next,
|
|
2554
|
+
reason: `${m.label} does not support resolution "${res}" \u2014 using "${next}" instead. Supported: ${allowed.join(", ")}.`
|
|
2555
|
+
});
|
|
2556
|
+
out.resolution = next;
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
return out;
|
|
2560
|
+
}
|
|
2387
2561
|
var MODEL_VALUE_LABELS = {
|
|
2388
2562
|
// aspect ratios
|
|
2389
2563
|
"1:1": "1:1 (Square)",
|
|
@@ -2398,6 +2572,7 @@ var MODEL_VALUE_LABELS = {
|
|
|
2398
2572
|
"2K": "2K (High)",
|
|
2399
2573
|
"4K": "4K (Ultra)",
|
|
2400
2574
|
"4k": "4K",
|
|
2575
|
+
"2k": "2K",
|
|
2401
2576
|
"8K": "8K (Ultra)",
|
|
2402
2577
|
// qualities
|
|
2403
2578
|
"medium": "Medium (Balanced)",
|
|
@@ -2525,6 +2700,25 @@ function modelIdsByKindMode(kind, modes, opts = {}) {
|
|
|
2525
2700
|
// src/model-constants.ts
|
|
2526
2701
|
var CREDIT_BASE_USD = 2e-3;
|
|
2527
2702
|
var IMAGE_PROMPT_MAX = 5e3;
|
|
2703
|
+
var IMAGE_ASPECT_RATIO_VALUES = [
|
|
2704
|
+
"auto",
|
|
2705
|
+
"1:1",
|
|
2706
|
+
"16:9",
|
|
2707
|
+
"9:16",
|
|
2708
|
+
"4:3",
|
|
2709
|
+
"3:4",
|
|
2710
|
+
"3:2",
|
|
2711
|
+
"2:3",
|
|
2712
|
+
"5:4",
|
|
2713
|
+
"4:5",
|
|
2714
|
+
"21:9",
|
|
2715
|
+
// Ultra-wide / ultra-tall banner ratios: Wan 2.7 + Wan 2.7 Pro (8:1, 1:8)
|
|
2716
|
+
// and Nano Banana 2 Lite (4:1, 1:4, 8:1, 1:8).
|
|
2717
|
+
"4:1",
|
|
2718
|
+
"1:4",
|
|
2719
|
+
"8:1",
|
|
2720
|
+
"1:8"
|
|
2721
|
+
];
|
|
2528
2722
|
var MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER = {
|
|
2529
2723
|
// ── higher than the 5000 default ──
|
|
2530
2724
|
"nano-banana-2": 2e4,
|
|
@@ -2562,6 +2756,7 @@ function getMaxImagePromptChars(provider) {
|
|
|
2562
2756
|
}
|
|
2563
2757
|
var VIDEO_PROMPT_MAX = 8e3;
|
|
2564
2758
|
var SUNO_TEXT_MAX = 5e3;
|
|
2759
|
+
var SUNO_HARD_CEILING = 3e4;
|
|
2565
2760
|
var PROMPT_HARD_CEILING = 3e4;
|
|
2566
2761
|
var LLM_TEXT_INPUT_MAX = 1e5;
|
|
2567
2762
|
var MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER = {
|
|
@@ -3563,6 +3758,39 @@ var VIDEO_REF_LIMITS_BY_PROVIDER = {
|
|
|
3563
3758
|
// the user's references (the grok-imagine-video-1.5 bug). Add only with a
|
|
3564
3759
|
// verified provider path + the catalog `reference-image` feature.
|
|
3565
3760
|
};
|
|
3761
|
+
var VIDEO_REF_VIDEO_DURATION_LIMITS = {
|
|
3762
|
+
"seedance-2-5": { minSec: 2, maxSec: 30, maxTotalSec: 30 },
|
|
3763
|
+
// MiniMax Hailuo 3 — the provider states the per-clip bound in its own reject
|
|
3764
|
+
// text: "content[1].video_url: invalid param: video duration 52838 ms,
|
|
3765
|
+
// expected [2000, 15000] ms" (app-reports P4, 2 rows, the same clip retried).
|
|
3766
|
+
// The KIE reference-to-video doc adds the COMBINED cap — the same shape the
|
|
3767
|
+
// audio side already declares in SEEDANCE_2_R2V_MAX_AUDIO_SEC_BY_PROVIDER
|
|
3768
|
+
// above, whose h3 row cites the same page.
|
|
3769
|
+
"minimax-h3": { minSec: 2, maxSec: 15, maxTotalSec: 15 }
|
|
3770
|
+
};
|
|
3771
|
+
function checkRefVideoDurations(provider, durationsSec) {
|
|
3772
|
+
const limit = VIDEO_REF_VIDEO_DURATION_LIMITS[provider];
|
|
3773
|
+
if (!limit) return { ok: true };
|
|
3774
|
+
const usable = durationsSec.filter((d) => Number.isFinite(d) && d > 0);
|
|
3775
|
+
if (usable.length === 0) return { ok: true };
|
|
3776
|
+
const offender = usable.find((d) => d < limit.minSec || d > limit.maxSec);
|
|
3777
|
+
if (offender !== void 0) {
|
|
3778
|
+
return {
|
|
3779
|
+
ok: false,
|
|
3780
|
+
message: `Each reference video must be between ${limit.minSec} and ${limit.maxSec} seconds \u2014 one is ${offender.toFixed(1)}s. Trim it (a Trim Video node upstream works) and run again.`
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
if (limit.maxTotalSec !== void 0) {
|
|
3784
|
+
const total = usable.reduce((a, b) => a + b, 0);
|
|
3785
|
+
if (total > limit.maxTotalSec) {
|
|
3786
|
+
return {
|
|
3787
|
+
ok: false,
|
|
3788
|
+
message: `Reference videos must not exceed ${limit.maxTotalSec} seconds in total \u2014 these add up to ${total.toFixed(1)}s. Remove one or trim them and run again.`
|
|
3789
|
+
};
|
|
3790
|
+
}
|
|
3791
|
+
}
|
|
3792
|
+
return { ok: true };
|
|
3793
|
+
}
|
|
3566
3794
|
var RESOLUTION_VIDEO_REF_PRICING = SEEDANCE_2_PROVIDERS;
|
|
3567
3795
|
var RESOLUTION_DURATION_PRICING = {
|
|
3568
3796
|
// KIE supports only 480p/720p here; 480p is the default.
|
|
@@ -3656,10 +3884,39 @@ var VIDEO_AUDIO_CAPABILITY = {
|
|
|
3656
3884
|
// and skip the lip-sync pass. `defaultOn` mirrors the KIE default so an
|
|
3657
3885
|
// intent-less request is described honestly; audio is priced into the uniform
|
|
3658
3886
|
// per-second rate, so NOT cost-affecting (no `:audio` composite).
|
|
3659
|
-
// gemini-omni-flash is deliberately ABSENT — gemini-omni-video is absent too
|
|
3660
|
-
// (mode "none"), and the siblings must not disagree.
|
|
3661
3887
|
"wan-3": { mode: "ambient", field: "audio", defaultOn: true },
|
|
3662
|
-
"wan-3-prime": { mode: "ambient", field: "audio", defaultOn: true }
|
|
3888
|
+
"wan-3-prime": { mode: "ambient", field: "audio", defaultOn: true },
|
|
3889
|
+
// Gemini Omni (both SKUs — the pro `gemini-omni-video` and the faster
|
|
3890
|
+
// `gemini-omni-flash`; one model at two speeds, so their rows are identical
|
|
3891
|
+
// and a test pins that). Settled 2026-09-03 from Google's own documentation
|
|
3892
|
+
// at https://ai.google.dev/gemini-api/docs/omni, having been unlisted — and
|
|
3893
|
+
// therefore reported as SILENT — while the catalog described both as "native
|
|
3894
|
+
// audio".
|
|
3895
|
+
//
|
|
3896
|
+
// "ambient", and alwaysOn with no toggle field, on three sentences from that
|
|
3897
|
+
// page:
|
|
3898
|
+
// - "By default the model will try to generate an appropriate audio track
|
|
3899
|
+
// for a video." Audio on every render, and the KIE input schema
|
|
3900
|
+
// (prompt / image_urls / first+last_frame_url / audio_ids / video_list /
|
|
3901
|
+
// character_ids / duration / aspect_ratio / seed / resolution — see
|
|
3902
|
+
// docs.kie.ai/market/gemini-omni-video and
|
|
3903
|
+
// docs.kie.ai/market/google/gemini-omni-flash-1-1) carries no on/off
|
|
3904
|
+
// lever, so there is nothing for applyVideoAudioToggle to write.
|
|
3905
|
+
// - NOT native_speech: "Multi-turn voice extension: Generating spoken
|
|
3906
|
+
// dialogue or speech is supported when extending previously generated
|
|
3907
|
+
// videos via multi-turn (`previous_interaction_id`)" — a field KIE's
|
|
3908
|
+
// createTask schema does not expose, so the dialogue path is unreachable
|
|
3909
|
+
// on our transport. Held to the Wan 3.0 bar: no documented dialogue
|
|
3910
|
+
// guarantee on the path we actually drive ⇒ ambient, and upgrade only on
|
|
3911
|
+
// a live probe (the kling-3.0 standard). Classifying it native_speech
|
|
3912
|
+
// would reroute the Story→Video dialogue pipeline past the lip-sync pass.
|
|
3913
|
+
// - NOT audio_driven either: "Uploading audio references is unsupported in
|
|
3914
|
+
// the current version of the API", and "any audio in a video reference is
|
|
3915
|
+
// ignored" — there is no reference-audio transport to be driven by, and
|
|
3916
|
+
// runGeminiOmni never sends `audio_ids`.
|
|
3917
|
+
// Audio is priced into the per-tier rate, so NOT cost-affecting.
|
|
3918
|
+
"gemini-omni-video": { mode: "ambient", alwaysOn: true },
|
|
3919
|
+
"gemini-omni-flash": { mode: "ambient", alwaysOn: true }
|
|
3663
3920
|
};
|
|
3664
3921
|
var VIDEO_AUDIO_NONE = { mode: "none" };
|
|
3665
3922
|
function getVideoAudioCapability(model) {
|
|
@@ -4426,17 +4683,33 @@ function buildCreditModelIdentifier(provider, quality, resolution, renderingSpee
|
|
|
4426
4683
|
}
|
|
4427
4684
|
return provider;
|
|
4428
4685
|
}
|
|
4686
|
+
function resolveNormalizedImageGen(opts) {
|
|
4687
|
+
const str = (v) => typeof v === "string" && v.length > 0 ? v : void 0;
|
|
4688
|
+
const provider = str(opts.provider) ?? "nano-banana";
|
|
4689
|
+
const modelId = opts.swapToI2i && opts.refCount > 0 ? T2I_TO_I2I_VARIANT[provider] ?? provider : provider;
|
|
4690
|
+
const n = normalizeModelInput(modelId, {
|
|
4691
|
+
aspectRatio: str(opts.aspectRatio),
|
|
4692
|
+
resolution: str(opts.resolution),
|
|
4693
|
+
quality: str(opts.quality)
|
|
4694
|
+
});
|
|
4695
|
+
return {
|
|
4696
|
+
identifier: buildCreditModelIdentifier(
|
|
4697
|
+
modelId,
|
|
4698
|
+
n.quality,
|
|
4699
|
+
n.resolution,
|
|
4700
|
+
str(opts.renderingSpeed),
|
|
4701
|
+
void 0,
|
|
4702
|
+
opts.refCount
|
|
4703
|
+
),
|
|
4704
|
+
modelId,
|
|
4705
|
+
aspectRatio: n.aspectRatio,
|
|
4706
|
+
resolution: n.resolution,
|
|
4707
|
+
quality: n.quality,
|
|
4708
|
+
adjustments: n.adjustments
|
|
4709
|
+
};
|
|
4710
|
+
}
|
|
4429
4711
|
function resolveImageGenCreditIdentifier(opts) {
|
|
4430
|
-
|
|
4431
|
-
const effectiveProvider = opts.swapToI2i && opts.refCount > 0 ? T2I_TO_I2I_VARIANT[provider] ?? provider : provider;
|
|
4432
|
-
return buildCreditModelIdentifier(
|
|
4433
|
-
effectiveProvider,
|
|
4434
|
-
opts.quality,
|
|
4435
|
-
opts.resolution,
|
|
4436
|
-
opts.renderingSpeed,
|
|
4437
|
-
void 0,
|
|
4438
|
-
opts.refCount
|
|
4439
|
-
);
|
|
4712
|
+
return resolveNormalizedImageGen(opts).identifier;
|
|
4440
4713
|
}
|
|
4441
4714
|
var T2V_CREDIT_OVERRIDES = {
|
|
4442
4715
|
"grok": "grok-i2v",
|
|
@@ -4451,6 +4724,16 @@ var LTX_DURATION_TIERS = {
|
|
|
4451
4724
|
"ltx-2.3-pro": { "1080p": [6, 8, 10], "2k": [6, 8, 10], "4k": [6, 8, 10] },
|
|
4452
4725
|
"ltx-2.3-fast": { "1080p": [6, 8, 10, 12, 14, 16, 18, 20], "2k": [6, 8, 10], "4k": [6, 8, 10] }
|
|
4453
4726
|
};
|
|
4727
|
+
function ltxPricedTier(provider, resolution, duration) {
|
|
4728
|
+
const bands = LTX_DURATION_TIERS[provider];
|
|
4729
|
+
if (!bands) return void 0;
|
|
4730
|
+
const band2 = bands[String(resolution)] ? String(resolution) : "1080p";
|
|
4731
|
+
const allowed = bands[band2];
|
|
4732
|
+
const raw = typeof duration === "string" ? parseInt(duration, 10) : duration ?? allowed[0];
|
|
4733
|
+
const want = Number.isNaN(raw) ? allowed[0] : raw;
|
|
4734
|
+
const dur = allowed.reduce((b, a) => Math.abs(a - want) < Math.abs(b - want) ? a : b);
|
|
4735
|
+
return { band: band2, duration: dur };
|
|
4736
|
+
}
|
|
4454
4737
|
function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mode, resolution, hasVideoRef) {
|
|
4455
4738
|
let effectiveProvider = provider;
|
|
4456
4739
|
if (nodeType === "text-to-video") {
|
|
@@ -4476,14 +4759,9 @@ function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mo
|
|
|
4476
4759
|
const d = Number.isNaN(raw) ? 8 : GEMINI_OMNI_DURATIONS.reduce((b, a) => Math.abs(a - raw) < Math.abs(b - raw) ? a : b);
|
|
4477
4760
|
return resolution === "4k" ? `${effectiveProvider}:4k:${d}` : `${effectiveProvider}:${d}`;
|
|
4478
4761
|
}
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
const allowed = bands[band2];
|
|
4483
|
-
const raw = typeof duration === "string" ? parseInt(duration, 10) : duration ?? allowed[0];
|
|
4484
|
-
const want = Number.isNaN(raw) ? allowed[0] : raw;
|
|
4485
|
-
const dur = allowed.reduce((b, a) => Math.abs(a - want) < Math.abs(b - want) ? a : b);
|
|
4486
|
-
return `${effectiveProvider}:${band2}:${dur}s`;
|
|
4762
|
+
const ltxTier = ltxPricedTier(effectiveProvider, resolution, duration);
|
|
4763
|
+
if (ltxTier) {
|
|
4764
|
+
return `${effectiveProvider}:${ltxTier.band}:${ltxTier.duration}s`;
|
|
4487
4765
|
}
|
|
4488
4766
|
if (!DURATION_PRICED_PROVIDERS.has(effectiveProvider)) {
|
|
4489
4767
|
return effectiveProvider;
|
|
@@ -4523,6 +4801,22 @@ function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mo
|
|
|
4523
4801
|
}
|
|
4524
4802
|
return identifier;
|
|
4525
4803
|
}
|
|
4804
|
+
function pricedVideoSelection(opts) {
|
|
4805
|
+
const adjustments = [];
|
|
4806
|
+
const ltx = ltxPricedTier(opts.provider, opts.resolution, opts.duration);
|
|
4807
|
+
const resolution = opts.resolution ?? (ltx ? ltx.band : PRICING_DEFAULT_RESOLUTION[opts.provider]);
|
|
4808
|
+
if (!ltx) return { resolution, adjustments };
|
|
4809
|
+
const requested = typeof opts.duration === "string" ? parseInt(opts.duration, 10) : opts.duration;
|
|
4810
|
+
if (requested !== void 0 && !Number.isNaN(requested) && requested !== ltx.duration) {
|
|
4811
|
+
adjustments.push({
|
|
4812
|
+
field: "duration",
|
|
4813
|
+
from: requested,
|
|
4814
|
+
to: ltx.duration,
|
|
4815
|
+
reason: `LTX renders ${ltx.band} in ${ltx.duration}s steps \u2014 using ${ltx.duration}s instead of ${requested}s.`
|
|
4816
|
+
});
|
|
4817
|
+
}
|
|
4818
|
+
return { resolution, duration: ltx.duration, adjustments };
|
|
4819
|
+
}
|
|
4526
4820
|
function buildMotionCreditModelIdentifier(provider, resolution, videoDuration) {
|
|
4527
4821
|
if (provider === "wan-animate-move" || provider === "wan-animate-replace") {
|
|
4528
4822
|
if (resolution === "580p" || resolution === "720p") {
|
|
@@ -4537,6 +4831,28 @@ function buildMotionCreditModelIdentifier(provider, resolution, videoDuration) {
|
|
|
4537
4831
|
const resSuffix = resolution === "1080p" ? ":1080p" : "";
|
|
4538
4832
|
return `${base}${resSuffix}:${tier.suffix}`;
|
|
4539
4833
|
}
|
|
4834
|
+
var SUNO_VERSION_PRICED_OPERATIONS = [
|
|
4835
|
+
"suno-generate",
|
|
4836
|
+
"suno-cover",
|
|
4837
|
+
"suno-extend"
|
|
4838
|
+
];
|
|
4839
|
+
var SUNO_SELECT_OPERATIONS = [
|
|
4840
|
+
"suno-generate",
|
|
4841
|
+
"suno-cover",
|
|
4842
|
+
"suno-extend",
|
|
4843
|
+
"suno-mashup",
|
|
4844
|
+
"suno-add-instrumental",
|
|
4845
|
+
"suno-add-vocals",
|
|
4846
|
+
"suno-upload-extend"
|
|
4847
|
+
];
|
|
4848
|
+
function sunoCreditType(model, operation) {
|
|
4849
|
+
if (!SUNO_VERSION_PRICED_OPERATIONS.includes(operation)) {
|
|
4850
|
+
return operation;
|
|
4851
|
+
}
|
|
4852
|
+
if (model === "V5_5") return "suno-v5_5";
|
|
4853
|
+
if (model === "V5") return "suno-v5";
|
|
4854
|
+
return operation;
|
|
4855
|
+
}
|
|
4540
4856
|
|
|
4541
4857
|
// src/credit-estimators/video-utils.ts
|
|
4542
4858
|
var VIDEO_UTIL_PRICING = {
|
|
@@ -4626,6 +4942,71 @@ function extractVideoDurationFromNode(data) {
|
|
|
4626
4942
|
return void 0;
|
|
4627
4943
|
}
|
|
4628
4944
|
|
|
4945
|
+
// src/topaz-upscale.ts
|
|
4946
|
+
var TOPAZ_UPSCALE_FACTORS = ["1", "2", "4"];
|
|
4947
|
+
var TOPAZ_DEFAULT_UPSCALE_FACTOR = "2";
|
|
4948
|
+
var LEGACY_TIER_TO_FACTOR = {
|
|
4949
|
+
"2K": "2",
|
|
4950
|
+
"4K": "4",
|
|
4951
|
+
"8K": "4"
|
|
4952
|
+
};
|
|
4953
|
+
function isFactor(v) {
|
|
4954
|
+
return TOPAZ_UPSCALE_FACTORS.includes(v);
|
|
4955
|
+
}
|
|
4956
|
+
function resolveTopazUpscale(input) {
|
|
4957
|
+
const adjustments = [];
|
|
4958
|
+
const rawFactor = typeof input.upscaleFactor === "string" ? input.upscaleFactor : "";
|
|
4959
|
+
const rawTier = typeof input.targetResolution === "string" ? input.targetResolution : "";
|
|
4960
|
+
const trimmedFactor = rawFactor.trim();
|
|
4961
|
+
const normalizedTier = rawTier.trim().toUpperCase();
|
|
4962
|
+
const factorGiven = trimmedFactor.length > 0;
|
|
4963
|
+
const factorValid = factorGiven && isFactor(trimmedFactor);
|
|
4964
|
+
const tierGiven = normalizedTier.length > 0;
|
|
4965
|
+
const tierMappedFactor = tierGiven ? LEGACY_TIER_TO_FACTOR[normalizedTier] : void 0;
|
|
4966
|
+
const finalFactor = factorValid ? trimmedFactor : tierMappedFactor ?? TOPAZ_DEFAULT_UPSCALE_FACTOR;
|
|
4967
|
+
if (factorGiven && !factorValid) {
|
|
4968
|
+
adjustments.push({
|
|
4969
|
+
field: "upscaleFactor",
|
|
4970
|
+
from: rawFactor,
|
|
4971
|
+
to: finalFactor,
|
|
4972
|
+
reason: `Topaz upscale accepts a factor of 1, 2 or 4 \u2014 "${rawFactor}" was replaced with ${finalFactor}.`
|
|
4973
|
+
});
|
|
4974
|
+
}
|
|
4975
|
+
if (factorValid && tierGiven) {
|
|
4976
|
+
if (tierMappedFactor !== finalFactor) {
|
|
4977
|
+
adjustments.push({
|
|
4978
|
+
field: "targetResolution",
|
|
4979
|
+
from: rawTier,
|
|
4980
|
+
to: void 0,
|
|
4981
|
+
reason: "upscaleFactor takes precedence over the legacy targetResolution."
|
|
4982
|
+
});
|
|
4983
|
+
}
|
|
4984
|
+
} else if (!factorValid && tierGiven) {
|
|
4985
|
+
if (tierMappedFactor) {
|
|
4986
|
+
if (normalizedTier === "8K") {
|
|
4987
|
+
adjustments.push({
|
|
4988
|
+
field: "targetResolution",
|
|
4989
|
+
from: rawTier,
|
|
4990
|
+
to: finalFactor,
|
|
4991
|
+
reason: "Topaz upscale offers factors up to 4x \u2014 an 8K target renders and bills at the 4x tier."
|
|
4992
|
+
});
|
|
4993
|
+
}
|
|
4994
|
+
} else {
|
|
4995
|
+
adjustments.push({
|
|
4996
|
+
field: "targetResolution",
|
|
4997
|
+
from: rawTier,
|
|
4998
|
+
to: finalFactor,
|
|
4999
|
+
reason: `Unknown Topaz target "${rawTier}" \u2014 rendering at ${finalFactor}x.`
|
|
5000
|
+
});
|
|
5001
|
+
}
|
|
5002
|
+
}
|
|
5003
|
+
return {
|
|
5004
|
+
upscaleFactor: finalFactor,
|
|
5005
|
+
creditTier: finalFactor === "4" ? "4K" : void 0,
|
|
5006
|
+
adjustments
|
|
5007
|
+
};
|
|
5008
|
+
}
|
|
5009
|
+
|
|
4629
5010
|
// src/presentation-utils.ts
|
|
4630
5011
|
var INPUT_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
4631
5012
|
"text-prompt",
|
|
@@ -6398,6 +6779,35 @@ function resolveNodeRefs(text, labelToOutput) {
|
|
|
6398
6779
|
}
|
|
6399
6780
|
return result;
|
|
6400
6781
|
}
|
|
6782
|
+
var REF_TOKEN_NAMESPACE_PREFIXES = [
|
|
6783
|
+
"image:",
|
|
6784
|
+
"video:",
|
|
6785
|
+
"audio:",
|
|
6786
|
+
"slot:",
|
|
6787
|
+
"ref:"
|
|
6788
|
+
];
|
|
6789
|
+
function classifyRefToken(name, resolvable) {
|
|
6790
|
+
const lower = name.toLowerCase();
|
|
6791
|
+
if (name === "" || REF_TOKEN_NAMESPACE_PREFIXES.some((p) => lower.startsWith(p))) return "skip";
|
|
6792
|
+
if (RESERVED_TEMPLATE_VARS.has(name)) return "reserved";
|
|
6793
|
+
if (resolvable === null) return "unknown";
|
|
6794
|
+
return resolvable.has(canonicalVarName(name)) ? "wired" : "missing";
|
|
6795
|
+
}
|
|
6796
|
+
function unresolvedRefTokens(text, opts) {
|
|
6797
|
+
if (typeof text !== "string" || text.length === 0) return [];
|
|
6798
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6799
|
+
const out = [];
|
|
6800
|
+
for (const m of text.matchAll(NODE_REF_PATTERN)) {
|
|
6801
|
+
const { name, fallback } = parseNodeRef(m[1] ?? "");
|
|
6802
|
+
if (fallback !== null) continue;
|
|
6803
|
+
if (classifyRefToken(name, opts.resolvable) !== "missing") continue;
|
|
6804
|
+
const canon = canonicalVarName(name);
|
|
6805
|
+
if (opts.known.has(canon) || seen.has(canon)) continue;
|
|
6806
|
+
seen.add(canon);
|
|
6807
|
+
out.push(name);
|
|
6808
|
+
}
|
|
6809
|
+
return out;
|
|
6810
|
+
}
|
|
6401
6811
|
|
|
6402
6812
|
// src/filter-condition.ts
|
|
6403
6813
|
function tryParseJson(item) {
|
|
@@ -9584,6 +9994,18 @@ function togglePick(current, id, maxSelected) {
|
|
|
9584
9994
|
return [...current.slice(1), id];
|
|
9585
9995
|
}
|
|
9586
9996
|
|
|
9997
|
+
// src/safety-retry-policy.ts
|
|
9998
|
+
function safetyRetryPolicy(modelId) {
|
|
9999
|
+
const entry = getModel(modelId);
|
|
10000
|
+
const safetyFilter = entry?.safetyFilter;
|
|
10001
|
+
if (!safetyFilter?.stochastic) return { maxAttempts: 1 };
|
|
10002
|
+
const fallback = safetyFilter.fallback;
|
|
10003
|
+
if (fallback && getModel(fallback)) {
|
|
10004
|
+
return { maxAttempts: 2, fallback };
|
|
10005
|
+
}
|
|
10006
|
+
return { maxAttempts: 2 };
|
|
10007
|
+
}
|
|
10008
|
+
|
|
9587
10009
|
// src/caption-styles.ts
|
|
9588
10010
|
var STATIC_CAPTION_STYLES = ["subtitle"];
|
|
9589
10011
|
var KINETIC_CAPTION_STYLES = [
|
|
@@ -9724,6 +10146,11 @@ var EXECUTION_DATA_KEYS = /* @__PURE__ */ new Set([
|
|
|
9724
10146
|
"currentJobId",
|
|
9725
10147
|
"currentJobProgress",
|
|
9726
10148
|
"errorMessage",
|
|
10149
|
+
// Structured detail alongside errorMessage for a safety-filter block
|
|
10150
|
+
// (see `JobErrorHint` in the app's frontend/src/types/nodes.ts). Same
|
|
10151
|
+
// lifecycle as errorMessage: a RESULT the user expects to survive reload,
|
|
10152
|
+
// never user-edited config.
|
|
10153
|
+
"errorHint",
|
|
9727
10154
|
"isStreaming",
|
|
9728
10155
|
"generatedImageUrl",
|
|
9729
10156
|
"generatedVideoUrl",
|
|
@@ -12525,7 +12952,9 @@ var DEFAULT_VOICE_CHANGER_MODEL = "eleven_multilingual_sts_v2";
|
|
|
12525
12952
|
// src/normalize-node-params.ts
|
|
12526
12953
|
var MODEL_PARAM_NODE_TYPES = /* @__PURE__ */ new Set([
|
|
12527
12954
|
"generate-image",
|
|
12528
|
-
"image-to-image"
|
|
12955
|
+
"image-to-image",
|
|
12956
|
+
"modify-image",
|
|
12957
|
+
"edit-image"
|
|
12529
12958
|
]);
|
|
12530
12959
|
function normalizeNodeModelParams(nodes) {
|
|
12531
12960
|
const adjustments = [];
|
|
@@ -13459,6 +13888,26 @@ var clipLookSchema = zod.z.object({
|
|
|
13459
13888
|
* insert) states the deviation in that scene's `visual`, as with `lighting`.
|
|
13460
13889
|
*/
|
|
13461
13890
|
style: zod.z.string().optional(),
|
|
13891
|
+
/**
|
|
13892
|
+
* The Style picker CATALOG ID the prose in `style` corresponds to — the
|
|
13893
|
+
* analyzer's PICK ("pixar-3d" beside "3D stylized animation"), not a second
|
|
13894
|
+
* description of it.
|
|
13895
|
+
*
|
|
13896
|
+
* Worth strictly more than the prose it accompanies: an id addresses the
|
|
13897
|
+
* catalog, so a recreation renders the same medium the product's own Style
|
|
13898
|
+
* picker would render, instead of re-interpreting a sentence. Absent when the
|
|
13899
|
+
* analyzer read a medium it could not place in the catalog — `style` then
|
|
13900
|
+
* carries the whole answer, as it always did.
|
|
13901
|
+
*
|
|
13902
|
+
* A free `string` here on purpose. The PRODUCER validates it against the
|
|
13903
|
+
* catalog (the analyzer plugin's wire schema is an enum generated from
|
|
13904
|
+
* `STYLES`, so an invented id never leaves it), while this package must not
|
|
13905
|
+
* carry the catalog itself. A closed enum here would only add a second copy
|
|
13906
|
+
* of the vocabulary to drift out of date — and, worse, would REJECT a
|
|
13907
|
+
* catalog entry newer than the installed `@nodaro/shared`, which is exactly
|
|
13908
|
+
* the analysis a consumer most wants to read.
|
|
13909
|
+
*/
|
|
13910
|
+
styleId: zod.z.string().optional(),
|
|
13462
13911
|
/** Colour grade / palette — "muted teal-and-orange, crushed blacks". */
|
|
13463
13912
|
grade: zod.z.string().optional(),
|
|
13464
13913
|
/** Camera or film FORMAT and stock — "anamorphic digital", "16mm film grain". */
|
|
@@ -13529,8 +13978,9 @@ var entitySlotSchema = zod.z.object({
|
|
|
13529
13978
|
/** NON-default looks only; present only when at least one exists. */
|
|
13530
13979
|
variations: zod.z.array(slotVariationSchema).max(VIDEO_ANALYSIS_MAX_VARIATIONS).optional()
|
|
13531
13980
|
});
|
|
13981
|
+
var VIDEO_ANALYSIS_AUDIO_MODES = ["speech", "music", "sfx", "ambience"];
|
|
13532
13982
|
var audioLayerSchema = zod.z.object({
|
|
13533
|
-
mode: zod.z.enum(
|
|
13983
|
+
mode: zod.z.enum(VIDEO_ANALYSIS_AUDIO_MODES),
|
|
13534
13984
|
content: zod.z.string().min(1),
|
|
13535
13985
|
voice: zod.z.string().optional(),
|
|
13536
13986
|
/**
|
|
@@ -13553,7 +14003,34 @@ var audioLayerSchema = zod.z.object({
|
|
|
13553
14003
|
* (doctrine §5), so attribution here would resurrect the phantom-entity
|
|
13554
14004
|
* defect that `stripOrphanSlots` exists to kill.
|
|
13555
14005
|
*/
|
|
13556
|
-
speakerSlot: zod.z.string().optional()
|
|
14006
|
+
speakerSlot: zod.z.string().optional(),
|
|
14007
|
+
/**
|
|
14008
|
+
* SPEECH ONLY — WHO says these words, by NAME.
|
|
14009
|
+
*
|
|
14010
|
+
* The second of two ways to name a speaker, and the one for documents that
|
|
14011
|
+
* have no slots: `speakerSlot` addresses an `EntitySlot` of THIS analysis by
|
|
14012
|
+
* id, while `speaker` is the plain cast name a production keys its own cast
|
|
14013
|
+
* by ("Jack Mercer"). A layer may legitimately carry both — the id for the
|
|
14014
|
+
* analysis it came from, the name for the document it is going into — and a
|
|
14015
|
+
* consumer that understands only one reads the one it understands.
|
|
14016
|
+
*
|
|
14017
|
+
* Optional, and not refined against `mode`, for the same reason
|
|
14018
|
+
* `speakerSlot` is not: the window schema is the enforced decode grammar and
|
|
14019
|
+
* must not throw away a whole roll over one mis-tagged field.
|
|
14020
|
+
*
|
|
14021
|
+
* NOT swept by `dropUnknownSpeakers`. That function is the SLOT channel's
|
|
14022
|
+
* sanitizer — it judges an id against the surviving slot list, and a name has
|
|
14023
|
+
* no id space to be unknown in. The asymmetry is deliberate and pinned by
|
|
14024
|
+
* test; whoever owns the name's vocabulary sanitizes the name.
|
|
14025
|
+
*
|
|
14026
|
+
* The residual that leaves: a layer can keep a `speaker` naming someone
|
|
14027
|
+
* `stripOrphanSlots` already pruned as a phantom, where the same claim spelled
|
|
14028
|
+
* `speakerSlot` would have been dropped — the invented-narrator defect, in the
|
|
14029
|
+
* one spelling the sweep cannot see. LATENT today, since nothing in this
|
|
14030
|
+
* repo emits `speaker`; the day the analyzer does, that sweep is what has to
|
|
14031
|
+
* grow, not this field.
|
|
14032
|
+
*/
|
|
14033
|
+
speaker: zod.z.string().optional()
|
|
13557
14034
|
});
|
|
13558
14035
|
var windowSceneBase = zod.z.object({
|
|
13559
14036
|
startSec: zod.z.number().min(0),
|
|
@@ -13771,6 +14248,23 @@ function inferMusicVideo(analysis) {
|
|
|
13771
14248
|
})
|
|
13772
14249
|
);
|
|
13773
14250
|
}
|
|
14251
|
+
var DERIVED_ANALYSIS_TOP_KEYS = /* @__PURE__ */ new Set(["warnings", "variationFolds"]);
|
|
14252
|
+
var DERIVED_ANALYSIS_SCENE_KEYS = /* @__PURE__ */ new Set(["visualResolved", "slotRefs", "oversized"]);
|
|
14253
|
+
var asRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
14254
|
+
function stripDerivedAnalysisFields(json) {
|
|
14255
|
+
const doc = asRecord(json);
|
|
14256
|
+
if (!doc) return json;
|
|
14257
|
+
const out = {};
|
|
14258
|
+
for (const [key, value] of Object.entries(doc)) {
|
|
14259
|
+
if (DERIVED_ANALYSIS_TOP_KEYS.has(key)) continue;
|
|
14260
|
+
out[key] = key === "scenes" && Array.isArray(value) ? value.map((scene) => {
|
|
14261
|
+
const s = asRecord(scene);
|
|
14262
|
+
if (!s) return scene;
|
|
14263
|
+
return Object.fromEntries(Object.entries(s).filter(([k]) => !DERIVED_ANALYSIS_SCENE_KEYS.has(k)));
|
|
14264
|
+
}) : value;
|
|
14265
|
+
}
|
|
14266
|
+
return out;
|
|
14267
|
+
}
|
|
13774
14268
|
|
|
13775
14269
|
// src/video-analysis-pricing.ts
|
|
13776
14270
|
var VIDEO_ANALYSIS_DURATION_BUCKETS = [60, 180, 360, 600];
|
|
@@ -13895,6 +14389,7 @@ var WORKFLOW_VISIBILITIES = ["private", "workspace"];
|
|
|
13895
14389
|
var ACCESS_LEVELS = ["own", "edit", "view", "none"];
|
|
13896
14390
|
var GRANTED_ACCESS = ["view", "edit"];
|
|
13897
14391
|
var SUBMISSION_STATUSES = ["submitted", "in_review", "returned", "approved"];
|
|
14392
|
+
var USAGE_GROUP_BYS = ["workspace", "member", "model", "day", "none"];
|
|
13898
14393
|
var ORG_ERROR_CODES = [
|
|
13899
14394
|
"not_a_member",
|
|
13900
14395
|
"insufficient_role",
|
|
@@ -13914,6 +14409,8 @@ var ORG_ERROR_CODES = [
|
|
|
13914
14409
|
"domain_not_allowed",
|
|
13915
14410
|
"already_started",
|
|
13916
14411
|
"collab_unavailable",
|
|
14412
|
+
// A CSV usage export whose write-ahead audit row could not be written (503).
|
|
14413
|
+
"audit_unavailable",
|
|
13917
14414
|
// Organization, workspace and membership endpoints.
|
|
13918
14415
|
"terms_required",
|
|
13919
14416
|
"not_org_member",
|
|
@@ -14216,6 +14713,7 @@ exports.HINT_EXEMPT_PARAMETER_TYPES = HINT_EXEMPT_PARAMETER_TYPES;
|
|
|
14216
14713
|
exports.I2I_MASK_SUPPORT = I2I_MASK_SUPPORT;
|
|
14217
14714
|
exports.I2I_STRENGTH_SUPPORT = I2I_STRENGTH_SUPPORT;
|
|
14218
14715
|
exports.IDEOGRAM_PROVIDERS = IDEOGRAM_PROVIDERS;
|
|
14716
|
+
exports.IMAGE_ASPECT_RATIO_VALUES = IMAGE_ASPECT_RATIO_VALUES;
|
|
14219
14717
|
exports.IMAGE_CRITIC_LEAF_MODES = IMAGE_CRITIC_LEAF_MODES;
|
|
14220
14718
|
exports.IMAGE_CRITIC_MAX_RETRIES = IMAGE_CRITIC_MAX_RETRIES;
|
|
14221
14719
|
exports.IMAGE_CRITIC_METADATA_KEYS = IMAGE_CRITIC_METADATA_KEYS;
|
|
@@ -14372,6 +14870,7 @@ exports.REFERENCE_HANDLE_MAP = REFERENCE_HANDLE_MAP;
|
|
|
14372
14870
|
exports.REFERENCE_ROLE_PRESETS = REFERENCE_ROLE_PRESETS;
|
|
14373
14871
|
exports.REF_HANDLE_CATEGORY = REF_HANDLE_CATEGORY;
|
|
14374
14872
|
exports.REF_IMAGE_MAX_LIMITS = REF_IMAGE_MAX_LIMITS;
|
|
14873
|
+
exports.REF_TOKEN_NAMESPACE_PREFIXES = REF_TOKEN_NAMESPACE_PREFIXES;
|
|
14375
14874
|
exports.RENDERING_SPEED_SUPPORT = RENDERING_SPEED_SUPPORT;
|
|
14376
14875
|
exports.REPEATABLE_NODE_TYPES = REPEATABLE_NODE_TYPES;
|
|
14377
14876
|
exports.REPEAT_PLACEHOLDER = REPEAT_PLACEHOLDER;
|
|
@@ -14416,10 +14915,13 @@ exports.STRUCTURED_VISION_MODELS = STRUCTURED_VISION_MODELS;
|
|
|
14416
14915
|
exports.SUBMISSION_STATUSES = SUBMISSION_STATUSES;
|
|
14417
14916
|
exports.SUNO_ADD_TRACK_MODELS = SUNO_ADD_TRACK_MODELS;
|
|
14418
14917
|
exports.SUNO_FIELD_HANDLE_FIELDS = SUNO_FIELD_HANDLE_FIELDS;
|
|
14918
|
+
exports.SUNO_HARD_CEILING = SUNO_HARD_CEILING;
|
|
14419
14919
|
exports.SUNO_MODELS = SUNO_MODELS;
|
|
14920
|
+
exports.SUNO_SELECT_OPERATIONS = SUNO_SELECT_OPERATIONS;
|
|
14420
14921
|
exports.SUNO_TEXT_MAX = SUNO_TEXT_MAX;
|
|
14421
14922
|
exports.SUNO_TITLE_MAX = SUNO_TITLE_MAX;
|
|
14422
14923
|
exports.SUNO_TRACK_SOURCE_TYPES = SUNO_TRACK_SOURCE_TYPES;
|
|
14924
|
+
exports.SUNO_VERSION_PRICED_OPERATIONS = SUNO_VERSION_PRICED_OPERATIONS;
|
|
14423
14925
|
exports.SUPPORTED_FONT_NAMES = SUPPORTED_FONT_NAMES;
|
|
14424
14926
|
exports.SURROUND_DIRECTIONS = SURROUND_DIRECTIONS;
|
|
14425
14927
|
exports.SWITCHX_BLOCK_FRAMES = SWITCHX_BLOCK_FRAMES;
|
|
@@ -14443,6 +14945,8 @@ exports.TEXT_TO_VIDEO_PROVIDERS = TEXT_TO_VIDEO_PROVIDERS;
|
|
|
14443
14945
|
exports.TIER_MAX_PIPELINE_COST_CREDITS = TIER_MAX_PIPELINE_COST_CREDITS;
|
|
14444
14946
|
exports.TIER_PIPELINE_PARALLELISM = TIER_PIPELINE_PARALLELISM;
|
|
14445
14947
|
exports.TILT_CARRIED_FRACTION = TILT_CARRIED_FRACTION;
|
|
14948
|
+
exports.TOPAZ_DEFAULT_UPSCALE_FACTOR = TOPAZ_DEFAULT_UPSCALE_FACTOR;
|
|
14949
|
+
exports.TOPAZ_UPSCALE_FACTORS = TOPAZ_UPSCALE_FACTORS;
|
|
14446
14950
|
exports.TRANSCRIBE_PROVIDERS = TRANSCRIBE_PROVIDERS;
|
|
14447
14951
|
exports.TRANSIENT_RUNTIME_KEYS = TRANSIENT_RUNTIME_KEYS;
|
|
14448
14952
|
exports.TTS_PROVIDERS = TTS_PROVIDERS;
|
|
@@ -14450,6 +14954,7 @@ exports.TTS_TEXT_MAX = TTS_TEXT_MAX;
|
|
|
14450
14954
|
exports.TWO_K_RESOLUTION_PROVIDERS = TWO_K_RESOLUTION_PROVIDERS;
|
|
14451
14955
|
exports.TransitionTypeSchema = TransitionTypeSchema;
|
|
14452
14956
|
exports.UPSCALE_IMAGE_PROVIDERS = UPSCALE_IMAGE_PROVIDERS;
|
|
14957
|
+
exports.USAGE_GROUP_BYS = USAGE_GROUP_BYS;
|
|
14453
14958
|
exports.USAGE_MODES = USAGE_MODES;
|
|
14454
14959
|
exports.VARIABLES_HANDLE_ID = VARIABLES_HANDLE_ID;
|
|
14455
14960
|
exports.VARIABLE_PRICING_MODELS = VARIABLE_PRICING_MODELS;
|
|
@@ -14457,6 +14962,7 @@ exports.VEHICLES = VEHICLES;
|
|
|
14457
14962
|
exports.VEHICLE_SUBCATEGORY_LABELS = VEHICLE_SUBCATEGORY_LABELS;
|
|
14458
14963
|
exports.VEHICLE_SUBCATEGORY_ORDER = VEHICLE_SUBCATEGORY_ORDER;
|
|
14459
14964
|
exports.VEO_PROVIDERS = VEO_PROVIDERS;
|
|
14965
|
+
exports.VIDEO_ANALYSIS_AUDIO_MODES = VIDEO_ANALYSIS_AUDIO_MODES;
|
|
14460
14966
|
exports.VIDEO_ANALYSIS_BUCKET_CREDITS = VIDEO_ANALYSIS_BUCKET_CREDITS;
|
|
14461
14967
|
exports.VIDEO_ANALYSIS_CLIP_TRANSITIONS_IN = VIDEO_ANALYSIS_CLIP_TRANSITIONS_IN;
|
|
14462
14968
|
exports.VIDEO_ANALYSIS_DEFAULT_VARIATION = VIDEO_ANALYSIS_DEFAULT_VARIATION;
|
|
@@ -14501,6 +15007,7 @@ exports.VIDEO_PROMPT_MAX = VIDEO_PROMPT_MAX;
|
|
|
14501
15007
|
exports.VIDEO_PROVIDERS_REQUIRING_IMAGE = VIDEO_PROVIDERS_REQUIRING_IMAGE;
|
|
14502
15008
|
exports.VIDEO_PROVIDERS_WITHOUT_DISPATCH = VIDEO_PROVIDERS_WITHOUT_DISPATCH;
|
|
14503
15009
|
exports.VIDEO_REF_LIMITS_BY_PROVIDER = VIDEO_REF_LIMITS_BY_PROVIDER;
|
|
15010
|
+
exports.VIDEO_REF_VIDEO_DURATION_LIMITS = VIDEO_REF_VIDEO_DURATION_LIMITS;
|
|
14504
15011
|
exports.VIDEO_TO_VIDEO_PROVIDERS = VIDEO_TO_VIDEO_PROVIDERS;
|
|
14505
15012
|
exports.VIDEO_UPSCALE_PROVIDERS = VIDEO_UPSCALE_PROVIDERS;
|
|
14506
15013
|
exports.VIDEO_UTIL_PRICING = VIDEO_UTIL_PRICING;
|
|
@@ -14569,9 +15076,11 @@ exports.characterMentionSlug = characterMentionSlug;
|
|
|
14569
15076
|
exports.characterMentionableAssetArrays = characterMentionableAssetArrays;
|
|
14570
15077
|
exports.characterSheetRefItems = characterSheetRefItems;
|
|
14571
15078
|
exports.characterVariantAssetArrays = characterVariantAssetArrays;
|
|
15079
|
+
exports.checkRefVideoDurations = checkRefVideoDurations;
|
|
14572
15080
|
exports.cinematicCreditId = cinematicCreditId;
|
|
14573
15081
|
exports.clampCinematicDuration = clampCinematicDuration;
|
|
14574
15082
|
exports.clampSmartCutWindow = clampSmartCutWindow;
|
|
15083
|
+
exports.classifyRefToken = classifyRefToken;
|
|
14575
15084
|
exports.cleanOrphanedItems = cleanOrphanedItems;
|
|
14576
15085
|
exports.clearImageCriticMetadata = clearImageCriticMetadata;
|
|
14577
15086
|
exports.clearVideoCriticMetadata = clearVideoCriticMetadata;
|
|
@@ -14746,6 +15255,7 @@ exports.normalizeModelInput = normalizeModelInput;
|
|
|
14746
15255
|
exports.normalizeNodeModelParams = normalizeNodeModelParams;
|
|
14747
15256
|
exports.normalizePinterestUrl = normalizePinterestUrl;
|
|
14748
15257
|
exports.normalizeRoleSlug = normalizeRoleSlug;
|
|
15258
|
+
exports.normalizeVideoRequestParams = normalizeVideoRequestParams;
|
|
14749
15259
|
exports.normalizeWan3Resolution = normalizeWan3Resolution;
|
|
14750
15260
|
exports.orderedLlmModels = orderedLlmModels;
|
|
14751
15261
|
exports.parseAttributedDialogue = parseAttributedDialogue;
|
|
@@ -14770,6 +15280,7 @@ exports.presentTypes = presentTypes;
|
|
|
14770
15280
|
exports.presetApplyClearKeys = presetApplyClearKeys;
|
|
14771
15281
|
exports.presetDataMatches = presetDataMatches;
|
|
14772
15282
|
exports.presetEntries = presetEntries;
|
|
15283
|
+
exports.pricedVideoSelection = pricedVideoSelection;
|
|
14773
15284
|
exports.qualityOptionsByKind = qualityOptionsByKind;
|
|
14774
15285
|
exports.readPromptAffixes = readPromptAffixes;
|
|
14775
15286
|
exports.refHandleCategory = refHandleCategory;
|
|
@@ -14802,6 +15313,7 @@ exports.resolveLocationFields = resolveLocationFields;
|
|
|
14802
15313
|
exports.resolveLocationPresetCatalog = resolveLocationPresetCatalog;
|
|
14803
15314
|
exports.resolveLottieOverlaySrc = resolveLottieOverlaySrc;
|
|
14804
15315
|
exports.resolveNodeRefs = resolveNodeRefs;
|
|
15316
|
+
exports.resolveNormalizedImageGen = resolveNormalizedImageGen;
|
|
14805
15317
|
exports.resolveObjectAspectRatio = resolveObjectAspectRatio;
|
|
14806
15318
|
exports.resolvePipelineModel = resolvePipelineModel;
|
|
14807
15319
|
exports.resolveRelativeWindowToken = resolveRelativeWindowToken;
|
|
@@ -14813,6 +15325,7 @@ exports.resolveSlideshowTransition = resolveSlideshowTransition;
|
|
|
14813
15325
|
exports.resolveSourceThroughConnectedList = resolveSourceThroughConnectedList;
|
|
14814
15326
|
exports.resolveStoredTier = resolveStoredTier;
|
|
14815
15327
|
exports.resolveSwitchXCreditId = resolveSwitchXCreditId;
|
|
15328
|
+
exports.resolveTopazUpscale = resolveTopazUpscale;
|
|
14816
15329
|
exports.resolveVideoAnalysisModel = resolveVideoAnalysisModel;
|
|
14817
15330
|
exports.resolveVideoModeForInputs = resolveVideoModeForInputs;
|
|
14818
15331
|
exports.resolveVideoProviderForMode = resolveVideoProviderForMode;
|
|
@@ -14823,6 +15336,7 @@ exports.rewriteSpeakerSlots = rewriteSpeakerSlots;
|
|
|
14823
15336
|
exports.rgbaArrayToHex = rgbaArrayToHex;
|
|
14824
15337
|
exports.roleToPhrase = roleToPhrase;
|
|
14825
15338
|
exports.runSelector = runSelector;
|
|
15339
|
+
exports.safetyRetryPolicy = safetyRetryPolicy;
|
|
14826
15340
|
exports.sanitizeRole = sanitizeRole;
|
|
14827
15341
|
exports.searchModelVariants = searchModelVariants;
|
|
14828
15342
|
exports.seedance2AudioLimitSec = seedance2AudioLimitSec;
|
|
@@ -14844,8 +15358,10 @@ exports.splitByLoopDelimiter = splitByLoopDelimiter;
|
|
|
14844
15358
|
exports.splitGeneratedItems = splitGeneratedItems;
|
|
14845
15359
|
exports.spreadJsonArrayIfSingleton = spreadJsonArrayIfSingleton;
|
|
14846
15360
|
exports.stringifyPathResults = stringifyPathResults;
|
|
15361
|
+
exports.stripDerivedAnalysisFields = stripDerivedAnalysisFields;
|
|
14847
15362
|
exports.stripExportContent = stripExportContent;
|
|
14848
15363
|
exports.stripTransientRuntimeData = stripTransientRuntimeData;
|
|
15364
|
+
exports.sunoCreditType = sunoCreditType;
|
|
14849
15365
|
exports.supportedDefaultDimensions = supportedDefaultDimensions;
|
|
14850
15366
|
exports.supportsAdvancedMode = supportsAdvancedMode;
|
|
14851
15367
|
exports.supportsEndAnchor = supportsEndAnchor;
|
|
@@ -14857,6 +15373,7 @@ exports.tryParseJson = tryParseJson;
|
|
|
14857
15373
|
exports.uiAspectRatioFill = uiAspectRatioFill;
|
|
14858
15374
|
exports.uiDurationFill = uiDurationFill;
|
|
14859
15375
|
exports.uiResolutionFill = uiResolutionFill;
|
|
15376
|
+
exports.unresolvedRefTokens = unresolvedRefTokens;
|
|
14860
15377
|
exports.unwrapUnresolvedTokens = unwrapUnresolvedTokens;
|
|
14861
15378
|
exports.usageModeDirective = usageModeDirective;
|
|
14862
15379
|
exports.usageModeIncludesName = usageModeIncludesName;
|