@nodaro/shared 2.18.0 → 2.19.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 (74) hide show
  1. package/dist/index.cjs +251 -12
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +100 -6
  4. package/dist/index.d.ts +100 -6
  5. package/dist/index.js +243 -13
  6. package/dist/index.js.map +1 -1
  7. package/package.json +1 -1
  8. package/src/__tests__/credit-identifiers.test.ts +47 -0
  9. package/src/__tests__/gvp-supported-providers.test.ts +22 -1
  10. package/src/__tests__/prompt-length-limits.test.ts +4 -0
  11. package/src/__tests__/video-audio-capability.test.ts +43 -0
  12. package/src/__tests__/video-mode-for-inputs.test.ts +1 -1
  13. package/src/__tests__/wan-3-catalog.test.ts +243 -0
  14. package/src/credit-identifiers.ts +42 -9
  15. package/src/i18n/held-prop.ar.ts +2 -0
  16. package/src/i18n/held-prop.de.ts +3 -0
  17. package/src/i18n/held-prop.es.ts +3 -0
  18. package/src/i18n/held-prop.fr.ts +2 -0
  19. package/src/i18n/held-prop.he.ts +3 -0
  20. package/src/i18n/held-prop.hi.ts +2 -0
  21. package/src/i18n/held-prop.ja.ts +3 -0
  22. package/src/i18n/held-prop.ko.ts +3 -0
  23. package/src/i18n/held-prop.pt-BR.ts +3 -0
  24. package/src/i18n/held-prop.ru.ts +2 -0
  25. package/src/i18n/held-prop.zh-CN.ts +3 -0
  26. package/src/i18n/person.ar.ts +3 -0
  27. package/src/i18n/person.de.ts +4 -0
  28. package/src/i18n/person.es.ts +4 -0
  29. package/src/i18n/person.fr.ts +3 -0
  30. package/src/i18n/person.he.ts +4 -0
  31. package/src/i18n/person.hi.ts +3 -0
  32. package/src/i18n/person.ja.ts +4 -0
  33. package/src/i18n/person.ko.ts +4 -0
  34. package/src/i18n/person.pt-BR.ts +4 -0
  35. package/src/i18n/person.ru.ts +3 -0
  36. package/src/i18n/person.zh-CN.ts +4 -0
  37. package/src/i18n/setting.ar.ts +2 -0
  38. package/src/i18n/setting.de.ts +3 -0
  39. package/src/i18n/setting.es.ts +3 -0
  40. package/src/i18n/setting.fr.ts +2 -0
  41. package/src/i18n/setting.he.ts +3 -0
  42. package/src/i18n/setting.hi.ts +2 -0
  43. package/src/i18n/setting.ja.ts +3 -0
  44. package/src/i18n/setting.ko.ts +3 -0
  45. package/src/i18n/setting.pt-BR.ts +3 -0
  46. package/src/i18n/setting.ru.ts +2 -0
  47. package/src/i18n/setting.zh-CN.ts +3 -0
  48. package/src/i18n/style.ar.ts +2 -0
  49. package/src/i18n/style.de.ts +3 -0
  50. package/src/i18n/style.es.ts +3 -0
  51. package/src/i18n/style.fr.ts +2 -0
  52. package/src/i18n/style.he.ts +3 -0
  53. package/src/i18n/style.hi.ts +2 -0
  54. package/src/i18n/style.ja.ts +3 -0
  55. package/src/i18n/style.ko.ts +3 -0
  56. package/src/i18n/style.pt-BR.ts +3 -0
  57. package/src/i18n/style.ru.ts +2 -0
  58. package/src/i18n/style.zh-CN.ts +3 -0
  59. package/src/i18n/styling.ar.ts +4 -0
  60. package/src/i18n/styling.de.ts +5 -0
  61. package/src/i18n/styling.es.ts +5 -0
  62. package/src/i18n/styling.fr.ts +4 -0
  63. package/src/i18n/styling.he.ts +5 -0
  64. package/src/i18n/styling.hi.ts +4 -0
  65. package/src/i18n/styling.ja.ts +5 -0
  66. package/src/i18n/styling.ko.ts +5 -0
  67. package/src/i18n/styling.pt-BR.ts +5 -0
  68. package/src/i18n/styling.ru.ts +4 -0
  69. package/src/i18n/styling.zh-CN.ts +5 -0
  70. package/src/index.ts +9 -0
  71. package/src/model-catalog.ts +101 -0
  72. package/src/model-constants.ts +182 -7
  73. package/src/node-default-mappings.ts +5 -0
  74. package/src/video-ui-defaults.ts +66 -0
