@shop-os/modelkit 0.1.10 → 0.2.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/catalog.js CHANGED
@@ -93,11 +93,18 @@ var Catalog = class _Catalog {
93
93
  ...rows
94
94
  ]);
95
95
  }
96
+ /** Atomically swap every row. Builds the maps first so a bad batch throws before anything changes. */
97
+ replace(rows) {
98
+ const next = new _Catalog(rows);
99
+ this.byId.clear();
100
+ this.byAlias.clear();
101
+ for (const [id, model] of next.byId) this.byId.set(id, model);
102
+ for (const [alias, id] of next.byAlias) this.byAlias.set(alias, id);
103
+ }
96
104
  };
97
105
 
98
106
  // src/catalog/image.ts
99
- var IMAGE_USAGE = { unit: "images", modality: "IMAGE" };
100
- var IMAGE_GENERATE_EDIT = { imageGenerate: true, imageEdit: true };
107
+ var IMAGE_USAGE = { unit: "images" };
101
108
  var GEMINI_RATIOS = [
102
109
  "1:1",
103
110
  "2:3",
@@ -129,8 +136,7 @@ function geminiImage(id, label, aliases, sizes, display, exposure) {
129
136
  defaults: { size: "1K", aspectRatio: "1:1" },
130
137
  usage: { ...IMAGE_USAGE, slug: "gemini" },
131
138
  pricingKind: "image_size",
132
- display,
133
- capabilities: { ...IMAGE_GENERATE_EDIT }
139
+ display
134
140
  };
135
141
  return model;
136
142
  }
@@ -217,8 +223,7 @@ var IMAGE_MODELS = [
217
223
  provider: "openai",
218
224
  description: "The most capable model for image editing and complex creative instructions. Excels at text rendering, visual consistency, design generation, and iterative refinement.",
219
225
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/1204b494-8962-4f7f-af5e-699a8bdc98e3_compressed.png"
220
- },
221
- capabilities: { ...IMAGE_GENERATE_EDIT }
226
+ }
222
227
  },
223
228
  {
224
229
  // Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
@@ -252,8 +257,7 @@ var IMAGE_MODELS = [
252
257
  display: {
253
258
  provider: "openai",
254
259
  description: "OpenAI's most capable GPT Image 2.5 tier, built for editing precision; takes text and image input and outputs images in low, medium, high, xhigh, or max quality."
255
- },
256
- capabilities: { ...IMAGE_GENERATE_EDIT }
260
+ }
257
261
  },
258
262
  {
259
263
  // Same Images API surface as gpt-image-2 plus the "xhigh" and "max" quality tiers.
@@ -287,8 +291,7 @@ var IMAGE_MODELS = [
287
291
  display: {
288
292
  provider: "openai",
289
293
  description: "OpenAI's fastest GPT Image 2.5 tier for high-quality everyday image generation and editing; takes text and image input and outputs images."
290
- },
291
- capabilities: { ...IMAGE_GENERATE_EDIT }
294
+ }
292
295
  },
293
296
  {
294
297
  // Cowork allows 7 ratios; trigger-workflows allows 9 (adds 3:2, 9:21, drops 4:5/5:4).
@@ -326,8 +329,7 @@ var IMAGE_MODELS = [
326
329
  provider: "meta",
327
330
  description: "Meta's image model with built-in world knowledge and strong prompt adherence. Great for concept-rich scenes, realistic compositions, and reference-guided edits.",
328
331
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/characters/1787909065794-k9a7zz.png"
329
- },
330
- capabilities: { ...IMAGE_GENERATE_EDIT }
332
+ }
331
333
  },
332
334
  {
333
335
  id: "seedream-5-0-pro",
@@ -353,8 +355,7 @@ var IMAGE_MODELS = [
353
355
  provider: "bytedance",
354
356
  logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/3bba5d81-4e57-4e71-911b-cdfa05acca2c_compressed.png",
355
357
  description: "ByteDance Seedream 5.0 Pro text-to-image and multi-reference image-to-image (up to 10 inputs) with region editing; outputs 1K, 1.5K, or 2K."
356
- },
357
- capabilities: { ...IMAGE_GENERATE_EDIT }
358
+ }
358
359
  },
359
360
  {
360
361
  id: "seedream-4.5",
@@ -391,8 +392,7 @@ var IMAGE_MODELS = [
391
392
  display: {
392
393
  provider: "bytedance",
393
394
  description: "ByteDance Seedream 4.5 text-to-image and image-to-image with up to 14 reference images and batch image-set generation; outputs 2K or 4K."
394
- },
395
- capabilities: { ...IMAGE_GENERATE_EDIT }
395
+ }
396
396
  },
397
397
  {
398
398
  id: "flux-2-pro",
@@ -414,9 +414,9 @@ var IMAGE_MODELS = [
414
414
  pricingKind: "image_size",
415
415
  display: {
416
416
  provider: "black-forest-labs",
417
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/flux.png",
417
418
  description: "Black Forest Labs FLUX.2 [pro] text-to-image and multi-reference editing model served via Prodia; takes a prompt and up to 8 input images and outputs up to 4096x4096."
418
- },
419
- capabilities: { ...IMAGE_GENERATE_EDIT }
419
+ }
420
420
  },
421
421
  {
422
422
  // Prodia's gemini-3-pro jobs take aspect_ratio + resolution (1K/2K/4K), not
@@ -442,8 +442,7 @@ var IMAGE_MODELS = [
442
442
  display: {
443
443
  provider: "google",
444
444
  description: "Google Gemini 3 Pro image generation and editing served via Prodia; takes a prompt plus up to 3 reference images and outputs 1K, 2K, or 4K."
445
- },
446
- capabilities: { ...IMAGE_GENERATE_EDIT }
445
+ }
447
446
  },
448
447
  {
449
448
  // Nano Banana (img2img.v2) is flat-rate with aspect_ratio only; 3:2, 4:5,
@@ -468,8 +467,7 @@ var IMAGE_MODELS = [
468
467
  display: {
469
468
  provider: "google",
470
469
  description: "Google Nano Banana image generation and editing served via Prodia; takes a prompt plus 1-3 input images and matches the first input's aspect ratio in roughly 8 seconds."
471
- },
472
- capabilities: { ...IMAGE_GENERATE_EDIT }
470
+ }
473
471
  },
