@nodaro/shared 3.8.0 → 3.10.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 +325 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +806 -41
- package/dist/index.d.ts +806 -41
- package/dist/index.js +295 -64
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/credit-identifiers.test.ts +51 -1
- package/src/__tests__/gvp-supported-providers.test.ts +20 -3
- package/src/__tests__/model-catalog-sections.test.ts +59 -0
- package/src/__tests__/model-tree.test.ts +5 -2
- package/src/__tests__/parameter-node-value.test.ts +35 -0
- package/src/__tests__/pricing-default-duration.test.ts +45 -0
- package/src/__tests__/prompt-length-limits.test.ts +4 -0
- package/src/__tests__/scene3d-delivery-review.test.ts +512 -0
- package/src/__tests__/suno-credit-type.test.ts +46 -0
- package/src/__tests__/template-categories.test.ts +45 -0
- package/src/__tests__/video-ref-limits.test.ts +11 -2
- package/src/credit-identifiers.ts +64 -14
- package/src/i18n/camera-motions.ar.ts +5 -5
- package/src/i18n/camera-motions.de.ts +5 -5
- package/src/i18n/camera-motions.es.ts +5 -5
- package/src/i18n/camera-motions.fr.ts +5 -5
- package/src/i18n/camera-motions.he.ts +5 -5
- package/src/i18n/camera-motions.hi.ts +5 -5
- package/src/i18n/camera-motions.ja.ts +5 -5
- package/src/i18n/camera-motions.ko.ts +5 -5
- package/src/i18n/camera-motions.pt-BR.ts +5 -5
- package/src/i18n/camera-motions.ru.ts +5 -5
- package/src/i18n/camera-motions.zh-CN.ts +5 -5
- package/src/i18n/character-motion.ar.ts +1031 -0
- package/src/i18n/character-motion.de.ts +1031 -0
- package/src/i18n/character-motion.es.ts +1031 -0
- package/src/i18n/character-motion.fr.ts +1031 -0
- package/src/i18n/character-motion.he.ts +1031 -0
- package/src/i18n/character-motion.hi.ts +1031 -0
- package/src/i18n/character-motion.ja.ts +1031 -0
- package/src/i18n/character-motion.ko.ts +1031 -0
- package/src/i18n/character-motion.pt-BR.ts +1031 -0
- package/src/i18n/character-motion.ru.ts +1031 -0
- package/src/i18n/character-motion.zh-CN.ts +1031 -0
- package/src/i18n/types.ts +1 -0
- package/src/index.ts +28 -0
- package/src/model-catalog.ts +88 -35
- package/src/model-constants.ts +118 -24
- package/src/node-execution-state.ts +95 -0
- package/src/parameter-node-value.ts +33 -0
- package/src/presentation-utils.ts +1 -0
- package/src/pro-3d-render.ts +159 -0
- package/src/scene3d-delivery-notes.ts +490 -0
- package/src/scene3d-v2-plan.ts +8 -2
- package/src/smart-cut-windows.ts +15 -10
- package/src/template-categories.ts +67 -0
package/src/i18n/types.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -89,6 +89,12 @@ export {
|
|
|
89
89
|
AI_WRITER_PROVIDERS,
|
|
90
90
|
QA_CHECK_PROVIDERS,
|
|
91
91
|
SUNO_MODELS,
|
|
92
|
+
SUNO_ACTIVE_MODELS,
|
|
93
|
+
SUNO_LEGACY_MODELS,
|
|
94
|
+
DEFAULT_SUNO_MODEL,
|
|
95
|
+
SUNO_DURATION_MODELS,
|
|
96
|
+
isLegacySunoModel,
|
|
97
|
+
sunoModelHonoursDuration,
|
|
92
98
|
SUNO_ADD_TRACK_MODELS,
|
|
93
99
|
VOICE_DESIGN_MODELS,
|
|
94
100
|
DEFAULT_VOICE_DESIGN_MODEL,
|
|
@@ -161,6 +167,7 @@ export {
|
|
|
161
167
|
DEFAULT_VIDEO_DURATION_SEC,
|
|
162
168
|
applyDefaultVideoSelection,
|
|
163
169
|
PRICING_DEFAULT_DURATION_SEC,
|
|
170
|
+
pricedOutputDurationSec,
|
|
164
171
|
PRICING_DEFAULT_RESOLUTION,
|
|
165
172
|
} from "./model-constants.js"
|
|
166
173
|
|
|
@@ -247,6 +254,7 @@ export {
|
|
|
247
254
|
pricedVideoSelection,
|
|
248
255
|
buildMotionCreditModelIdentifier,
|
|
249
256
|
sunoCreditType,
|
|
257
|
+
SUNO_VERSION_CREDIT_KEYS,
|
|
250
258
|
SUNO_VERSION_PRICED_OPERATIONS,
|
|
251
259
|
SUNO_SELECT_OPERATIONS,
|
|
252
260
|
} from "./credit-identifiers.js"
|
|
@@ -540,6 +548,8 @@ export type { LocationCatalogRef } from "./location-preset-catalog-map.js"
|
|
|
540
548
|
export {
|
|
541
549
|
PARAMETER_NODE_TYPES,
|
|
542
550
|
HINT_EXEMPT_PARAMETER_TYPES,
|
|
551
|
+
VIDEO_ONLY_PARAMETER_NODE_TYPES,
|
|
552
|
+
EXECUTION_GRAPH_COMPOSED_PARAMETER_TYPES,
|
|
543
553
|
getParameterValue,
|
|
544
554
|
setRegisteredPersonPackFields,
|
|
545
555
|
} from "./parameter-node-value.js"
|
|
@@ -724,6 +734,8 @@ export {
|
|
|
724
734
|
MODEL_RECOMMENDATIONS,
|
|
725
735
|
listModels,
|
|
726
736
|
groupByFamily,
|
|
737
|
+
groupByKindAndFamily,
|
|
738
|
+
MODEL_KINDS,
|
|
727
739
|
getModel,
|
|
728
740
|
validateModelInput,
|
|
729
741
|
// Frontend picker derivers
|
|
@@ -970,6 +982,16 @@ export type { VoiceChangerModel } from "./voice-changer-models.js"
|
|
|
970
982
|
// --- Node presets ---
|
|
971
983
|
export { EXECUTION_DATA_KEYS, TRANSIENT_RUNTIME_KEYS, stripTransientRuntimeData } from "./node-runtime-keys.js"
|
|
972
984
|
|
|
985
|
+
// --- Execution node state (wire contract) ---
|
|
986
|
+
export {
|
|
987
|
+
OUTPUT_BEARING_NODE_STATUSES,
|
|
988
|
+
nodeStateMayCarryOutput,
|
|
989
|
+
} from "./node-execution-state.js"
|
|
990
|
+
export type {
|
|
991
|
+
NodeExecutionStatus,
|
|
992
|
+
NodeExecutionStateWire,
|
|
993
|
+
} from "./node-execution-state.js"
|
|
994
|
+
|
|
973
995
|
export {
|
|
974
996
|
MODEL_PARAM_NODE_TYPES,
|
|
975
997
|
normalizeNodeModelParams,
|
|
@@ -996,6 +1018,9 @@ export * from "./reference-sheet/index.js"
|
|
|
996
1018
|
// --- Reference Board (templates + provider constant) ---
|
|
997
1019
|
export * from "./reference-board-templates.js"
|
|
998
1020
|
|
|
1021
|
+
// --- Marketplace template categories (the eight use cases) ---
|
|
1022
|
+
export * from "./template-categories.js"
|
|
1023
|
+
|
|
999
1024
|
// --- Model tree (derive node targets + product-line grouping for the Models tab) ---
|
|
1000
1025
|
export * from "./model-tree.js"
|
|
1001
1026
|
|
|
@@ -1064,6 +1089,9 @@ export * from "./scene3d-v2.js"
|
|
|
1064
1089
|
export * from "./scene3d-v2-plan.js"
|
|
1065
1090
|
export * from "./scene3d-v2-resources.js"
|
|
1066
1091
|
export * from "./scene3d-camera-track.js"
|
|
1092
|
+
// --- What an authoring run says about its own answer: assumptions, summary,
|
|
1093
|
+
// repair count. Additive and optional on every Scene3D authoring lane. ---
|
|
1094
|
+
export * from "./scene3d-delivery-notes.js"
|
|
1067
1095
|
// --- 3D Render Pro: one durable operation, scene + video in one result ---
|
|
1068
1096
|
export * from "./pro-3d-render.js"
|
|
1069
1097
|
// --- Scene3D render pricing: which frame-size tier a render settles at.
|
package/src/model-catalog.ts
CHANGED
|
@@ -52,7 +52,6 @@ export type ModelMode =
|
|
|
52
52
|
| "music"
|
|
53
53
|
| "sfx"
|
|
54
54
|
| "stt"
|
|
55
|
-
| "voice-clone"
|
|
56
55
|
| "voice-design"
|
|
57
56
|
| "voice-changer"
|
|
58
57
|
| "isolation"
|
|
@@ -207,7 +206,7 @@ export const MODEL_RECOMMENDATIONS: readonly ModelRecommendation[] = [
|
|
|
207
206
|
{ 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." },
|
|
208
207
|
{ intent: "cheap batch video clips", modelIds: ["veo3.1", "wan-turbo", "bytedance-lite"], note: "VEO 3.1 Fast is the best price/quality balance with native audio." },
|
|
209
208
|
{ intent: "video with start + end frame", modelIds: ["veo3", "veo3.1", "kling-turbo", "minimax", "hailuo-standard", "seedance-2"], note: "All listed support an end frame; VEO uses imageUrls[start, end]." },
|
|
210
|
-
{ intent: "music / song generation", modelIds: ["suno-
|
|
209
|
+
{ 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." },
|
|
211
210
|
{ intent: "voice over / narration", modelIds: ["elevenlabs-v3", "elevenlabs-turbo"], note: "v3 supports [audio tags] for emotion; Turbo is cheaper for plain narration." },
|
|
212
211
|
{ intent: "lip-sync a portrait to audio", modelIds: ["kling-avatar-pro", "kling-avatar", "infinitalk"], note: "Pro for best mouth shape; InfiniTalk for resolution control." },
|
|
213
212
|
{ intent: "transcription / captions", modelIds: ["elevenlabs-stt"], note: "Word-level timestamps available." },
|
|
@@ -755,23 +754,8 @@ const IMAGE_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
755
754
|
{ identifier: "ideogram-remix:QUALITY", credits: 60, note: "best quality" },
|
|
756
755
|
],
|
|
757
756
|
},
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
kind: "image",
|
|
761
|
-
modes: ["edit"] as const,
|
|
762
|
-
family: "Ideogram",
|
|
763
|
-
label: "Ideogram Reframe",
|
|
764
|
-
series: "Ideogram",
|
|
765
|
-
description: "Outpaint / reframe to a new aspect ratio while preserving subject.",
|
|
766
|
-
useCases: ["outpaint", "reframe"],
|
|
767
|
-
features: ["reference-image"],
|
|
768
|
-
aspectRatios: IDEOGRAM_RATIOS,
|
|
769
|
-
pricing: [
|
|
770
|
-
{ identifier: "ideogram-reframe", credits: 18, note: "BALANCED default" },
|
|
771
|
-
{ identifier: "ideogram-reframe:TURBO", credits: 18, note: "fastest" },
|
|
772
|
-
{ identifier: "ideogram-reframe:QUALITY", credits: 18, note: "best quality" },
|
|
773
|
-
],
|
|
774
|
-
},
|
|
757
|
+
// `ideogram-reframe` was retired 2026-09-15 — KIE's `ideogram/v3-reframe`
|
|
758
|
+
// fails every task upstream (#1331); see IDEOGRAM_PROVIDERS in model-constants.
|
|
775
759
|
|
|
776
760
|
// ── Google Imagen ──
|
|
777
761
|
"imagen4": {
|
|
@@ -1238,9 +1222,17 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
1238
1222
|
family: "Google",
|
|
1239
1223
|
label: "VEO 3.1 Quality",
|
|
1240
1224
|
series: "VEO",
|
|
1241
|
-
description: "Google VEO 3.1 Quality — premium cinematic video. 4/6/8s clips, optional end frame, native audio. Flat per-generation pricing across durations.",
|
|
1225
|
+
description: "Google VEO 3.1 Quality — premium cinematic video. 4/6/8s clips, optional end frame, native audio. No reference-to-video mode (Fast/Lite only). Flat per-generation pricing across durations.",
|
|
1242
1226
|
useCases: ["cinematic", "premium", "narrative"],
|
|
1243
|
-
|
|
1227
|
+
// NO "reference-image": KIE serves REFERENCE_2_VIDEO on the Fast and Lite
|
|
1228
|
+
// SKUs only. Its own words, on a production job (2026-09-04, app-reports
|
|
1229
|
+
// lane G): "Reference to video only supports the Veo Fast model and Veo
|
|
1230
|
+
// Lite model." Until 2026-09-15 this entry claimed the feature, so the
|
|
1231
|
+
// editor offered the reference handles, the adapter sent
|
|
1232
|
+
// generationType: "REFERENCE_2_VIDEO", and the call came back 422 every
|
|
1233
|
+
// time — after credits were reserved. `veo3.1` (KIE `veo3_fast`) and
|
|
1234
|
+
// `veo3_lite` DO serve it and keep the flag.
|
|
1235
|
+
features: ["end-frame", "audio"],
|
|
1244
1236
|
durations: [4, 6, 8],
|
|
1245
1237
|
aspectRatios: VIDEO_RATIOS_HV,
|
|
1246
1238
|
// 720p (default) + 1080p inline. 4K generates the base at 1080p then chains
|
|
@@ -2204,7 +2196,7 @@ const VIDEO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2204
2196
|
id: "omnihuman-1-5",
|
|
2205
2197
|
kind: "video",
|
|
2206
2198
|
modes: ["lip-sync"] as const,
|
|
2207
|
-
family: "
|
|
2199
|
+
family: "Bytedance",
|
|
2208
2200
|
label: "OmniHuman 1.5",
|
|
2209
2201
|
series: "OmniHuman",
|
|
2210
2202
|
description: "Premium prompt-directed talking avatar from a still image + audio. 720p / 1080p, up to 60s. People, pets, anime.",
|
|
@@ -2468,17 +2460,8 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2468
2460
|
},
|
|
2469
2461
|
|
|
2470
2462
|
// ── ElevenLabs voice utilities ──
|
|
2471
|
-
|
|
2472
|
-
|
|
2473
|
-
kind: "audio",
|
|
2474
|
-
modes: ["voice-clone"] as const,
|
|
2475
|
-
family: "ElevenLabs",
|
|
2476
|
-
label: "Voice Clone (Instant)",
|
|
2477
|
-
series: "ElevenLabs",
|
|
2478
|
-
description: "Clone a voice from a short reference clip. Instant clone via direct ElevenLabs API.",
|
|
2479
|
-
useCases: ["voice-clone", "personalization"],
|
|
2480
|
-
pricing: [{ identifier: "voice-clone", credits: 50 }],
|
|
2481
|
-
},
|
|
2463
|
+
// (voice cloning was retired platform-wide on 2026-09-15 — no catalog entry,
|
|
2464
|
+
// no price, no MCP tool; existing clones still resolve as TTS voice ids.)
|
|
2482
2465
|
"elevenlabs-voice-design": {
|
|
2483
2466
|
id: "elevenlabs-voice-design",
|
|
2484
2467
|
kind: "audio",
|
|
@@ -2534,6 +2517,17 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2534
2517
|
useCases: ["dubbing", "multilingual"],
|
|
2535
2518
|
pricing: [{ identifier: "elevenlabs-dubbing", credits: 40, note: "per minute of the dubbed span (min 1)" }],
|
|
2536
2519
|
},
|
|
2520
|
+
"elevenlabs-dubbing-v2": {
|
|
2521
|
+
id: "elevenlabs-dubbing-v2",
|
|
2522
|
+
kind: "audio",
|
|
2523
|
+
modes: ["dubbing"] as const,
|
|
2524
|
+
family: "ElevenLabs",
|
|
2525
|
+
label: "ElevenLabs Dubbing v2",
|
|
2526
|
+
series: "ElevenLabs",
|
|
2527
|
+
description: "Translate + dub audio or a whole video into a new language — video in, dubbed video out. Async.",
|
|
2528
|
+
useCases: ["dubbing", "multilingual"],
|
|
2529
|
+
pricing: [{ identifier: "elevenlabs-dubbing-v2", credits: 1100, note: "per minute of the dubbed span (min 1)" }],
|
|
2530
|
+
},
|
|
2537
2531
|
"elevenlabs-forced-alignment": {
|
|
2538
2532
|
id: "elevenlabs-forced-alignment",
|
|
2539
2533
|
kind: "audio",
|
|
@@ -2580,7 +2574,7 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2580
2574
|
label: "Suno v5",
|
|
2581
2575
|
series: "Suno",
|
|
2582
2576
|
dataValue: "V5",
|
|
2583
|
-
description: "
|
|
2577
|
+
description: "Suno v5 — better vocal quality than v4, more genres. Same price.",
|
|
2584
2578
|
useCases: ["music", "song", "vocals", "premium"],
|
|
2585
2579
|
pricing: [{ identifier: "suno-v5", credits: 30, note: "per generation" }],
|
|
2586
2580
|
},
|
|
@@ -2592,11 +2586,47 @@ const AUDIO_MODELS: Record<string, ModelCatalogEntry> = {
|
|
|
2592
2586
|
label: "Suno v5.5",
|
|
2593
2587
|
series: "Suno",
|
|
2594
2588
|
dataValue: "V5_5",
|
|
2595
|
-
description: "Suno v5.5 —
|
|
2589
|
+
description: "Suno v5.5 — improved audio quality and expressiveness over v5.",
|
|
2596
2590
|
useCases: ["music", "song", "vocals", "premium"],
|
|
2597
2591
|
pricing: [{ identifier: "suno-v5_5", credits: 30, note: "per generation" }],
|
|
2592
|
+
},
|
|
2593
|
+
"suno-v6": {
|
|
2594
|
+
id: "suno-v6",
|
|
2595
|
+
kind: "audio",
|
|
2596
|
+
modes: ["music"] as const,
|
|
2597
|
+
family: "Suno",
|
|
2598
|
+
label: "Suno V6",
|
|
2599
|
+
series: "Suno",
|
|
2600
|
+
dataValue: "V6",
|
|
2601
|
+
description: "Suno V6 — greater musical expression with more natural vocals and richer details. The flagship and the default.",
|
|
2602
|
+
useCases: ["music", "song", "vocals", "premium"],
|
|
2603
|
+
pricing: [{ identifier: "suno-v6", credits: 30, note: "per generation" }],
|
|
2598
2604
|
featured: true,
|
|
2599
2605
|
},
|
|
2606
|
+
"suno-v6_wild": {
|
|
2607
|
+
id: "suno-v6_wild",
|
|
2608
|
+
kind: "audio",
|
|
2609
|
+
modes: ["music"] as const,
|
|
2610
|
+
family: "Suno",
|
|
2611
|
+
label: "Suno V6 Wild",
|
|
2612
|
+
series: "Suno",
|
|
2613
|
+
dataValue: "V6_WILD",
|
|
2614
|
+
description: "Suno V6 Wild — pushes creative boundaries for bolder, more distinctive musical expression; more varied, less predictable results.",
|
|
2615
|
+
useCases: ["music", "song", "vocals", "experimental"],
|
|
2616
|
+
pricing: [{ identifier: "suno-v6_wild", credits: 30, note: "per generation" }],
|
|
2617
|
+
},
|
|
2618
|
+
"suno-v6_mini": {
|
|
2619
|
+
id: "suno-v6_mini",
|
|
2620
|
+
kind: "audio",
|
|
2621
|
+
modes: ["music"] as const,
|
|
2622
|
+
family: "Suno",
|
|
2623
|
+
label: "Suno V6 Mini",
|
|
2624
|
+
series: "Suno",
|
|
2625
|
+
dataValue: "V6_MINI",
|
|
2626
|
+
description: "Suno V6 Mini — lightweight and fast, balancing quality and speed for effortless creation.",
|
|
2627
|
+
useCases: ["music", "song", "vocals", "fast"],
|
|
2628
|
+
pricing: [{ identifier: "suno-v6_mini", credits: 30, note: "per generation" }],
|
|
2629
|
+
},
|
|
2600
2630
|
}
|
|
2601
2631
|
|
|
2602
2632
|
// =============================================================================
|
|
@@ -2642,6 +2672,29 @@ export function groupByFamily(
|
|
|
2642
2672
|
return Array.from(groups.entries()).map(([family, models]) => ({ family, models }))
|
|
2643
2673
|
}
|
|
2644
2674
|
|
|
2675
|
+
export const MODEL_KINDS = ["image", "video", "audio"] as const satisfies readonly ModelKind[]
|
|
2676
|
+
|
|
2677
|
+
/**
|
|
2678
|
+
* The Image / Video / Audio envelope every model-discovery surface renders
|
|
2679
|
+
* (`GET /v1/models`, MCP `list_models`): each model is filed under ITS OWN
|
|
2680
|
+
* kind, then by vendor family within that kind — so a vendor that ships more
|
|
2681
|
+
* than one kind (Google: Imagen + VEO, ByteDance: Seedream + Seedance, …)
|
|
2682
|
+
* appears once per kind it actually ships.
|
|
2683
|
+
*
|
|
2684
|
+
* This is the ONE grouping both surfaces call. Grouping by family first and
|
|
2685
|
+
* letting the family's first model pick the section filed every VEO, Seedance,
|
|
2686
|
+
* Wan and ByteDance video model under "image" whenever the call carried no
|
|
2687
|
+
* `kind` filter (#1332) — an explicit `kind` pre-filtered the list and hid it.
|
|
2688
|
+
* Empty sections are omitted; section order is fixed image → video → audio.
|
|
2689
|
+
*/
|
|
2690
|
+
export function groupByKindAndFamily(
|
|
2691
|
+
entries: ModelCatalogEntry[],
|
|
2692
|
+
): Array<{ kind: ModelKind; families: Array<{ family: string; models: ModelCatalogEntry[] }> }> {
|
|
2693
|
+
return MODEL_KINDS
|
|
2694
|
+
.map((kind) => ({ kind, families: groupByFamily(entries.filter((m) => m.kind === kind)) }))
|
|
2695
|
+
.filter((section) => section.families.length > 0)
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2645
2698
|
export function getModel(id: string): ModelCatalogEntry | undefined {
|
|
2646
2699
|
return MODEL_CATALOG[id]
|
|
2647
2700
|
}
|
package/src/model-constants.ts
CHANGED
|
@@ -91,14 +91,20 @@ export const MAX_IMAGE_PROMPT_CHARS_BY_PROVIDER: Record<string, number> = {
|
|
|
91
91
|
"seedream-5-lite-i2i": 3000, // docs.kie.ai/market/seedream-5-lite-image-to-image (NB: t2i sibling is 1000)
|
|
92
92
|
"qwen": 3000, // docs.kie.ai/market/qwen/text-to-image
|
|
93
93
|
"qwen-edit": 2000, // docs.kie.ai/market/qwen/image-edit
|
|
94
|
+
// Z-Image is the SHORTEST of the family — "maxLength: 1000" in its schema
|
|
95
|
+
// (docs.kie.ai/market/z-image/z-image, re-fetched 2026-09-15). It was listed
|
|
96
|
+
// below as "verified == 5000", which is how three production runs on
|
|
97
|
+
// 2026-09-07 sent a workflow-assembled prompt straight into KIE's
|
|
98
|
+
// `{"code":500,"msg":"The text length cannot exceed the maximum limit"}`.
|
|
99
|
+
"z-image": 1000, // docs.kie.ai/market/z-image/z-image
|
|
94
100
|
// verified == 5000 default (no entry needed): imagen4(-fast/-ultra), nano-banana,
|
|
95
101
|
// nano-banana-edit, flux, flux-flex, gpt-image-2, ideogram-v3/-edit/-remix,
|
|
96
|
-
//
|
|
102
|
+
// grok, qwen-i2i, seedream-5-pro, seedream-5-pro-i2i
|
|
97
103
|
// (docs.kie.ai/market/seedream/5-pro-text-to-image + 5-pro-image-to-image).
|
|
98
104
|
// grok-i2i: doc states 390000 (78× its t2i sibling) — treated as a KIE schema
|
|
99
105
|
// typo and left at the 5000 default per the sanity-cap decision.
|
|
100
106
|
// UNVERIFIED (no limit stated in schema) → 5000 default: flux-kontext(-max)
|
|
101
|
-
// gpt-image, gpt-image-i2i, flux-i2i, flux-pro-i2i
|
|
107
|
+
// gpt-image, gpt-image-i2i, flux-i2i, flux-pro-i2i.
|
|
102
108
|
}
|
|
103
109
|
|
|
104
110
|
/** Max assembled image-prompt length (chars) for a provider: its verified
|
|
@@ -119,10 +125,10 @@ export const VIDEO_PROMPT_MAX = 8000
|
|
|
119
125
|
|
|
120
126
|
/**
|
|
121
127
|
* Suno prompt / lyrics / content ceiling — the LARGEST any Suno version accepts
|
|
122
|
-
* in custom mode (
|
|
128
|
+
* in custom mode (V6 family and V4.5+ / V5 / V5.5 = 5000). NOT the route
|
|
123
129
|
* Zod bound — the routes bind at {@link SUNO_HARD_CEILING} and clamp to the
|
|
124
130
|
* per-version cap via {@link getMaxSunoPromptChars} (3000 non-custom for every
|
|
125
|
-
* version; in custom mode 3000 for V4/V3.5, 5000 for V4.5+/V5) before the job
|
|
131
|
+
* version; in custom mode 3000 for V4/V3.5, 5000 for V4.5+/V5/V6) before the job
|
|
126
132
|
* is built. This constant is shared with the editor `maxLength` / counter
|
|
127
133
|
* (warn-don't-block at the per-version cap). `style` and `title` have their
|
|
128
134
|
* own caps ({@link getMaxSunoStyleChars} / {@link SUNO_TITLE_MAX}).
|
|
@@ -310,9 +316,11 @@ export function getMaxTtsChars(provider: string | undefined): number {
|
|
|
310
316
|
* SUNO_TEXT_MAX} is 5000 today — the largest per-version prompt cap; the
|
|
311
317
|
* route Zod bound is {@link SUNO_HARD_CEILING}.)
|
|
312
318
|
* - prompt / lyrics: 3000 in non-custom mode (all versions); in custom mode
|
|
313
|
-
* 3000 for V4/V3.5 and 5000 for V4.5 / V4.5PLUS / V4.5ALL / V5 / V5.5
|
|
314
|
-
*
|
|
315
|
-
* -
|
|
319
|
+
* 3000 for V4/V3.5 and 5000 for V4.5 / V4.5PLUS / V4.5ALL / V5 / V5.5 and
|
|
320
|
+
* the whole V6 family (V6 / V6_WILD / V6_MINI).
|
|
321
|
+
* - style: 200 for V4/V3.5, 1000 for V4.5+ and V6.
|
|
322
|
+
* - title: 80 (all versions; the extend docs quote 100 for V6 — we keep the
|
|
323
|
+
* stricter generate cap so one value is right everywhere).
|
|
316
324
|
*/
|
|
317
325
|
export const SUNO_TITLE_MAX = 80
|
|
318
326
|
|
|
@@ -506,7 +514,6 @@ export const MODELS_WITH_REFERENCE_IMAGE_SUPPORT = new Set([
|
|
|
506
514
|
"flux-kontext-max",
|
|
507
515
|
"ideogram-edit",
|
|
508
516
|
"ideogram-remix",
|
|
509
|
-
"ideogram-reframe",
|
|
510
517
|
"qwen-i2i",
|
|
511
518
|
"qwen-edit",
|
|
512
519
|
"seedream-edit",
|
|
@@ -586,7 +593,6 @@ export const REF_IMAGE_MAX_LIMITS: Record<string, number> = {
|
|
|
586
593
|
"flux-kontext-max": 1,
|
|
587
594
|
"ideogram-edit": 1,
|
|
588
595
|
"ideogram-remix": 1,
|
|
589
|
-
"ideogram-reframe": 1,
|
|
590
596
|
"qwen-i2i": 1,
|
|
591
597
|
"qwen-edit": 1,
|
|
592
598
|
"grok-i2i": 1,
|
|
@@ -660,7 +666,6 @@ export const VARIABLE_PRICING_MODELS: Record<string, "quality" | "resolution" |
|
|
|
660
666
|
"topaz-image-upscale": "resolution",
|
|
661
667
|
"ideogram-edit": "rendering-speed",
|
|
662
668
|
"ideogram-remix": "rendering-speed",
|
|
663
|
-
"ideogram-reframe": "rendering-speed",
|
|
664
669
|
"ideogram-v3": "rendering-speed",
|
|
665
670
|
"wan-2.7": "resolution",
|
|
666
671
|
"wan-2.7-pro": "resolution",
|
|
@@ -687,7 +692,12 @@ export const RESOLUTION_2K_4K_TIERED_PROVIDERS = new Set([
|
|
|
687
692
|
])
|
|
688
693
|
|
|
689
694
|
// Ideogram family models with TURBO/QUALITY pricing variants
|
|
690
|
-
|
|
695
|
+
// `ideogram-reframe` (KIE `ideogram/v3-reframe`) was retired 2026-09-15: KIE no
|
|
696
|
+
// longer documents the model and every task — the minimal documented payload
|
|
697
|
+
// included — fails upstream with "[500] internal error" (#1331). Its price rows
|
|
698
|
+
// are removed by migration 424; re-add everywhere per the Provider Enum Sync
|
|
699
|
+
// table if KIE brings it back.
|
|
700
|
+
export const IDEOGRAM_PROVIDERS = new Set(["ideogram-edit", "ideogram-remix", "ideogram-v3"])
|
|
691
701
|
|
|
692
702
|
// =====================================================================
|
|
693
703
|
// Provider arrays (single source of truth for route Zod validation)
|
|
@@ -742,7 +752,6 @@ export const IMAGE_I2I_PROVIDERS = [
|
|
|
742
752
|
"grok-2-i2i",
|
|
743
753
|
"ideogram-edit",
|
|
744
754
|
"ideogram-remix",
|
|
745
|
-
"ideogram-reframe",
|
|
746
755
|
"qwen-i2i",
|
|
747
756
|
"qwen-edit",
|
|
748
757
|
"seedream-edit",
|
|
@@ -1229,19 +1238,72 @@ export const QA_CHECK_PROVIDERS = [
|
|
|
1229
1238
|
] as const
|
|
1230
1239
|
export type QaCheckProvider = typeof QA_CHECK_PROVIDERS[number]
|
|
1231
1240
|
|
|
1232
|
-
/**
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1241
|
+
/**
|
|
1242
|
+
* The current Suno generation (docs.kie.ai/suno-api/generate-music, 2026-09:
|
|
1243
|
+
* the V6 family), listed first in every picker; V6 is the default.
|
|
1244
|
+
*
|
|
1245
|
+
* - V6 — flagship: greater musical expression, more natural vocals, richer details.
|
|
1246
|
+
* - V6_WILD — bolder, more distinctive, less predictable output for exploration.
|
|
1247
|
+
* - V6_MINI — lightweight and fast; quality/speed balance.
|
|
1248
|
+
*
|
|
1249
|
+
* This is also the set that honours `duration` ({@link SUNO_DURATION_MODELS}).
|
|
1250
|
+
*/
|
|
1251
|
+
export const SUNO_ACTIVE_MODELS = ["V6", "V6_WILD", "V6_MINI"] as const
|
|
1252
|
+
export type SunoActiveModel = typeof SUNO_ACTIVE_MODELS[number]
|
|
1253
|
+
|
|
1254
|
+
/**
|
|
1255
|
+
* The earlier Suno generations. Still offered in every picker as ordinary
|
|
1256
|
+
* choices (users report each has its own character), still accepted by every
|
|
1257
|
+
* route, and confirmed generating on 2026-09-11. KIE's docs tag them
|
|
1258
|
+
* "Discontinued"; if KIE ever stops serving one, coerce it to
|
|
1259
|
+
* {@link DEFAULT_SUNO_MODEL} at the provider send seam — never remove it from
|
|
1260
|
+
* {@link SUNO_MODELS}, which would 400 every saved music workflow.
|
|
1261
|
+
*/
|
|
1262
|
+
export const SUNO_LEGACY_MODELS = [
|
|
1263
|
+
"V5_5",
|
|
1264
|
+
"V5",
|
|
1236
1265
|
"V4_5PLUS",
|
|
1237
1266
|
"V4_5ALL",
|
|
1238
|
-
"
|
|
1239
|
-
"
|
|
1267
|
+
"V4_5",
|
|
1268
|
+
"V4",
|
|
1240
1269
|
] as const
|
|
1270
|
+
export type SunoLegacyModel = typeof SUNO_LEGACY_MODELS[number]
|
|
1271
|
+
|
|
1272
|
+
/**
|
|
1273
|
+
* Every Suno model version — the picker order, the route / MCP Zod enum and
|
|
1274
|
+
* the `data.model` type on Suno nodes. Current generation first (V6 = default),
|
|
1275
|
+
* then the earlier generations newest-first.
|
|
1276
|
+
*/
|
|
1277
|
+
export const SUNO_MODELS = [...SUNO_ACTIVE_MODELS, ...SUNO_LEGACY_MODELS] as const
|
|
1241
1278
|
export type SunoModel = typeof SUNO_MODELS[number]
|
|
1242
1279
|
|
|
1243
|
-
/** Suno
|
|
1244
|
-
export const
|
|
1280
|
+
/** The Suno version used when a caller omits `model` — KIE's own default. */
|
|
1281
|
+
export const DEFAULT_SUNO_MODEL = "V6" satisfies SunoActiveModel
|
|
1282
|
+
|
|
1283
|
+
export function isLegacySunoModel(model: string | undefined): model is SunoLegacyModel {
|
|
1284
|
+
return (SUNO_LEGACY_MODELS as readonly string[]).includes(model ?? "")
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
/**
|
|
1288
|
+
* Suno versions that HONOUR `duration` (custom mode only). Per the generate /
|
|
1289
|
+
* extend docs the field "will only take effect when the model is V6, V6_MINI,
|
|
1290
|
+
* or V6_WILD" — V5_5 was struck from that sentence when V6 shipped. The
|
|
1291
|
+
* provider client's send-gate (`sunoGenerate` in suno-client.ts) is the single
|
|
1292
|
+
* chokepoint that consults this set; the editor uses it only to decide whether
|
|
1293
|
+
* to SHOW the duration field.
|
|
1294
|
+
*/
|
|
1295
|
+
export const SUNO_DURATION_MODELS: ReadonlySet<string> = new Set<SunoModel>(SUNO_ACTIVE_MODELS)
|
|
1296
|
+
|
|
1297
|
+
export function sunoModelHonoursDuration(model: string | undefined): boolean {
|
|
1298
|
+
return SUNO_DURATION_MODELS.has(model ?? "")
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
/**
|
|
1302
|
+
* Suno models accepted by add-instrumental / add-vocals (docs enum: the V6
|
|
1303
|
+
* family plus V4_5PLUS / V5 / V5_5). Same current-then-earlier order as
|
|
1304
|
+
* {@link SUNO_MODELS}.
|
|
1305
|
+
*/
|
|
1306
|
+
export const SUNO_ADD_TRACK_MODELS = [...SUNO_ACTIVE_MODELS, "V4_5PLUS", "V5", "V5_5"] as const
|
|
1245
1307
|
export type SunoAddTrackModel = typeof SUNO_ADD_TRACK_MODELS[number]
|
|
1246
1308
|
|
|
1247
1309
|
/** Voice design models */
|
|
@@ -1310,7 +1372,7 @@ export const I2I_STRENGTH_SUPPORT: Record<string, { min: number; max: number; st
|
|
|
1310
1372
|
|
|
1311
1373
|
/** Models that accept a seed parameter for reproducible generation */
|
|
1312
1374
|
export const SEED_SUPPORT = new Set([
|
|
1313
|
-
"ideogram-remix", "ideogram-
|
|
1375
|
+
"ideogram-remix", "ideogram-v3",
|
|
1314
1376
|
"qwen", "qwen-i2i", "qwen-edit",
|
|
1315
1377
|
"flux", "flux-flex", "flux-i2i", "flux-pro-i2i", "flux-kontext", "flux-kontext-max",
|
|
1316
1378
|
"flux-2-klein", "kontext-multi",
|
|
@@ -1318,7 +1380,7 @@ export const SEED_SUPPORT = new Set([
|
|
|
1318
1380
|
|
|
1319
1381
|
/** Ideogram models that support rendering_speed selection (TURBO/BALANCED/QUALITY) */
|
|
1320
1382
|
export const RENDERING_SPEED_SUPPORT = new Set([
|
|
1321
|
-
"ideogram-remix", "ideogram-
|
|
1383
|
+
"ideogram-remix", "ideogram-v3",
|
|
1322
1384
|
])
|
|
1323
1385
|
|
|
1324
1386
|
/** Models that accept guidance_scale for controlling prompt adherence */
|
|
@@ -1924,8 +1986,13 @@ export const VIDEO_REF_LIMITS_BY_PROVIDER: Record<
|
|
|
1924
1986
|
"kling-3-omni": { images: 7 }, // catalog/docs: "end frame + up to 7 reference images"
|
|
1925
1987
|
"grok-i2v": { images: 7 }, // backend kie/models.ts maxRefImages: 7
|
|
1926
1988
|
"happyhorse-ref2v": { images: 9 }, // backend kie/models.ts maxRefImages: 9
|
|
1927
|
-
// VEO 3.x — REFERENCE_2_VIDEO path caps refs at 3 (kie/video.ts
|
|
1928
|
-
|
|
1989
|
+
// VEO 3.x — REFERENCE_2_VIDEO path caps refs at 3 (kie/video.ts slices to
|
|
1990
|
+
// this number). `veo3` (VEO 3.1 QUALITY) is deliberately ABSENT: KIE serves
|
|
1991
|
+
// reference-to-video on the Fast and Lite SKUs only and rejects it on
|
|
1992
|
+
// Quality with "Reference to video only supports the Veo Fast model and Veo
|
|
1993
|
+
// Lite model." (production, 2026-09-04). Absent ⇒ 0 ⇒ the handle dims, the
|
|
1994
|
+
// `connectedReferences` assembly strips image tokens, and kie/video.ts never
|
|
1995
|
+
// flips a Quality call to REFERENCE_2_VIDEO.
|
|
1929
1996
|
"veo3.1": { images: 3 },
|
|
1930
1997
|
"veo3_lite": { images: 3 },
|
|
1931
1998
|
// NOTE: wan-i2v / hailuo-2.3[-pro] / bytedance-pro[-fast] / grok-imagine-video-1.5
|
|
@@ -2458,6 +2525,33 @@ export const VIDEO_VARIABLE_PRICING: Record<string, "duration" | "duration+audio
|
|
|
2458
2525
|
*/
|
|
2459
2526
|
export const PRICING_DEFAULT_DURATION_SEC: Record<string, number> = {
|
|
2460
2527
|
"minimax-h3": 6,
|
|
2528
|
+
// KIE renders 8s when `duration` is omitted (kie/models.ts extraParams), and
|
|
2529
|
+
// Seedance 2.5 prices one tier per second across 4–30s, so the 5s fallback
|
|
2530
|
+
// billed a 5s tier against an 8s render — and under-reserved every
|
|
2531
|
+
// reference-video run's output seconds by three (#1397).
|
|
2532
|
+
"seedance-2-5": 8,
|
|
2533
|
+
// Same shape: KIE renders 8s by default and the ladder is priced per second,
|
|
2534
|
+
// so the 5s fallback billed a 5s tier against an 8s render (caught by the
|
|
2535
|
+
// render-default ↔ priced-tier invariant in
|
|
2536
|
+
// backend/src/providers/__tests__/pricing-default-duration-sync.test.ts).
|
|
2537
|
+
"grok-imagine-video-1.5": 8,
|
|
2538
|
+
}
|
|
2539
|
+
|
|
2540
|
+
/**
|
|
2541
|
+
* The output seconds a request is PRICED at: the requested duration when the
|
|
2542
|
+
* caller gave one, else the provider's own default render length
|
|
2543
|
+
* ({@link PRICING_DEFAULT_DURATION_SEC}), else the historical 5s fallback.
|
|
2544
|
+
*
|
|
2545
|
+
* The ONE source for `buildVideoCreditModelIdentifier`'s tier AND for every
|
|
2546
|
+
* dynamic reservation that scales by output seconds (the Seedance 2 and
|
|
2547
|
+
* MiniMax Hailuo 3 reference-video overrides on both the route and the DAG
|
|
2548
|
+
* lane) — a literal `?? 5` in any of those places re-opens the gap this map
|
|
2549
|
+
* closes.
|
|
2550
|
+
*/
|
|
2551
|
+
export function pricedOutputDurationSec(provider: string, requested: number | string | undefined): number {
|
|
2552
|
+
const fallback = PRICING_DEFAULT_DURATION_SEC[provider] ?? 5
|
|
2553
|
+
const parsed = typeof requested === "string" ? parseInt(requested, 10) : requested
|
|
2554
|
+
return parsed === undefined || Number.isNaN(parsed) ? fallback : parsed
|
|
2461
2555
|
}
|
|
2462
2556
|
|
|
2463
2557
|
/**
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The wire contract for one node's entry in an execution's `nodeStates` map —
|
|
3
|
+
* the shape the orchestrator persists on `workflow_executions.node_states`,
|
|
4
|
+
* emits on the SSE execution stream, and every client reads back.
|
|
5
|
+
*
|
|
6
|
+
* Why this lives here rather than in the backend
|
|
7
|
+
* ----------------------------------------------
|
|
8
|
+
* The shape had THREE independent declarations — the orchestrator's rich
|
|
9
|
+
* `NodeExecutionState` (workflow-engine/types.ts), the SDK's loose one
|
|
10
|
+
* (`packages/client/src/resources/executions.ts`) and the editor's local copy
|
|
11
|
+
* (`workflow-editor/run-handlers.ts`) — and nothing tied them together. The
|
|
12
|
+
* field that made that expensive is `output`: it used to be an unstated
|
|
13
|
+
* convention that only a COMPLETED node carries one, so every consumer read it
|
|
14
|
+
* exclusively under `status === "completed"` and a failed node's retained
|
|
15
|
+
* result had nowhere to travel.
|
|
16
|
+
*
|
|
17
|
+
* This module states the rule once. The backend keeps its richer `NodeOutput`
|
|
18
|
+
* typing (its `NodeExecutionState` must stay ASSIGNABLE to the wire shape — a
|
|
19
|
+
* type-level test pins that); the SDK and the editor extend/import it.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* The status a node reports inside an execution.
|
|
24
|
+
*
|
|
25
|
+
* `cancelled` is deliberately absent: a cancelled child job is mapped onto
|
|
26
|
+
* `skipped` by the reconcile lane (see `lib/reconcile/node-states.ts`), and a
|
|
27
|
+
* HELD job keeps `status: "running"` with the `awaitingReview` sidecar rather
|
|
28
|
+
* than adding a member here.
|
|
29
|
+
*/
|
|
30
|
+
export type NodeExecutionStatus =
|
|
31
|
+
| "pending"
|
|
32
|
+
| "running"
|
|
33
|
+
| "completed"
|
|
34
|
+
| "failed"
|
|
35
|
+
| "skipped"
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* The statuses whose node state MAY carry `output`.
|
|
39
|
+
*
|
|
40
|
+
* `completed` is the obvious one. `failed` is here because a run can refuse
|
|
41
|
+
* its result and still RETAIN what it produced — the 3D-scene authoring lanes
|
|
42
|
+
* publish a real, renderable revision and then fail the job on the visual
|
|
43
|
+
* reviewer's verdict (`SCENE_QUALITY_FAILED`), so the scene and the refusal are
|
|
44
|
+
* both true at once. That output was billed; dropping it because the status is
|
|
45
|
+
* not `"completed"` is what this set exists to stop.
|
|
46
|
+
*
|
|
47
|
+
* `pending` / `running` / `skipped` never carry one: nothing has settled, or
|
|
48
|
+
* the node was gated out.
|
|
49
|
+
*/
|
|
50
|
+
export const OUTPUT_BEARING_NODE_STATUSES: ReadonlySet<NodeExecutionStatus> =
|
|
51
|
+
new Set<NodeExecutionStatus>(["completed", "failed"])
|
|
52
|
+
|
|
53
|
+
/** Whether a node in this status may carry `output`. */
|
|
54
|
+
export function nodeStateMayCarryOutput(status: string | undefined): boolean {
|
|
55
|
+
return (
|
|
56
|
+
status !== undefined &&
|
|
57
|
+
OUTPUT_BEARING_NODE_STATUSES.has(status as NodeExecutionStatus)
|
|
58
|
+
)
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* One node's execution state, as it travels on the wire.
|
|
63
|
+
*
|
|
64
|
+
* Additive by construction — an older client ignores fields it does not know,
|
|
65
|
+
* which is why `output` on a failed node is safe to start sending.
|
|
66
|
+
*
|
|
67
|
+
* `TOutput` lets a declaration that knows its own richer output shape (the
|
|
68
|
+
* orchestrator's `NodeOutput`, the editor's) stay ASSIGNABLE to this contract
|
|
69
|
+
* instead of restating it; the default is what an external client sees.
|
|
70
|
+
*/
|
|
71
|
+
export interface NodeExecutionStateWire<TOutput = Record<string, unknown>> {
|
|
72
|
+
status: NodeExecutionStatus | (string & {})
|
|
73
|
+
nodeType?: string
|
|
74
|
+
jobId?: string | null
|
|
75
|
+
/** Every job id of a fan-out node (one per list / loop iteration). */
|
|
76
|
+
jobIds?: string[]
|
|
77
|
+
creditsUsed?: number
|
|
78
|
+
error?: string | null
|
|
79
|
+
/** Stable code for a refusal a client may branch on — never on the text. */
|
|
80
|
+
errorCode?: string
|
|
81
|
+
/**
|
|
82
|
+
* What the node produced.
|
|
83
|
+
*
|
|
84
|
+
* Present for a `completed` node, and for a `failed` node whose run RETAINED
|
|
85
|
+
* a structured result (see {@link OUTPUT_BEARING_NODE_STATUSES}). A consumer
|
|
86
|
+
* that reads it must therefore gate on the FIELD, not on the status, and
|
|
87
|
+
* must not treat its presence as success.
|
|
88
|
+
*/
|
|
89
|
+
output?: TOutput
|
|
90
|
+
startedAt?: string | null
|
|
91
|
+
completedAt?: string | null
|
|
92
|
+
/** The node's job is parked in `pending_review`; `status` stays "running". */
|
|
93
|
+
awaitingReview?: boolean
|
|
94
|
+
progress?: number
|
|
95
|
+
}
|