package/dist/index.cjs CHANGED
@@ -84,6 +84,7 @@ var WAN_27_IMAGE_RATIOS = ["1:1", "16:9", "9:16", "4:3", "3:4", "21:9", "8:1", "
84
84
  var VIDEO_RATIOS_HVS345 = ["16:9", "9:16", "1:1", "4:3", "3:4"];
85
85
  var VIDEO_RATIOS_SEEDANCE_2 = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9", "adaptive"];
86
86
  var VIDEO_RATIOS_HAPPYHORSE_11 = ["16:9", "9:16", "1:1", "4:3", "3:4", "4:5", "5:4", "21:9", "9:21"];
87
+ var VIDEO_RATIOS_WAN_3 = ["adaptive", "16:9", "4:3", "1:1", "3:4", "9:16"];
87
88
  var IMAGE_MODELS = {
88
89
  // ── Google Nano Banana ──
89
90
  "nano-banana": {
@@ -1023,6 +1024,42 @@ var VIDEO_MODELS = {
1023
1024
  { identifier: "gemini-omni-video:4k:vref", credits: 900, note: "video-edit 4K" }
1024
1025
  ]
1025
1026
  },
1027
+ // Gemini Omni Flash 1.1 — the faster/cheaper Omni SKU (KIE
1028
+ // `google/gemini-omni-flash-1-1`). Identical request surface to
1029
+ // gemini-omni-video, so every capability below is deliberate PARITY with the
1030
+ // sibling: same 4/6/8/10s ladder, same 720p/1080p + 4K bands, same
1031
+ // features (the KIE schema also exposes first/last frame, but the pro
1032
+ // sibling's frame path is unwired here too — no "end-frame" until it is).
1033
+ // 360p is on the KIE enum but NOT exposed: it sits in the same credit band as
1034
+ // 720p/1080p, so it could only hand the user a worse render at the same price.
1035
+ "gemini-omni-flash": {
1036
+ id: "gemini-omni-flash",
1037
+ kind: "video",
1038
+ modes: ["i2v", "t2v"],
1039
+ // V2V is served via the i2v handle, not a catalog mode
1040
+ family: "Google",
1041
+ label: "Gemini Omni Flash",
1042
+ series: "Gemini",
1043
+ description: "Google Gemini Omni Flash \u2014 faster/cheaper Omni tier: multimodal video with native audio, text/image-to-video + video-edit.",
1044
+ useCases: ["cinematic", "fast"],
1045
+ features: ["audio", "reference-image"],
1046
+ aspectRatios: VIDEO_RATIOS_HV,
1047
+ resolutions: ["720p", "1080p", "4k"],
1048
+ durations: [4, 6, 8, 10],
1049
+ pricing: [
1050
+ { identifier: "gemini-omni-flash", credits: 270, note: "default \u2014 8s 720p/1080p (the credit builder's duration fallback)" },
1051
+ { identifier: "gemini-omni-flash:4", credits: 160, note: "720p/1080p 4s" },
1052
+ { identifier: "gemini-omni-flash:6", credits: 210, note: "720p/1080p 6s" },
1053
+ { identifier: "gemini-omni-flash:8", credits: 270, note: "720p/1080p 8s" },
1054
+ { identifier: "gemini-omni-flash:10", credits: 320, note: "720p/1080p 10s" },
1055
+ { identifier: "gemini-omni-flash:4k:4", credits: 370, note: "4K 4s" },
1056
+ { identifier: "gemini-omni-flash:4k:6", credits: 420, note: "4K 6s" },
1057
+ { identifier: "gemini-omni-flash:4k:8", credits: 480, note: "4K 8s" },
1058
+ { identifier: "gemini-omni-flash:4k:10", credits: 530, note: "4K 10s" },
1059
+ { identifier: "gemini-omni-flash:vref", credits: 420, note: "video-edit 720p/1080p" },
1060
+ { identifier: "gemini-omni-flash:4k:vref", credits: 630, note: "video-edit 4K" }
1061
+ ]
1062
+ },
1026
1063
  // ── Kling ──
1027
1064
  "kling": {
1028
1065
  id: "kling",
@@ -1290,6 +1327,66 @@ var VIDEO_MODELS = {
1290
1327
  ]
1291
1328
  },
1292
1329
  // ── Wan ──
1330
+ // Wan 3.0 (standard + Prime) — a NEW generation, not a tier of the 2.x ladder.
1331
+ // One id per SKU serves BOTH modes (no t2v twin, no alias): first/last frame
1332
+ // OR an all-purpose reference mode (images/videos/audio, bound in the prompt
1333
+ // as Image1/Video1/Audio1 — no space, unlike Wan 2.x), native audio behind a
1334
+ // boolean `audio` lever, 2-30s at 480p/720p/1080p.
1335
+ // `video-reference` is deliberately NOT declared: KIE accepts reference videos,
1336
+ // but the extend chain is unwired and KIE caps input-video + output at 30s,
1337
+ // which the segment bounds cannot express. Precedent: gemini-omni-video carries
1338
+ // ref limits without the feature. The ref CAPS still live in
1339
+ // VIDEO_REF_LIMITS_BY_PROVIDER (model-constants).
1340
+ // `resolutions` is ascending (repo convention); the DEFAULT tier (720p) is
1341
+ // declared explicitly in PRICING_DEFAULT_RESOLUTION, never by array position.
1342
+ "wan-3": {
1343
+ id: "wan-3",
1344
+ kind: "video",
1345
+ modes: ["i2v", "t2v"],
1346
+ family: "Alibaba",
1347
+ label: "Wan 3.0",
1348
+ series: "Wan",
1349
+ description: "Wan 3.0 \u2014 multimodal: first/last frame or image/video/audio references, native audio, 2-30s at 480p/720p/1080p.",
1350
+ useCases: ["motion", "narrative", "long-form"],
1351
+ features: ["end-frame", "audio", "reference-image"],
1352
+ aspectRatios: VIDEO_RATIOS_WAN_3,
1353
+ durations: [2, 3, 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],
1354
+ resolutions: ["480p", "720p", "1080p"],
1355
+ pricing: [
1356
+ { identifier: "wan-3", credits: 200, note: "default 5s 720p \u2014 see :Ns:res variants for exact" },
1357
+ { identifier: "wan-3:5s:720p", credits: 200, note: "5s 720p (the default tier)" },
1358
+ { identifier: "wan-3:8s:480p", credits: 160, note: "8s 480p" },
1359
+ { identifier: "wan-3:8s:720p", credits: 320, note: "8s 720p" },
1360
+ { identifier: "wan-3:8s:1080p", credits: 640, note: "8s 1080p" },
1361
+ { identifier: "wan-3:30s:480p", credits: 600, note: "30s 480p (max)" },
1362
+ { identifier: "wan-3:30s:720p", credits: 1200, note: "30s 720p (max)" },
1363
+ { identifier: "wan-3:30s:1080p", credits: 2400, note: "30s 1080p (max)" }
1364
+ ]
1365
+ },
1366
+ "wan-3-prime": {
1367
+ id: "wan-3-prime",
1368
+ kind: "video",
1369
+ modes: ["i2v", "t2v"],
1370
+ family: "Alibaba",
1371
+ label: "Wan 3.0 Prime",
1372
+ series: "Wan",
1373
+ description: "Wan 3.0 Prime \u2014 Alibaba's high-speed Wan 3.0 tier: same multimodal surface and 2-30s range, faster turnaround at a higher per-second rate.",
1374
+ useCases: ["fast", "motion", "narrative"],
1375
+ features: ["end-frame", "audio", "reference-image"],
1376
+ aspectRatios: VIDEO_RATIOS_WAN_3,
1377
+ durations: [2, 3, 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],
1378
+ resolutions: ["480p", "720p", "1080p"],
1379
+ pricing: [
1380
+ { identifier: "wan-3-prime", credits: 320, note: "default 5s 720p \u2014 see :Ns:res variants for exact" },
1381
+ { identifier: "wan-3-prime:5s:720p", credits: 320, note: "5s 720p (the default tier)" },
1382
+ { identifier: "wan-3-prime:8s:480p", credits: 250, note: "8s 480p" },
1383
+ { identifier: "wan-3-prime:8s:720p", credits: 510, note: "8s 720p" },
1384
+ { identifier: "wan-3-prime:8s:1080p", credits: 1010, note: "8s 1080p" },
1385
+ { identifier: "wan-3-prime:30s:480p", credits: 920, note: "30s 480p (max)" },
1386
+ { identifier: "wan-3-prime:30s:720p", credits: 1890, note: "30s 720p (max)" },
1387
+ { identifier: "wan-3-prime:30s:1080p", credits: 3780, note: "30s 1080p (max)" }
1388
+ ]
1389
+ },
1293
1390
  "wan-i2v": {
1294
1391
  id: "wan-i2v",
1295
1392
  kind: "video",
@@ -2481,6 +2578,13 @@ var MAX_VIDEO_PROMPT_CHARS_BY_PROVIDER = {
2481
2578
  // (docs.kie.ai/market/bytedance/seedance-2-5).
2482
2579
  "seedance-2-5": 3e4,
2483
2580
  "gemini-omni-video": 2e4,
2581
+ // Gemini Omni Flash 1.1 — same 20000-char prompt surface as the pro sibling
2582
+ // (docs.kie.ai/market/google/gemini-omni-flash-1-1).
2583
+ "gemini-omni-flash": 2e4,
2584
+ // Wan 3.0 / 3.0 Prime — 20000 chars, excess truncated by the provider
2585
+ // (docs.kie.ai/market/wan/3-0-video and /3-0-video-prime).
2586
+ "wan-3": 2e4,
2587
+ "wan-3-prime": 2e4,
2484
2588
  "bytedance-lite": 1e4,
2485
2589
  "bytedance-pro": 1e4,
2486
2590
  "bytedance-pro-fast": 1e4,
@@ -2873,6 +2977,11 @@ var IMAGE_TO_VIDEO_PROVIDERS = [
2873
2977
  "runway-kie",
2874
2978
  "kling-3-omni",
2875
2979
  "gemini-omni-video",
2980
+ "gemini-omni-flash",
2981
+ // Wan 3.0 family — one id per SKU serves BOTH modes (no t2v twin, no alias),
2982
+ // so each id is listed in this array AND in TEXT_TO_VIDEO_PROVIDERS.
2983
+ "wan-3",
2984
+ "wan-3-prime",
2876
2985
  "ltx-2.3-pro",
2877
2986
  "ltx-2.3-fast",
2878
2987
  // xAI Grok Imagine Video 1.5 — KIE i2v (image_urls required). Also listed in
@@ -2908,6 +3017,12 @@ var TEXT_TO_VIDEO_PROVIDERS = [
2908
3017
  "happyhorse",
2909
3018
  "runway-kie",
2910
3019
  "gemini-omni-video",
3020
+ "gemini-omni-flash",
3021
+ // Wan 3.0 family — REAL t2v (prompt-only runs are the documented default
3022
+ // mode), so they belong in this main section and must NOT be gated by
3023
+ // VIDEO_PROVIDERS_REQUIRING_IMAGE.
3024
+ "wan-3",
3025
+ "wan-3-prime",
2911
3026
  "ltx-2.3-pro",
2912
3027
  "ltx-2.3-fast",
2913
3028
  // ── i2v-only providers (image required) ──────────────────────────────────
@@ -3204,7 +3319,13 @@ var DURATION_PRICED_PROVIDERS = /* @__PURE__ */ new Set([
3204
3319
  "grok-imagine-video-1.5",
3205
3320
  "happyhorse",
3206
3321
  "happyhorse-i2v",
3207
- "happyhorse-ref2v"
3322
+ "happyhorse-ref2v",
3323
+ // Wan 3.0 family — per-second billing at three resolution rates. NOTE:
3324
+ // gemini-omni-flash is deliberately ABSENT (like gemini-omni-video): the
3325
+ // Gemini Omni branch in buildVideoCreditModelIdentifier early-returns before
3326
+ // this gate is consulted.
3327
+ "wan-3",
3328
+ "wan-3-prime"
3208
3329
  ]);
3209
3330
  var SEEDANCE_2_PROVIDERS = /* @__PURE__ */ new Set([
3210
3331
  "seedance-2",
@@ -3230,6 +3351,33 @@ var MINIMAX_H3_DEFAULT_RESOLUTION = "2K";
3230
3351
  function normalizeMinimaxH3Resolution(resolution) {
3231
3352
  return resolution?.trim().toLowerCase() === "768p" ? "768P" : MINIMAX_H3_DEFAULT_RESOLUTION;
3232
3353
  }
3354
+ var WAN_3_PROVIDERS = /* @__PURE__ */ new Set([
3355
+ "wan-3",
3356
+ "wan-3-prime"
3357
+ ]);
3358
+ function isWan3Provider(provider) {
3359
+ return !!provider && WAN_3_PROVIDERS.has(provider);
3360
+ }
3361
+ var WAN_3_DEFAULT_RESOLUTION = "720P";
3362
+ function normalizeWan3Resolution(resolution) {
3363
+ switch (resolution?.trim().toLowerCase()) {
3364
+ case "480p":
3365
+ return "480P";
3366
+ case "1080p":
3367
+ return "1080P";
3368
+ case "720p":
3369
+ return "720P";
3370
+ default:
3371
+ return WAN_3_DEFAULT_RESOLUTION;
3372
+ }
3373
+ }
3374
+ var GEMINI_OMNI_PROVIDERS = /* @__PURE__ */ new Set([
3375
+ "gemini-omni-video",
3376
+ "gemini-omni-flash"
3377
+ ]);
3378
+ function isGeminiOmniProvider(provider) {
3379
+ return !!provider && GEMINI_OMNI_PROVIDERS.has(provider);
3380
+ }
3233
3381
  var VIDEO_PROVIDERS_WITHOUT_DISPATCH = /* @__PURE__ */ new Set([
3234
3382
  "kling-3-omni"
3235
3383
  ]);
@@ -3313,7 +3461,7 @@ function maxSegmentsFor(provider, capSec) {
3313
3461
  return max > 0 ? Math.ceil(capSec / max) : 0;
3314
3462
  }
3315
3463
  function defaultVideoAspectRatio(provider) {
3316
- return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) ? "adaptive" : "16:9";
3464
+ return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider) ? "adaptive" : "16:9";
3317
3465
  }
3318
3466
  var VEO_PROVIDERS = /* @__PURE__ */ new Set([
3319
3467
  "veo3",
@@ -3357,7 +3505,11 @@ var SEEDANCE_2_R2V_MAX_AUDIO_SEC_BY_PROVIDER = {
3357
3505
  "seedance-2-5": 30,
3358
3506
  // MiniMax Hailuo 3 — documented hard limit: each reference audio segment
3359
3507
  // 2-15s, ≤15s total (docs.kie.ai/market/minimax-h3/reference-to-video).
3360
- "minimax-h3": 15
3508
+ "minimax-h3": 15,
3509
+ // Wan 3.0 family — documented hard limit: each reference audio clip 1-15s,
3510
+ // ≤15s combined (docs.kie.ai/market/wan/3-0-video).
3511
+ "wan-3": 15,
3512
+ "wan-3-prime": 15
3361
3513
  };
3362
3514
  function seedance2AudioLimitSec(provider) {
3363
3515
  if (!provider) return null;
@@ -3383,8 +3535,17 @@ var VIDEO_REF_LIMITS_BY_PROVIDER = {
3383
3535
  // bills input images beyond the first 5 (11 KIE cr each) — see the
3384
3536
  // minimax-h3 credit helper in backend ee/billing.
3385
3537
  "minimax-h3": { ...SEEDANCE_2_REF_LIMITS },
3538
+ // Wan 3.0 family — all-purpose reference mode: up to 10 images / 5 videos
3539
+ // (each 1-15s, ≤15s combined) / 5 audio clips (each 1-15s, ≤15s combined).
3540
+ // The reference arrays are mutually EXCLUSIVE with first/last frame at the
3541
+ // provider (docs.kie.ai/market/wan/3-0-video).
3542
+ "wan-3": { images: 10, videos: 5, audio: 5 },
3543
+ "wan-3-prime": { images: 10, videos: 5, audio: 5 },
3386
3544
  // Multi-image reference providers.
3387
3545
  "gemini-omni-video": { images: 7, videos: 1 },
3546
+ // Gemini Omni Flash 1.1 — identical quota to the pro sibling
3547
+ // (images + 2×videos + character_ids ≤ 7).
3548
+ "gemini-omni-flash": { images: 7, videos: 1 },
3388
3549
  "kling-3-omni": { images: 7 },
3389
3550
  // catalog/docs: "end frame + up to 7 reference images"
3390
3551
  "grok-i2v": { images: 7 },
@@ -3415,13 +3576,26 @@ var RESOLUTION_DURATION_PRICING = {
3415
3576
  // pinned to 720p via extraParams in backend kie/models.ts so render matches.
3416
3577
  "happyhorse": ["720p", "1080p"],
3417
3578
  "happyhorse-i2v": ["720p", "1080p"],
3418
- "happyhorse-ref2v": ["720p", "1080p"]
3579
+ "happyhorse-ref2v": ["720p", "1080p"],
3580
+ // Wan 3.0 / Prime — per-second billing at three published resolution rates.
3581
+ // Ascending, matching the catalog; the BILLED default is declared explicitly
3582
+ // in PRICING_DEFAULT_RESOLUTION ("720p") rather than carried by index 0, and
3583
+ // the provider layer pins the same 720P so render == billed.
3584
+ "wan-3": ["480p", "720p", "1080p"],
3585
+ "wan-3-prime": ["480p", "720p", "1080p"]
3419
3586
  };
3420
3587
  var NATIVE_ADAPTIVE_ASPECT = {
3421
3588
  "seedance-2": "adaptive",
3422
3589
  "seedance-2-fast": "adaptive",
3423
3590
  "seedance-2-mini": "adaptive",
3424
- "seedance-2-5": "adaptive"
3591
+ "seedance-2-5": "adaptive",
3592
+ // Wan 3.0 family: `adaptive` is the enum DEFAULT and KIE documents it as
3593
+ // "automatically selects the ratio based on the input media and intent"
3594
+ // (docs.kie.ai/market/wan/3-0-video) — i.e. match-the-input, not merely
3595
+ // "provider default" (the grok `auto` trap). DOC-verified only; re-confirm
3596
+ // with a live job before relying on it for off-catalog ratios.
3597
+ "wan-3": "adaptive",
3598
+ "wan-3-prime": "adaptive"
3425
3599
  };
3426
3600
  var FRAME_MODE_ADAPTIVE_ONLY_ASPECT = /* @__PURE__ */ new Set([
3427
3601
  "seedance-2-5"
@@ -3472,7 +3646,20 @@ var VIDEO_AUDIO_CAPABILITY = {
3472
3646
  // MiniMax Hailuo 3 — multimodal; lip-syncs to reference audio (r2v). The
3473
3647
  // KIE API exposes NO audio on/off parameter (audio is always produced), so
3474
3648
  // there is no toggle field — alwaysOn, like VEO.
3475
- "minimax-h3": { mode: "audio_driven", alwaysOn: true }
3649
+ "minimax-h3": { mode: "audio_driven", alwaysOn: true },
3650
+ // Wan 3.0 family — a single boolean `audio` lever (KIE default true) produces
3651
+ // an ambient/SFX track with the clip. Classified "ambient", NOT
3652
+ // "native_speech" or "audio_driven": the schema documents no dialogue
3653
+ // guarantee, and reference audio is a generic conditioning array, not a
3654
+ // verified lip-sync transport. Upgrade only on a live probe (the kling-3.0
3655
+ // standard) — `audio_driven` would reroute the Story→Video dialogue pipeline
3656
+ // and skip the lip-sync pass. `defaultOn` mirrors the KIE default so an
3657
+ // intent-less request is described honestly; audio is priced into the uniform
3658
+ // 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
+ "wan-3": { mode: "ambient", field: "audio", defaultOn: true },
3662
+ "wan-3-prime": { mode: "ambient", field: "audio", defaultOn: true }
3476
3663
  };
3477
3664
  var VIDEO_AUDIO_NONE = { mode: "none" };
3478
3665
  function getVideoAudioCapability(model) {
@@ -3491,6 +3678,7 @@ function applyVideoAudioToggle(input, provider, opts) {
3491
3678
  const enabled = cap.affectsCost ? opts?.sound : opts?.sound ?? opts?.generateAudio;
3492
3679
  if (enabled === void 0) return;
3493
3680
  if (cap.field === "generateAudio") input.generate_audio = enabled;
3681
+ else if (cap.field === "audio") input.audio = enabled;
3494
3682
  else input.sound = enabled;
3495
3683
  }
3496
3684
  var MODE_ADDON_PROVIDERS = /* @__PURE__ */ new Set([]);
@@ -3520,14 +3708,27 @@ var VIDEO_VARIABLE_PRICING = {
3520
3708
  // images are billed via the dedicated compute hook, not the identifier.
3521
3709
  "minimax-h3": "duration+resolution",
3522
3710
  // Grok Imagine Video 1.5 — per-second billing split 480p/720p (no video-ref dimension).
3523
- "grok-imagine-video-1.5": "duration+resolution"
3711
+ "grok-imagine-video-1.5": "duration+resolution",
3712
+ // Wan 3.0 family — per-second billing at three resolution rates (no video-ref
3713
+ // dimension: reference runs bill output seconds only). No gemini-omni-flash
3714
+ // entry, mirroring gemini-omni-video which has none either.
3715
+ "wan-3": "duration+resolution",
3716
+ "wan-3-prime": "duration+resolution"
3524
3717
  };
3525
3718
  var PRICING_DEFAULT_DURATION_SEC = {
3526
3719
  "minimax-h3": 6
3527
3720
  };
3528
3721
  var PRICING_DEFAULT_RESOLUTION = {
3529
3722
  // KIE renders 720p when `resolution` is omitted (kie/models.ts extraParams).
3530
- "seedance-2-5": "720p"
3723
+ "seedance-2-5": "720p",
3724
+ // Wan 3.0 family — KIE's OWN default is 1080P, but the provider layer pins
3725
+ // 720P (normalizeWan3Resolution / WAN_3_DEFAULT_RESOLUTION) so the rendered
3726
+ // tier equals the tier the bare identifier bills. This declaration is what
3727
+ // makes the billed default explicit instead of an array ordering: the
3728
+ // RESOLUTION_DURATION_PRICING branch consults it before falling back to the
3729
+ // first tier, so the catalog can stay ascending without repricing anything.
3730
+ "wan-3": "720p",
3731
+ "wan-3-prime": "720p"
3531
3732
  };
3532
3733
  var HAPPYHORSE_DURATION_TIERS = Array.from(
3533
3734
  { length: 13 },
@@ -3537,6 +3738,10 @@ var SEEDANCE_2_5_DURATION_TIERS = Array.from(
3537
3738
  { length: 27 },
3538
3739
  (_, i) => ({ maxSeconds: i + 4, suffix: `${i + 4}s` })
3539
3740
  );
3741
+ var WAN_3_DURATION_TIERS = Array.from(
3742
+ { length: 29 },
3743
+ (_, i) => ({ maxSeconds: i + 2, suffix: `${i + 2}s` })
3744
+ );
3540
3745
  var VIDEO_DURATION_TIERS = {
3541
3746
  "kling-3.0": [
3542
3747
  { maxSeconds: 5, suffix: "5s" },
@@ -3612,6 +3817,8 @@ var VIDEO_DURATION_TIERS = {
3612
3817
  { maxSeconds: 15, suffix: "15s" }
3613
3818
  ],
3614
3819
  "seedance-2-5": SEEDANCE_2_5_DURATION_TIERS,
3820
+ "wan-3": WAN_3_DURATION_TIERS,
3821
+ "wan-3-prime": WAN_3_DURATION_TIERS,
3615
3822
  // MiniMax Hailuo 3 — true per-second billing (KIE 36.5 cr/s @2K, 22.5 cr/s
3616
3823
  // @768P). One tier per allowed second (4-15s) so the composite identifier
3617
3824
  // maps 1:1 to the seeded price — no rounding/overcharge for any on-menu
@@ -4261,13 +4468,13 @@ function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mo
4261
4468
  if (resolution === "1080p" && VEO_RESOLUTION_TIERED_PROVIDERS.has(effectiveProvider)) return `${effectiveProvider}:1080p`;
4262
4469
  return effectiveProvider;
4263
4470
  }
4264
- if (effectiveProvider === "gemini-omni-video") {
4471
+ if (isGeminiOmniProvider(effectiveProvider)) {
4265
4472
  if (hasVideoRef) {
4266
- return resolution === "4k" ? "gemini-omni-video:4k:vref" : "gemini-omni-video:vref";
4473
+ return resolution === "4k" ? `${effectiveProvider}:4k:vref` : `${effectiveProvider}:vref`;
4267
4474
  }
4268
4475
  const raw = parseInt(String(duration ?? 8), 10);
4269
4476
  const d = Number.isNaN(raw) ? 8 : GEMINI_OMNI_DURATIONS.reduce((b, a) => Math.abs(a - raw) < Math.abs(b - raw) ? a : b);
4270
- return resolution === "4k" ? `gemini-omni-video:4k:${d}` : `gemini-omni-video:${d}`;
4477
+ return resolution === "4k" ? `${effectiveProvider}:4k:${d}` : `${effectiveProvider}:${d}`;
4271
4478
  }
4272
4479
  if (effectiveProvider === "ltx-2.3-pro" || effectiveProvider === "ltx-2.3-fast") {
4273
4480
  const bands = LTX_DURATION_TIERS[effectiveProvider];
@@ -4305,7 +4512,10 @@ function buildVideoCreditModelIdentifier(provider, duration, sound, nodeType, mo
4305
4512
  }
4306
4513
  const resTiers = RESOLUTION_DURATION_PRICING[effectiveProvider];
4307
4514
  if (resTiers) {
4308
- const res = resolution && resTiers.includes(resolution) ? resolution : resTiers[0];
4515
+ const declaredDefault = PRICING_DEFAULT_RESOLUTION[effectiveProvider];
4516
+ const fallback = declaredDefault && resTiers.includes(declaredDefault) ? declaredDefault : resTiers[0];
4517
+ const requested = isWan3Provider(effectiveProvider) ? normalizeWan3Resolution(resolution).toLowerCase() : resolution;
4518
+ const res = requested && resTiers.includes(requested) ? requested : fallback;
4309
4519
  identifier += `:${res}`;
4310
4520
  }
4311
4521
  if (isMinimaxH3Provider(effectiveProvider) && normalizeMinimaxH3Resolution(resolution) === "768P") {
@@ -7925,6 +8135,10 @@ var QUALITY_MAP = {
7925
8135
  // Seedance 2.5 spans 480p/720p/1080p on KIE (1080p accepted since the
7926
8136
  // 2026-08-17 re-probe; 4k still rejected), so each quality rung gets its own tier.
7927
8137
  "seedance-2-5": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
8138
+ // Wan 3.0 family — 480p / 720p / 1080p (lowercase catalog spellings; the
8139
+ // uppercase KIE wire form is produced only by normalizeWan3Resolution).
8140
+ "wan-3": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
8141
+ "wan-3-prime": { field: "resolution", values: { low: "480p", mid: "720p", high: "1080p" } },
7928
8142
  "wan-2.7-i2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
7929
8143
  "wan-2.7-t2v": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
7930
8144
  "happyhorse": { field: "resolution", values: { low: "720p", mid: "1080p", high: "1080p" } },
@@ -7938,6 +8152,7 @@ var QUALITY_MAP = {
7938
8152
  "ltx-2.3-pro": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
7939
8153
  "ltx-2.3-fast": { field: "resolution", values: { low: "1080p", mid: "2k", high: "4k" } },
7940
8154
  "gemini-omni-video": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
8155
+ "gemini-omni-flash": { field: "resolution", values: { low: "720p", mid: "1080p", high: "4k" } },
7941
8156
  // Grok Imagine Video 1.5 — only 480p/720p (no 1080p tier); high clamps to 720p.
7942
8157
  "grok-imagine-video-1.5": { field: "resolution", values: { low: "480p", mid: "720p", high: "720p" } },
7943
8158
  // Replicate Flux 2 family — MP-based resolution (matching IMAGE_RESOLUTION_OPTIONS["flux-2-*"]).
@@ -13642,6 +13857,21 @@ function bucketSecondsFromAuditCreditId(id) {
13642
13857
  return m ? Number(m[1]) : null;
13643
13858
  }
13644
13859
 
13860
+ // src/video-ui-defaults.ts
13861
+ function uiAspectRatioFill(provider) {
13862
+ return isSeedance2Provider(provider) || isMinimaxH3Provider(provider) || isWan3Provider(provider) ? "adaptive" : void 0;
13863
+ }
13864
+ function uiResolutionFill(provider) {
13865
+ if (isWan3Provider(provider)) return PRICING_DEFAULT_RESOLUTION[provider];
13866
+ if (isSeedance2Provider(provider)) return MODEL_CATALOG[provider]?.resolutions?.[0];
13867
+ return void 0;
13868
+ }
13869
+ function uiDurationFill(provider) {
13870
+ if (isWan3Provider(provider)) return 5;
13871
+ if (isGeminiOmniProvider(provider)) return 8;
13872
+ return void 0;
13873
+ }
13874
+
13645
13875
  // src/smart-cut-windows.ts
13646
13876
  var SMART_CUT_WINDOW_MAX = 24;
13647
13877
  var SMART_CUT_WINDOW_MIN = 1;
@@ -13966,6 +14196,7 @@ exports.FURNITURE_SUBCATEGORY_LABELS = FURNITURE_SUBCATEGORY_LABELS;
13966
14196
  exports.FURNITURE_SUBCATEGORY_ORDER = FURNITURE_SUBCATEGORY_ORDER;
13967
14197
  exports.FixContinuityInputSchema = FixContinuityInputSchema;
13968
14198
  exports.FixContinuityResultSchema = FixContinuityResultSchema;
14199
+ exports.GEMINI_OMNI_PROVIDERS = GEMINI_OMNI_PROVIDERS;
13969
14200
  exports.GENERATE_TEXT_DELIMITER = GENERATE_TEXT_DELIMITER;
13970
14201
  exports.GLOBAL_MAX_DURATION_SECONDS = GLOBAL_MAX_DURATION_SECONDS;
13971
14202
  exports.GRANTED_ACCESS = GRANTED_ACCESS;
@@ -14281,6 +14512,8 @@ exports.ValidateMatchCutInputSchema = ValidateMatchCutInputSchema;
14281
14512
  exports.ValidateMatchCutResultSchema = ValidateMatchCutResultSchema;
14282
14513
  exports.VideoCriticVerdictSchema = VideoCriticVerdictSchema;
14283
14514
  exports.VoiceMatchSchema = VoiceMatchSchema;
14515
+ exports.WAN_3_DEFAULT_RESOLUTION = WAN_3_DEFAULT_RESOLUTION;
14516
+ exports.WAN_3_PROVIDERS = WAN_3_PROVIDERS;
14284
14517
  exports.WARDROBE_VARIANTS = WARDROBE_VARIANTS;
14285
14518
  exports.WEAPONS = WEAPONS;
14286
14519
  exports.WEAPON_SUBCATEGORY_LABELS = WEAPON_SUBCATEGORY_LABELS;
@@ -14463,6 +14696,7 @@ exports.isCollectInEdge = isCollectInEdge;
14463
14696
  exports.isDefaultSelectorConfig = isDefaultSelectorConfig;
14464
14697
  exports.isExpandedClone = isExpandedClone;
14465
14698
  exports.isFlux2Model = isFlux2Model;
14699
+ exports.isGeminiOmniProvider = isGeminiOmniProvider;
14466
14700
  exports.isGvpSupportedProvider = isGvpSupportedProvider;
14467
14701
  exports.isHandleInputWired = isHandleInputWired;
14468
14702
  exports.isKineticCaptionStyle = isKineticCaptionStyle;
@@ -14479,6 +14713,7 @@ exports.isUsageMode = isUsageMode;
14479
14713
  exports.isVeoProvider = isVeoProvider;
14480
14714
  exports.isVideoAnalysisMixedTier = isVideoAnalysisMixedTier;
14481
14715
  exports.isVideoAnalysisTier = isVideoAnalysisTier;
14716
+ exports.isWan3Provider = isWan3Provider;
14482
14717
  exports.jsonResultToList = jsonResultToList;
14483
14718
  exports.knownEntitySlugsFromRefs = knownEntitySlugsFromRefs;
14484
14719
  exports.knownImageSlugsFromRefs = knownImageSlugsFromRefs;
@@ -14511,6 +14746,7 @@ exports.normalizeModelInput = normalizeModelInput;
14511
14746
  exports.normalizeNodeModelParams = normalizeNodeModelParams;
14512
14747
  exports.normalizePinterestUrl = normalizePinterestUrl;
14513
14748
  exports.normalizeRoleSlug = normalizeRoleSlug;
14749
+ exports.normalizeWan3Resolution = normalizeWan3Resolution;
14514
14750
  exports.orderedLlmModels = orderedLlmModels;
14515
14751
  exports.parseAttributedDialogue = parseAttributedDialogue;
14516
14752
  exports.parseCharacterMentionToken = parseCharacterMentionToken;
@@ -14618,6 +14854,9 @@ exports.toConnectedReference = toConnectedReference;
14618
14854
  exports.toConnectedReferences = toConnectedReferences;
14619
14855
  exports.togglePick = togglePick;
14620
14856
  exports.tryParseJson = tryParseJson;
14857
+ exports.uiAspectRatioFill = uiAspectRatioFill;
14858
+ exports.uiDurationFill = uiDurationFill;
14859
+ exports.uiResolutionFill = uiResolutionFill;
14621
14860
  exports.unwrapUnresolvedTokens = unwrapUnresolvedTokens;
14622
14861
  exports.usageModeDirective = usageModeDirective;
14623
14862
  exports.usageModeIncludesName = usageModeIncludesName;