474
472
  {
475
473
  // WAN 2.7 takes `images` (up to 9) and a `size` enum whose exact values
@@ -490,13 +488,12 @@ var IMAGE_MODELS = [
490
488
  supports: []
491
489
  },
492
490
  defaults: { size: "1K", aspectRatio: "1:1" },
493
- usage: { unit: "compute_seconds", modality: "IMAGE" },
491
+ usage: { unit: "compute_seconds" },
494
492
  pricingKind: "image_size",
495
493
  display: {
496
494
  provider: "alibaba",
497
495
  description: "Alibaba Wan 2.7 Image Pro text-to-image and image-editing model; takes a prompt plus up to 9 reference images and generates up to 4K (4096x4096)."
498
- },
499
- capabilities: { ...IMAGE_GENERATE_EDIT }
496
+ }
500
497
  },
501
498
  {
502
499
  // Qwen Image 2 Pro has aspect_ratio but no size input; resolution follows
@@ -518,13 +515,12 @@ var IMAGE_MODELS = [
518
515
  supports: []
519
516
  },
520
517
  defaults: { aspectRatio: "1:1" },
521
- usage: { unit: "compute_seconds", modality: "IMAGE" },
518
+ usage: { unit: "compute_seconds" },
522
519
  pricingKind: "image_size",
523
520
  display: {
524
521
  provider: "alibaba",
525
522
  description: "Alibaba Qwen Image 2 Pro unified text-to-image and editing model; takes a prompt plus an optional single reference image and generates native 2K output."
526
- },
527
- capabilities: { ...IMAGE_GENERATE_EDIT }
523
+ }
528
524
  },
529
525
  {
530
526
  // Qwen Image Edit Plus takes aspect_ratio (or match_input_image) and
@@ -546,13 +542,12 @@ var IMAGE_MODELS = [
546
542
  supports: ["outputFormat"]
547
543
  },
548
544
  defaults: { outputFormat: "png" },
549
- usage: { unit: "compute_seconds", modality: "IMAGE" },
545
+ usage: { unit: "compute_seconds" },
550
546
  pricingKind: "image_size",
551
547
  display: {
552
548
  provider: "alibaba",
553
549
  description: "Alibaba Qwen Image Edit Plus with Lightning and a skin-retouching LoRA; takes one or more reference images plus an edit prompt and outputs webp, jpg, or png."
554
- },
555
- capabilities: { ...IMAGE_GENERATE_EDIT }
550
+ }
556
551
  }
557
552
  ];
558
553
 
@@ -574,7 +569,7 @@ var OTHER_MODELS = [
574
569
  supports: []
575
570
  },
576
571
  defaults: {},
577
- usage: { unit: "images", modality: "AUDIO" },
572
+ usage: { unit: "images" },
578
573
  pricingKind: "flat",
579
574
  display: {
580
575
  provider: "google",
@@ -597,7 +592,7 @@ var OTHER_MODELS = [
597
592
  supports: []
598
593
  },
599
594
  defaults: {},
600
- usage: { unit: "images", modality: "AUDIO" },
595
+ usage: { unit: "images" },
601
596
  pricingKind: "flat",
602
597
  display: {
603
598
  provider: "google",
@@ -620,7 +615,7 @@ var OTHER_MODELS = [
620
615
  supports: ["seed", "negativePrompt"]
621
616
  },
622
617
  defaults: {},
623
- usage: { unit: "compute_seconds", modality: "AUDIO" },
618
+ usage: { unit: "compute_seconds" },
624
619
  pricingKind: "flat",
625
620
  display: {
626
621
  provider: "google",
@@ -643,7 +638,7 @@ var OTHER_MODELS = [
643
638
  supports: ["seed", "negativePrompt"]
644
639
  },
645
640
  defaults: { durationSeconds: 8 },
646
- usage: { unit: "compute_seconds", modality: "AUDIO" },
641
+ usage: { unit: "compute_seconds" },
647
642
  pricingKind: "flat",
648
643
  display: {
649
644
  provider: "mmaudio",
@@ -666,7 +661,7 @@ var OTHER_MODELS = [
666
661
  },
667
662
  defaults: { durationSeconds: 15, instrumental: true },
668
663
  // Replicate's run() does not report predict_time; billed by generated length.
669
- usage: { unit: "seconds", modality: "AUDIO" },
664
+ usage: { unit: "seconds" },
670
665
  pricingKind: "flat",
671
666
  display: {
672
667
  provider: "elevenlabs",
@@ -689,13 +684,13 @@ var OTHER_MODELS = [
689
684
  supports: ["scaleFactor", "outputFormat", "upscale"]
690
685
  },
691
686
  defaults: { scaleFactor: 2, outputFormat: "png" },
692
- usage: { unit: "compute_seconds", modality: "IMAGE" },
687
+ usage: { unit: "compute_seconds" },
693
688
  pricingKind: "flat",
694
689
  display: {
695
690
  provider: "topaz",
691
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/topazlabs.png",
696
692
  description: "Topaz Labs AI image upscaling on Replicate; takes one input image and upscales up to 6x with selectable enhancement models and optional face enhancement."
697
- },
698
- capabilities: { imageEdit: true }
693
+ }
699
694
  },
700
695
  {
701
696
  id: "bg-remove",
@@ -712,19 +707,30 @@ var OTHER_MODELS = [
712
707
  supports: []
713
708
  },
714
709
  defaults: {},
715
- usage: { unit: "images", modality: "IMAGE" },
710
+ usage: { unit: "images" },
716
711
  pricingKind: "flat",
717
712
  display: {
718
713
  provider: "prodia",
719
714
  description: "Prodia background removal; takes one input image and returns a PNG cut-out of the subject plus an optional black-and-white mask."
720
- },
721
- capabilities: { imageEdit: true }
715
+ }
722
716
  }
723
717
  ];
724
718
 
725
719
  // src/catalog/text.ts
726
- var TEXT_USAGE = { unit: "tokens", modality: "TEXT" };
720
+ var TEXT_USAGE = { unit: "tokens" };
721
+ var CDN = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image";
722
+ var PROVIDER_LOGOS = {
723
+ anthropic: `${CDN}/25fad392-188c-4829-a3d0-c4fa02d1c8cd.png`,
724
+ openai: `${CDN}/1204b494-8962-4f7f-af5e-699a8bdc98e3.png`,
725
+ google: `${CDN}/192485d2-a76a-4657-9c06-930b2c70badd.png`,
726
+ deepseek: `${CDN}/9b7406d2-a696-4558-ab79-90a37e3f4574.png`,
727
+ xai: `${CDN}/858b7fcc-9bd5-411d-aea1-a7b35ecfffab.png`,
728
+ moonshot: `${CDN}/5a1e2eae-3474-4fac-9c74-a93f41ee6f67.png`,
729
+ minimax: `${CDN}/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png`
730
+ };
727
731
  function text(id, label, providerModelId, extra) {
732
+ const display = extra?.display;
733
+ const logo = display && !display.logo ? PROVIDER_LOGOS[display.provider] : void 0;
728
734
  return {
729
735
  id,
730
736
  aliases: [],
@@ -738,7 +744,8 @@ function text(id, label, providerModelId, extra) {
738
744
  defaults: {},
739
745
  usage: { ...TEXT_USAGE },
740
746
  pricingKind: "token",
741
- ...extra
747
+ ...extra,
748
+ ...display && logo ? { display: { ...display, logo } } : {}
742
749
  };
743
750
  }
744
751
  var ANTHROPIC_THINKING = {
@@ -757,7 +764,7 @@ var TEXT_MODELS = [
757
764
  costTier: 2,
758
765
  description: "OpenAI GPT-4o flagship multimodal model; text and image input, 128K-token context."
759
766
  },
760
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
767
+ capabilities: { vision: true, contextWindow: 128e3 }
761
768
  }),
762
769
  text("gpt-4o-mini", "GPT-4o mini", "gpt-4o-mini", {
763
770
  exposure: "internal",
@@ -766,7 +773,7 @@ var TEXT_MODELS = [
766
773
  costTier: 1,
767
774
  description: "OpenAI GPT-4o mini fast, low-cost multimodal model; text and image input, 128K-token context."
768
775
  },
769
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 128e3 }
776
+ capabilities: { vision: true, contextWindow: 128e3 }
770
777
  }),
771
778
  text("gpt-5.1", "GPT-5.1", "gpt-5.1", {
772
779
  exposure: "catalog",
@@ -775,7 +782,7 @@ var TEXT_MODELS = [
775
782
  costTier: 3,
776
783
  description: "OpenAI GPT-5.1 reasoning model for coding and agentic tasks; text and image input, 400K-token context."
777
784
  },
778
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
785
+ capabilities: { vision: true, contextWindow: 4e5 }
779
786
  }),
780
787
  text("gpt-5.2", "GPT-5.2", "gpt-5.2", {
781
788
  exposure: "catalog",
@@ -784,7 +791,7 @@ var TEXT_MODELS = [
784
791
  costTier: 3,
785
792
  description: "OpenAI GPT-5.2 reasoning model for complex professional work; text and image input, 400K-token context."
786
793
  },
787
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
794
+ capabilities: { vision: true, contextWindow: 4e5 }
788
795
  }),
789
796
  // 1.05M-token context: https://platform.openai.com/docs/models/gpt-5.4
790
797
  text("gpt-5.4", "GPT-5.4", "gpt-5.4", {
@@ -796,8 +803,6 @@ var TEXT_MODELS = [
796
803
  },
797
804
  capabilities: {
798
805
  vision: true,
799
- tools: true,
800
- structuredOutput: true,
801
806
  contextWindow: 105e4
802
807
  }
803
808
  }),
@@ -810,7 +815,7 @@ var TEXT_MODELS = [
810
815
  costTier: 1,
811
816
  description: "OpenAI GPT-5.4 mini efficient reasoning model for high-volume workloads; text and image input, 400K-token context."
812
817
  },
813
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 4e5 }
818
+ capabilities: { vision: true, contextWindow: 4e5 }
814
819
  }),
815
820
  text("gpt-5.5", "GPT-5.5", "gpt-5.5", {
816
821
  exposure: "catalog",
@@ -821,8 +826,6 @@ var TEXT_MODELS = [
821
826
  },
822
827
  capabilities: {
823
828
  vision: true,
824
- tools: true,
825
- structuredOutput: true,
826
829
  contextWindow: 105e4
827
830
  }
828
831
  }),
@@ -837,8 +840,6 @@ var TEXT_MODELS = [
837
840
  capabilities: {
838
841
  reasoning: true,
839
842
  vision: true,
840
- tools: true,
841
- structuredOutput: true,
842
843
  contextWindow: 105e4
843
844
  }
844
845
  }),
@@ -853,8 +854,6 @@ var TEXT_MODELS = [
853
854
  capabilities: {
854
855
  reasoning: true,
855
856
  vision: true,
856
- tools: true,
857
- structuredOutput: true,
858
857
  contextWindow: 105e4
859
858
  }
860
859
  }),
@@ -869,8 +868,6 @@ var TEXT_MODELS = [
869
868
  capabilities: {
870
869
  reasoning: true,
871
870
  vision: true,
872
- tools: true,
873
- structuredOutput: true,
874
871
  contextWindow: 105e4
875
872
  }
876
873
  }),
@@ -883,7 +880,7 @@ var TEXT_MODELS = [
883
880
  costTier: 2,
884
881
  description: "Anthropic Claude Sonnet 4.5 (legacy) balanced model; text and image input, 200K-token context."
885
882
  },
886
- capabilities: { vision: true, tools: true, structuredOutput: true, contextWindow: 2e5 }
883
+ capabilities: { vision: true, contextWindow: 2e5 }
887
884
  }),
888
885
  // Anthropic retired the dated 4.0 ids; callers that still send them get 4.6.
889
886
  text("claude-sonnet-4-6", "Claude Sonnet 4.6", "claude-sonnet-4-6", {
@@ -903,8 +900,6 @@ var TEXT_MODELS = [
903
900
  capabilities: {
904
901
  reasoning: true,
905
902
  vision: true,
906
- tools: true,
907
- structuredOutput: true,
908
903
  contextWindow: 1e6
909
904
  }
910
905
  }),
@@ -919,8 +914,6 @@ var TEXT_MODELS = [
919
914
  capabilities: {
920
915
  reasoning: true,
921
916
  vision: true,
922
- tools: true,
923
- structuredOutput: true,
924
917
  contextWindow: 1e6
925
918
  }
926
919
  }),
@@ -936,8 +929,6 @@ var TEXT_MODELS = [
936
929
  capabilities: {
937
930
  reasoning: true,
938
931
  vision: true,
939
- tools: true,
940
- structuredOutput: true,
941
932
  contextWindow: 1e6
942
933
  }
943
934
  }),
@@ -953,8 +944,6 @@ var TEXT_MODELS = [
953
944
  capabilities: {
954
945
  reasoning: true,
955
946
  vision: true,
956
- tools: true,
957
- structuredOutput: true,
958
947
  contextWindow: 2e5
959
948
  }
960
949
  }),
@@ -968,8 +957,6 @@ var TEXT_MODELS = [
968
957
  },
969
958
  capabilities: {
970
959
  vision: true,
971
- tools: true,
972
- structuredOutput: true,
973
960
  contextWindow: 1e6
974
961
  }
975
962
  }),
@@ -982,8 +969,6 @@ var TEXT_MODELS = [
982
969
  },
983
970
  capabilities: {
984
971
  vision: true,
985
- tools: true,
986
- structuredOutput: true,
987
972
  contextWindow: 1e6
988
973
  }
989
974
  }),
@@ -996,8 +981,6 @@ var TEXT_MODELS = [
996
981
  },
997
982
  capabilities: {
998
983
  vision: true,
999
- tools: true,
1000
- structuredOutput: true,
1001
984
  contextWindow: 1048576
1002
985
  }
1003
986
  }),
@@ -1010,8 +993,6 @@ var TEXT_MODELS = [
1010
993
  },
1011
994
  capabilities: {
1012
995
  vision: true,
1013
- tools: true,
1014
- structuredOutput: true,
1015
996
  contextWindow: 1048576
1016
997
  }
1017
998
  }),
@@ -1024,8 +1005,6 @@ var TEXT_MODELS = [
1024
1005
  },
1025
1006
  capabilities: {
1026
1007
  vision: true,
1027
- tools: true,
1028
- structuredOutput: true,
1029
1008
  contextWindow: 1048576
1030
1009
  }
1031
1010
  }),
@@ -1038,8 +1017,6 @@ var TEXT_MODELS = [
1038
1017
  },
1039
1018
  capabilities: {
1040
1019
  vision: true,
1041
- tools: true,
1042
- structuredOutput: true,
1043
1020
  contextWindow: 1048576
1044
1021
  }
1045
1022
  }),
@@ -1052,8 +1029,6 @@ var TEXT_MODELS = [
1052
1029
  },
1053
1030
  capabilities: {
1054
1031
  vision: true,
1055
- tools: true,
1056
- structuredOutput: true,
1057
1032
  contextWindow: 1048576
1058
1033
  }
1059
1034
  }),
@@ -1067,8 +1042,6 @@ var TEXT_MODELS = [
1067
1042
  },
1068
1043
  capabilities: {
1069
1044
  vision: true,
1070
- tools: true,
1071
- structuredOutput: true,
1072
1045
  contextWindow: 1048576
1073
1046
  }
1074
1047
  }),
@@ -1081,8 +1054,6 @@ var TEXT_MODELS = [
1081
1054
  },
1082
1055
  capabilities: {
1083
1056
  vision: true,
1084
- tools: true,
1085
- structuredOutput: true,
1086
1057
  contextWindow: 1048576
1087
1058
  }
1088
1059
  }),
@@ -1101,8 +1072,6 @@ var TEXT_MODELS = [
1101
1072
  },
1102
1073
  capabilities: {
1103
1074
  vision: true,
1104
- tools: true,
1105
- structuredOutput: true,
1106
1075
  contextWindow: 1048576
1107
1076
  }
1108
1077
  }),
@@ -1115,8 +1084,6 @@ var TEXT_MODELS = [
1115
1084
  },
1116
1085
  capabilities: {
1117
1086
  vision: true,
1118
- tools: false,
1119
- structuredOutput: true,
1120
1087
  contextWindow: 128e3
1121
1088
  }
1122
1089
  }),
@@ -1129,8 +1096,6 @@ var TEXT_MODELS = [
1129
1096
  },
1130
1097
  capabilities: {
1131
1098
  vision: true,
1132
- tools: false,
1133
- structuredOutput: true,
1134
1099
  contextWindow: 2e5
1135
1100
  }
1136
1101
  }),
@@ -1143,8 +1108,6 @@ var TEXT_MODELS = [
1143
1108
  },
1144
1109
  capabilities: {
1145
1110
  vision: true,
1146
- tools: false,
1147
- structuredOutput: true,
1148
1111
  contextWindow: 128e3
1149
1112
  }
1150
1113
  }),
@@ -1164,8 +1127,6 @@ var TEXT_MODELS = [
1164
1127
  capabilities: {
1165
1128
  reasoning: true,
1166
1129
  vision: true,
1167
- tools: true,
1168
- structuredOutput: true,
1169
1130
  contextWindow: 1e6
1170
1131
  }
1171
1132
  }),
@@ -1180,8 +1141,6 @@ var TEXT_MODELS = [
1180
1141
  capabilities: {
1181
1142
  reasoning: true,
1182
1143
  vision: false,
1183
- tools: true,
1184
- structuredOutput: true,
1185
1144
  contextWindow: 1e6
1186
1145
  }
1187
1146
  }),
@@ -1195,14 +1154,14 @@ var TEXT_MODELS = [
1195
1154
  },
1196
1155
  capabilities: {
1197
1156
  vision: true,
1198
- tools: true,
1199
- structuredOutput: true,
1200
1157
  contextWindow: 1e6
1201
1158
  }
1202
1159
  }),
1203
1160
  // Moonshot retired kimi-k2.5 on 2026-08-31 and no longer publishes its specs.
1204
1161
  text("kimi-k2.5", "Kimi K2.5", "kimi-k2.5", {
1205
- exposure: "catalog",
1162
+ lifecycle: "deprecated",
1163
+ replacedBy: "kimi-k3",
1164
+ exposure: "internal",
1206
1165
  display: {
1207
1166
  chat: { temperature: 1 },
1208
1167
  provider: "moonshot",
@@ -1222,8 +1181,6 @@ var TEXT_MODELS = [
1222
1181
  capabilities: {
1223
1182
  reasoning: true,
1224
1183
  vision: true,
1225
- tools: true,
1226
- structuredOutput: true,
1227
1184
  contextWindow: 1e6
1228
1185
  }
1229
1186
  }),
@@ -1237,12 +1194,12 @@ var TEXT_MODELS = [
1237
1194
  costTier: 2,
1238
1195
  description: "MiniMax M3 frontier multimodal model for agentic reasoning, tool use, and coding; text, image, and video input, 1M-token context."
1239
1196
  },
1240
- capabilities: { vision: true, tools: true, contextWindow: 1e6 }
1197
+ capabilities: { vision: true, contextWindow: 1e6 }
1241
1198
  })
1242
1199
  ];
1243
1200
 
1244
1201
  // src/catalog/video.ts
1245
- var VIDEO_USAGE = { unit: "seconds", modality: "VIDEO" };
1202
+ var VIDEO_USAGE = { unit: "seconds" };
1246
1203
  var SEEDANCE_RATIOS = ["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "adaptive"];
1247
1204
  var KLING_RATIOS = ["16:9", "9:16", "1:1", "adaptive"];
1248
1205
  var OMNI_RATIOS = ["16:9", "9:16"];
@@ -1416,7 +1373,7 @@ var VIDEO_MODELS = [
1416
1373
  constraints: {
1417
1374
  aspectRatios: [...SEEDANCE_RATIOS],
1418
1375
  resolutions: ["480p", "720p", "1080p", "4k"],
1419
- durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1376
+ durations: { min: 4, max: 15 },
1420
1377
  durationPresets: [4, 6, 8, 10, 12, 15],
1421
1378
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1422
1379
  ratioIgnoredWith: ["firstFrame"],
@@ -1449,7 +1406,7 @@ var VIDEO_MODELS = [
1449
1406
  constraints: {
1450
1407
  aspectRatios: [...SEEDANCE_RATIOS],
1451
1408
  resolutions: ["480p", "720p"],
1452
- durations: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
1409
+ durations: { min: 4, max: 15 },
1453
1410
  references: { images: 9, videos: 3, audios: 3, audioOnly: false },
1454
1411
  ratioIgnoredWith: ["firstFrame"],
1455
1412
  supports: ["generateAudio", "seed", "lastFrame", "watermark"]
@@ -1522,7 +1479,7 @@ var VIDEO_MODELS = [
1522
1479
  },
1523
1480
  // No resolution default: xAI picks its own unless the caller asks.
1524
1481
  defaults: { durationSeconds: 8, aspectRatio: "16:9" },
1525
- usage: { unit: "reported_cost_usd", modality: "VIDEO", slug: "grok" },
1482
+ usage: { unit: "reported_cost_usd", slug: "grok" },
1526
1483
  pricingKind: "video_per_second",
1527
1484
  display: {
1528
1485
  provider: "xai",
@@ -1556,6 +1513,7 @@ var VIDEO_MODELS = [
1556
1513
  pricingKind: "video_per_second",
1557
1514
  display: {
1558
1515
  provider: "kuaishou",
1516
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1559
1517
  description: "Kuaishou Kling 2.5 Turbo Pro image-to-video; animates a single input image from a text prompt with an optional end image, 5- or 10-second clips."
1560
1518
  },
1561
1519
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
@@ -1586,6 +1544,7 @@ var VIDEO_MODELS = [
1586
1544
  pricingKind: "video_per_second",
1587
1545
  display: {
1588
1546
  provider: "kuaishou",
1547
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1589
1548
  description: "Kuaishou Kling 3.0 Pro image-to-video; a required start image plus a text prompt (or multi-shot prompts) with optional end image and native audio, 3-15 second clips."
1590
1549
  },
1591
1550
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
@@ -1619,10 +1578,11 @@ var VIDEO_MODELS = [
1619
1578
  supports: ["generateAudio", "lastFrame"]
1620
1579
  },
1621
1580
  defaults: { durationSeconds: 5, aspectRatio: "16:9", generateAudio: false, mode: "pro" },
1622
- usage: { unit: "compute_seconds", modality: "VIDEO" },
1581
+ usage: { unit: "compute_seconds" },
1623
1582
  pricingKind: "video_per_second",
1624
1583
  display: {
1625
1584
  provider: "kuaishou",
1585
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1626
1586
  description: "Kuaishou Kling Video 3.0 Omni unified generation and editing from text, start/end images, up to 7 reference images, and reference video; up to 15 seconds at up to 1080p."
1627
1587
  },
1628
1588
  capabilities: {}
@@ -1652,6 +1612,7 @@ var VIDEO_MODELS = [
1652
1612
  pricingKind: "video_per_second",
1653
1613
  display: {
1654
1614
  provider: "minimax",
1615
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1655
1616
  description: "MiniMax H3 multimodal video model for text-to-video, image-to-video (first/last frame), and reference-to-video with native audio, up to 2K."
1656
1617
  },
1657
1618
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
@@ -1681,6 +1642,7 @@ var VIDEO_MODELS = [
1681
1642
  pricingKind: "video_per_second",
1682
1643
  display: {
1683
1644
  provider: "minimax",
1645
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1684
1646
  description: "High-speed MiniMax H3 Max variant for text-to-video and image-to-video (first/last frame) only, up to 768p."
1685
1647
  },
1686
1648
  capabilities: { ...FRAMES_EXCLUDE_REFERENCES }
@@ -1711,6 +1673,7 @@ var VIDEO_MODELS = [
1711
1673
  pricingKind: "video_per_second",
1712
1674
  display: {
1713
1675
  provider: "minimax",
1676
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1714
1677
  description: "MiniMax H3 reference-to-video mode guided by up to 9 reference images, 3 reference videos, and 3 audio clips; reference and image-to-video inputs cannot be mixed."
1715
1678
  },
1716
1679
  capabilities: {}
@@ -1741,6 +1704,7 @@ var VIDEO_MODELS = [
1741
1704
  pricingKind: "video_per_second",
1742
1705
  display: {
1743
1706
  provider: "minimax",
1707
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1744
1708
  description: "MiniMax H3 Max reference-to-video on fal; conditions on reference images, videos, and audio. MiniMax's own docs do not list a reference mode for H3 Max."
1745
1709
  },
1746
1710
  capabilities: {}
@@ -1766,6 +1730,7 @@ var VIDEO_MODELS = [
1766
1730
  pricingKind: "video_per_second",
1767
1731
  display: {
1768
1732
  provider: "kuaishou",
1733
+ logo: "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/kling-color.png",
1769
1734
  description: "Kuaishou Kling O1 Reference Video-to-Video; a prompt plus a 3-10 second reference video (optional reference images) generates 3-10 second clips preserving motion and camera language."
1770
1735
  },
1771
1736
  capabilities: { acceptsSourceVideo: true }
@@ -1785,10 +1750,11 @@ var VIDEO_MODELS = [
1785
1750
  supports: ["lastFrame"]
1786
1751
  },
1787
1752
  defaults: { durationSeconds: 6, resolution: "768p" },
1788
- usage: { unit: "compute_seconds", modality: "VIDEO" },
1753
+ usage: { unit: "compute_seconds" },
1789
1754
  pricingKind: "video_per_second",
1790
1755
  display: {
1791
1756
  provider: "minimax",
1757
+ logo: "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/f4c2e906-28b7-4a4a-b491-df8fef7808ed.png",
1792
1758
  description: "MiniMax Hailuo 02 text-to-video and image-to-video model with realistic physics and strong prompt following; outputs 768p at 6 or 10 seconds."
1793
1759
  },
1794
1760
  capabilities: {}
@@ -1825,6 +1791,387 @@ var MODELS = [
1825
1791
  ...OTHER_MODELS
1826
1792
  ];
1827
1793
 
1794
+ // src/catalog/schema.ts
1795
+ import { z } from "zod";
1796
+ var ADAPTER_IDS = [
1797
+ "ai-sdk-text",
1798
+ "google-image",
1799
+ "openai-image",
1800
+ "google-genai",
1801
+ "ark",
1802
+ "fal",
1803
+ "replicate",
1804
+ "prodia",
1805
+ "higgsfield",
1806
+ "xai-video"
1807
+ ];
1808
+ var ModelTypeSchema = z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
1809
+ var LifecycleSchema = z.enum(["active", "deprecated", "retired"]);
1810
+ var AdapterSchema = z.enum(ADAPTER_IDS);
1811
+ var AspectRatioSchema = z.enum([
1812
+ "1:1",
1813
+ "16:9",
1814
+ "9:16",
1815
+ "4:3",
1816
+ "3:4",
1817
+ "3:2",
1818
+ "2:3",
1819
+ "4:5",
1820
+ "5:4",
1821
+ "21:9",
1822
+ "9:21",
1823
+ "97:30",
1824
+ "adaptive"
1825
+ ]);
1826
+ var ImageSizeSchema = z.enum(["512", "1K", "2K", "4K"]);
1827
+ var VideoResolutionSchema = z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
1828
+ var ImageQualitySchema = z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
1829
+ var OutputFormatSchema = z.enum(["png", "jpeg", "webp"]);
1830
+ var RequiredInputSchema = z.enum(["firstFrame", "sourceVideo", "references"]);
1831
+ var SupportedOptionSchema = z.enum([
1832
+ "seed",
1833
+ "quality",
1834
+ "negativePrompt",
1835
+ "cfgScale",
1836
+ "generateAudio",
1837
+ "promptExpansion",
1838
+ "lastFrame",
1839
+ "count",
1840
+ "outputFormat",
1841
+ "scaleFactor",
1842
+ "safetySettings",
1843
+ "temperature",
1844
+ "upscale",
1845
+ "watermark",
1846
+ "safetyChecker",
1847
+ "instrumental"
1848
+ ]);
1849
+ var UsageUnitSchema = z.enum([
1850
+ "tokens",
1851
+ "images",
1852
+ "seconds",
1853
+ "reported_cost_usd",
1854
+ "compute_seconds"
1855
+ ]);
1856
+ var PricingKindSchema = z.enum(["token", "image_size", "video_per_second", "flat"]);
1857
+ var ProviderOptionValueSchema = z.lazy(
1858
+ () => z.union([
1859
+ z.string(),
1860
+ z.number(),
1861
+ z.boolean(),
1862
+ z.array(ProviderOptionValueSchema),
1863
+ z.record(z.string(), ProviderOptionValueSchema)
1864
+ ])
1865
+ );
1866
+ var ProviderOptionsSchema = z.record(z.string(), z.record(z.string(), ProviderOptionValueSchema));
1867
+ var ReferenceLimitsSchema = z.looseObject({
1868
+ images: z.number().optional(),
1869
+ videos: z.number().optional(),
1870
+ audios: z.number().optional(),
1871
+ total: z.number().optional(),
1872
+ audioOnly: z.boolean().optional()
1873
+ });
1874
+ var ModelConstraintsSchema = z.looseObject({
1875
+ aspectRatios: z.array(AspectRatioSchema).optional(),
1876
+ sizes: z.array(ImageSizeSchema).optional(),
1877
+ resolutions: z.array(VideoResolutionSchema).optional(),
1878
+ durations: z.union([z.looseObject({ min: z.number(), max: z.number() }), z.array(z.number())]).optional(),
1879
+ durationPresets: z.array(z.number()).optional(),
1880
+ qualityOptions: z.array(z.string()).optional(),
1881
+ exactSizes: z.record(z.string(), z.string()).optional(),
1882
+ references: ReferenceLimitsSchema.optional(),
1883
+ requires: z.array(RequiredInputSchema).optional(),
1884
+ supports: z.array(SupportedOptionSchema).optional(),
1885
+ ratioIgnoredWith: z.array(z.enum(["firstFrame", "sourceVideo"])).optional()
1886
+ });
1887
+ var MediaRefSchema = z.union([
1888
+ z.looseObject({ url: z.string(), label: z.string().optional() }),
1889
+ z.looseObject({
1890
+ bytes: z.instanceof(Uint8Array),
1891
+ mime: z.string(),
1892
+ label: z.string().optional()
1893
+ })
1894
+ ]);
1895
+ var ImageSafetySettingSchema = z.looseObject({ category: z.string(), threshold: z.string() });
1896
+ var UpscaleOptionsSchema = z.looseObject({
1897
+ enhanceModel: z.string().optional(),
1898
+ subjectDetection: z.string().optional(),
1899
+ faceEnhancement: z.boolean().optional(),
1900
+ faceEnhancementCreativity: z.number().optional(),
1901
+ faceEnhancementStrength: z.number().optional()
1902
+ });
1903
+ var DefaultsSchema = z.looseObject({
1904
+ references: z.array(MediaRefSchema).optional(),
1905
+ aspectRatio: AspectRatioSchema.optional(),
1906
+ size: ImageSizeSchema.optional(),
1907
+ exactSize: z.string().optional(),
1908
+ quality: ImageQualitySchema.optional(),
1909
+ seed: z.number().optional(),
1910
+ count: z.number().optional(),
1911
+ outputFormat: OutputFormatSchema.optional(),
1912
+ scaleFactor: z.number().optional(),
1913
+ safetySettings: z.array(ImageSafetySettingSchema).optional(),
1914
+ temperature: z.number().optional(),
1915
+ upscale: UpscaleOptionsSchema.optional(),
1916
+ firstFrame: MediaRefSchema.optional(),
1917
+ lastFrame: MediaRefSchema.optional(),
1918
+ sourceVideo: MediaRefSchema.optional(),
1919
+ referenceImages: z.array(MediaRefSchema).optional(),
1920
+ referenceVideos: z.array(MediaRefSchema).optional(),
1921
+ referenceAudios: z.array(MediaRefSchema).optional(),
1922
+ resolution: VideoResolutionSchema.optional(),
1923
+ durationSeconds: z.number().optional(),
1924
+ generateAudio: z.boolean().optional(),
1925
+ negativePrompt: z.string().optional(),
1926
+ cfgScale: z.number().optional(),
1927
+ promptExpansion: z.enum(["fast", "balanced", "quality"]).optional(),
1928
+ watermark: z.boolean().optional(),
1929
+ safetyChecker: z.boolean().optional(),
1930
+ mode: z.enum(["standard", "pro"]).optional(),
1931
+ instrumental: z.boolean().optional()
1932
+ });
1933
+ var CatalogDisplaySchema = z.looseObject({
1934
+ provider: z.string(),
1935
+ description: z.string(),
1936
+ logo: z.string().optional(),
1937
+ costTier: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(),
1938
+ recommended: z.boolean().optional(),
1939
+ sortOrder: z.number().optional(),
1940
+ chat: z.looseObject({
1941
+ providerOptions: ProviderOptionsSchema.optional(),
1942
+ temperature: z.number().optional()
1943
+ }).optional()
1944
+ });
1945
+ var CatalogCapabilitiesSchema = z.looseObject({
1946
+ acceptsSourceVideo: z.boolean().optional(),
1947
+ framesExcludeReferences: z.boolean().optional(),
1948
+ reasoning: z.boolean().optional(),
1949
+ vision: z.boolean().optional(),
1950
+ contextWindow: z.number().optional()
1951
+ });
1952
+ var CatalogModelSchemaBase = z.looseObject({
1953
+ id: z.string().min(1),
1954
+ aliases: z.array(z.string()).default([]),
1955
+ label: z.string().min(1),
1956
+ type: ModelTypeSchema,
1957
+ adapter: AdapterSchema,
1958
+ providerModelId: z.string().min(1),
1959
+ lifecycle: LifecycleSchema,
1960
+ replacedBy: z.string().optional(),
1961
+ exposure: z.enum(["catalog", "internal"]),
1962
+ constraints: ModelConstraintsSchema,
1963
+ defaults: DefaultsSchema,
1964
+ providerOptions: ProviderOptionsSchema.optional(),
1965
+ usage: z.looseObject({
1966
+ unit: UsageUnitSchema,
1967
+ slug: z.string().optional(),
1968
+ providerLabel: z.string().optional()
1969
+ }),
1970
+ pricingKind: PricingKindSchema,
1971
+ display: CatalogDisplaySchema.optional(),
1972
+ capabilities: CatalogCapabilitiesSchema.optional()
1973
+ }).superRefine((row, ctx) => {
1974
+ if (row.lifecycle === "active" && !row.display) {
1975
+ ctx.addIssue({
1976
+ code: "custom",
1977
+ path: ["display"],
1978
+ message: "active rows need display"
1979
+ });
1980
+ }
1981
+ if (row.lifecycle === "active" && row.type === "text" && !row.capabilities?.contextWindow) {
1982
+ ctx.addIssue({
1983
+ code: "custom",
1984
+ path: ["capabilities", "contextWindow"],
1985
+ message: "active text rows need contextWindow"
1986
+ });
1987
+ }
1988
+ if (row.replacedBy !== void 0 && row.replacedBy === row.id) {
1989
+ ctx.addIssue({
1990
+ code: "custom",
1991
+ path: ["replacedBy"],
1992
+ message: "replacedBy must not equal id"
1993
+ });
1994
+ }
1995
+ });
1996
+ var CatalogModelSchema = CatalogModelSchemaBase;
1997
+ var CatalogSchema = z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
1998
+ const seenIds = /* @__PURE__ */ new Map();
1999
+ rows.forEach((row, index) => {
2000
+ if (seenIds.has(row.id)) {
2001
+ ctx.addIssue({
2002
+ code: "custom",
2003
+ path: [index, "id"],
2004
+ message: `Duplicate model id "${row.id}"`
2005
+ });
2006
+ } else {
2007
+ seenIds.set(row.id, index);
2008
+ }
2009
+ });
2010
+ const seenAliases = /* @__PURE__ */ new Map();
2011
+ rows.forEach((row, index) => {
2012
+ row.aliases.forEach((alias, aliasIndex) => {
2013
+ const path = [index, "aliases", aliasIndex];
2014
+ if (alias === row.id || seenIds.has(alias)) {
2015
+ ctx.addIssue({
2016
+ code: "custom",
2017
+ path,
2018
+ message: `Alias "${alias}" collides with a model id`
2019
+ });
2020
+ return;
2021
+ }
2022
+ if (seenAliases.has(alias)) {
2023
+ ctx.addIssue({
2024
+ code: "custom",
2025
+ path,
2026
+ message: `Duplicate alias "${alias}"`
2027
+ });
2028
+ } else {
2029
+ seenAliases.set(alias, index);
2030
+ }
2031
+ });
2032
+ });
2033
+ });
2034
+
2035
+ // src/catalog/live.ts
2036
+ var liveCatalog = new Catalog(MODELS);
2037
+
2038
+ // src/catalog/load.ts
2039
+ var memo;
2040
+ var timer;
2041
+ var revision;
2042
+ var origin = "snapshot";
2043
+ function rowCount() {
2044
+ return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2045
+ }
2046
+ function authHeaders(auth) {
2047
+ return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2048
+ }
2049
+ function describeError(err) {
2050
+ return err instanceof Error ? err.message : String(err);
2051
+ }
2052
+ function parseEnvelope(json) {
2053
+ if (typeof json !== "object" || json === null || !("rows" in json)) {
2054
+ throw new Error("invalid catalog response: missing rows");
2055
+ }
2056
+ const rows = CatalogSchema.parse(json.rows);
2057
+ const rev = json.revision;
2058
+ if (typeof rev === "string") return { rows, revision: rev };
2059
+ return { rows };
2060
+ }
2061
+ function logPrimed(logger, result) {
2062
+ const { origin: loggedOrigin, rowCount: loggedCount, revision: loggedRevision } = result;
2063
+ logger.info("[modelkit] catalog primed", {
2064
+ origin: loggedOrigin,
2065
+ rowCount: loggedCount,
2066
+ revision: loggedRevision
2067
+ });
2068
+ }
2069
+ async function fetchRemote(source, logger) {
2070
+ const fetchImpl = source.fetch ?? globalThis.fetch;
2071
+ const headers = authHeaders(source.auth);
2072
+ if (revision !== void 0) headers["If-None-Match"] = `"${revision}"`;
2073
+ const res = await fetchImpl(`${source.baseUrl}/models/catalog`, {
2074
+ headers,
2075
+ signal: AbortSignal.timeout(source.timeoutMs ?? 1e4)
2076
+ });
2077
+ if (res.status === 304) return { kept: true };
2078
+ if (!res.ok) throw new Error(`catalog fetch failed with status ${res.status}`);
2079
+ const json = await res.json();
2080
+ const { rows, revision: rev } = parseEnvelope(json);
2081
+ if (rev === void 0) return { rows, fromCache: false };
2082
+ return { rows, revision: rev, fromCache: false };
2083
+ }
2084
+ async function writeCache(source, logger, rows, rev) {
2085
+ if (!source.cache) return;
2086
+ try {
2087
+ await source.cache.set(JSON.stringify({ rows, revision: rev }));
2088
+ } catch (err) {
2089
+ logger.warn("[modelkit] catalog cache write failed", err);
2090
+ }
2091
+ }
2092
+ async function prime(source, logger) {
2093
+ try {
2094
+ const fetched = await fetchRemote(source, logger);
2095
+ if ("kept" in fetched) {
2096
+ const result2 = { origin, rowCount: rowCount() };
2097
+ if (revision !== void 0) result2.revision = revision;
2098
+ logPrimed(logger, result2);
2099
+ return result2;
2100
+ }
2101
+ liveCatalog.replace(fetched.rows);
2102
+ origin = "remote";
2103
+ revision = fetched.revision;
2104
+ await writeCache(source, logger, fetched.rows, fetched.revision);
2105
+ const result = { origin, rowCount: rowCount() };
2106
+ if (fetched.revision !== void 0) result.revision = fetched.revision;
2107
+ logPrimed(logger, result);
2108
+ return result;
2109
+ } catch (err) {
2110
+ logger.warn("[modelkit] catalog remote failed, trying cache", err);
2111
+ const error = describeError(err);
2112
+ try {
2113
+ const cached = await source.cache?.get();
2114
+ if (!cached) throw new Error("no cached catalog");
2115
+ const { rows, revision: rev } = parseEnvelope(JSON.parse(cached));
2116
+ liveCatalog.replace(rows);
2117
+ origin = "last-good";
2118
+ revision = rev;
2119
+ const result = { origin, rowCount: rowCount(), error };
2120
+ if (rev !== void 0) result.revision = rev;
2121
+ logPrimed(logger, result);
2122
+ return result;
2123
+ } catch (cacheErr) {
2124
+ logger.warn("[modelkit] catalog cache failed, using snapshot", cacheErr);
2125
+ liveCatalog.replace([...MODELS]);
2126
+ origin = "snapshot";
2127
+ revision = void 0;
2128
+ const result = {
2129
+ origin,
2130
+ rowCount: rowCount(),
2131
+ error
2132
+ };
2133
+ logPrimed(logger, result);
2134
+ return result;
2135
+ }
2136
+ }
2137
+ }
2138
+ async function refresh(source, logger) {
2139
+ try {
2140
+ const fetched = await fetchRemote(source, logger);
2141
+ if ("kept" in fetched) return;
2142
+ liveCatalog.replace(fetched.rows);
2143
+ origin = "remote";
2144
+ revision = fetched.revision;
2145
+ await writeCache(source, logger, fetched.rows, fetched.revision);
2146
+ } catch (err) {
2147
+ logger.warn("[modelkit] catalog refresh failed, keeping current rows", err);
2148
+ }
2149
+ }
2150
+ function primeCatalog(source) {
2151
+ if (memo) return memo;
2152
+ const logger = source.logger ?? console;
2153
+ memo = prime(source, logger).then((result) => {
2154
+ const ttlMs = source.ttlMs ?? 3e5;
2155
+ if (ttlMs > 0 && timer === void 0) {
2156
+ timer = setInterval(() => void refresh(source, logger), ttlMs);
2157
+ const maybeUnref = timer;
2158
+ maybeUnref.unref?.();
2159
+ }
2160
+ return result;
2161
+ });
2162
+ return memo;
2163
+ }
2164
+ function resetLiveCatalog() {
2165
+ if (timer !== void 0) {
2166
+ clearInterval(timer);
2167
+ timer = void 0;
2168
+ }
2169
+ memo = void 0;
2170
+ revision = void 0;
2171
+ origin = "snapshot";
2172
+ liveCatalog.replace([...MODELS]);
2173
+ }
2174
+
1828
2175
  // src/resolve-options.ts
1829
2176
  var SIZE_ORDER = ["512", "1K", "2K", "4K"];
1830
2177
  var RESOLUTION_ORDER = ["360p", "480p", "720p", "768p", "1080p", "2k", "4k"];
@@ -2207,7 +2554,10 @@ function resolveOptions(model, request, onUnsupported = "error") {
2207
2554
  }
2208
2555
  }
2209
2556
  export {
2557
+ ADAPTER_IDS,
2210
2558
  Catalog,
2559
+ CatalogModelSchema,
2560
+ CatalogSchema,
2211
2561
  IMAGE_MODELS,
2212
2562
  MODELS,
2213
2563
  ModelKitError,
@@ -2215,7 +2565,10 @@ export {
2215
2565
  TEXT_MODELS,
2216
2566
  VIDEO_MODELS,
2217
2567
  isModelKitError,
2568
+ liveCatalog,
2218
2569
  nearestAspectRatio,
2570
+ primeCatalog,
2571
+ resetLiveCatalog,
2219
2572
  resolveAudioOptions,
2220
2573
  resolveImageOptions,
2221
2574
  resolveOptions,