@shop-os/modelkit 0.2.11 → 0.2.13

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.cjs CHANGED
@@ -23,6 +23,7 @@ __export(catalog_entry_exports, {
23
23
  ADAPTER_IDS: () => ADAPTER_IDS,
24
24
  Catalog: () => Catalog,
25
25
  CatalogModelSchema: () => CatalogModelSchema,
26
+ CatalogModelSchemaBase: () => CatalogModelSchemaBase,
26
27
  CatalogSchema: () => CatalogSchema,
27
28
  ExposureSchema: () => ExposureSchema,
28
29
  IMAGE_MODELS: () => IMAGE_MODELS,
@@ -1877,7 +1878,215 @@ var MODELS = [
1877
1878
  ];
1878
1879
 
1879
1880
  // src/catalog/schema.ts
1881
+ var import_zod2 = require("zod");
1882
+
1883
+ // src/catalog/collisions.ts
1884
+ function collisionIssues(rows) {
1885
+ const issues = [];
1886
+ const seenIds = /* @__PURE__ */ new Map();
1887
+ const seenAliases = /* @__PURE__ */ new Map();
1888
+ rows.forEach((row, index) => {
1889
+ if (seenIds.has(row.id)) {
1890
+ issues.push({
1891
+ index,
1892
+ path: ["id"],
1893
+ message: `Duplicate model id "${row.id}"`
1894
+ });
1895
+ } else {
1896
+ const aliasOwner = seenAliases.get(row.id);
1897
+ if (aliasOwner !== void 0) {
1898
+ issues.push({
1899
+ index: aliasOwner.index,
1900
+ path: ["aliases", aliasOwner.aliasIndex],
1901
+ message: `Alias "${row.id}" collides with a model id`
1902
+ });
1903
+ }
1904
+ seenIds.set(row.id, index);
1905
+ }
1906
+ const local = /* @__PURE__ */ new Set();
1907
+ for (const [aliasIndex, alias] of row.aliases.entries()) {
1908
+ if (alias === row.id || seenIds.has(alias)) {
1909
+ issues.push({
1910
+ index,
1911
+ path: ["aliases", aliasIndex],
1912
+ message: `Alias "${alias}" collides with a model id`
1913
+ });
1914
+ } else if (local.has(alias) || seenAliases.has(alias)) {
1915
+ issues.push({
1916
+ index,
1917
+ path: ["aliases", aliasIndex],
1918
+ message: `Duplicate alias "${alias}"`
1919
+ });
1920
+ }
1921
+ local.add(alias);
1922
+ if (!seenAliases.has(alias)) seenAliases.set(alias, { index, aliasIndex });
1923
+ }
1924
+ });
1925
+ return issues;
1926
+ }
1927
+
1928
+ // src/catalog/input-spec.ts
1880
1929
  var import_zod = require("zod");
1930
+ var VIDEO_INPUT_SPEC_KEYS = [
1931
+ "prompt",
1932
+ "durationSeconds",
1933
+ "aspectRatio",
1934
+ "resolution",
1935
+ "firstFrame",
1936
+ "lastFrame",
1937
+ "seed",
1938
+ "negativePrompt",
1939
+ "generateAudio",
1940
+ "cfgScale",
1941
+ "promptExpansion",
1942
+ "referenceImages"
1943
+ ];
1944
+ var AUDIO_INPUT_SPEC_KEYS = [
1945
+ "prompt",
1946
+ "durationSeconds",
1947
+ "seed",
1948
+ "negativePrompt",
1949
+ "references",
1950
+ "sourceVideo",
1951
+ "instrumental"
1952
+ ];
1953
+ var INPUT_SPEC_SUPPORTS_KEYS = [
1954
+ "lastFrame",
1955
+ "seed",
1956
+ "negativePrompt",
1957
+ "generateAudio",
1958
+ "cfgScale",
1959
+ "promptExpansion",
1960
+ "instrumental"
1961
+ ];
1962
+ var VIDEO_KEY_SET = new Set(VIDEO_INPUT_SPEC_KEYS);
1963
+ var AUDIO_KEY_SET = new Set(AUDIO_INPUT_SPEC_KEYS);
1964
+ var ALL_KEY_SET = /* @__PURE__ */ new Set([
1965
+ ...VIDEO_INPUT_SPEC_KEYS,
1966
+ ...AUDIO_INPUT_SPEC_KEYS
1967
+ ]);
1968
+ var ProviderScalarSchema = import_zod.z.union([import_zod.z.string(), import_zod.z.number(), import_zod.z.boolean()]);
1969
+ var FieldsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.string().min(1)).superRefine((fields, ctx) => {
1970
+ const keys = Object.keys(fields);
1971
+ if (keys.length === 0) {
1972
+ ctx.addIssue({
1973
+ code: "custom",
1974
+ message: "inputSpec.fields must name at least one field"
1975
+ });
1976
+ return;
1977
+ }
1978
+ for (const key of keys) {
1979
+ if (!ALL_KEY_SET.has(key)) {
1980
+ ctx.addIssue({
1981
+ code: "custom",
1982
+ message: `inputSpec.fields has unknown canonical key "${key}"`
1983
+ });
1984
+ }
1985
+ }
1986
+ });
1987
+ var ValuesSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
1988
+ for (const key of Object.keys(values)) {
1989
+ if (!ALL_KEY_SET.has(key)) {
1990
+ ctx.addIssue({
1991
+ code: "custom",
1992
+ message: `inputSpec.values has unknown canonical key "${key}"`
1993
+ });
1994
+ }
1995
+ }
1996
+ });
1997
+ var StaticSchema = import_zod.z.record(import_zod.z.string(), ProviderScalarSchema);
1998
+ var InputSpecSchema = import_zod.z.strictObject({
1999
+ fields: FieldsSchema,
2000
+ values: ValuesSchema.optional(),
2001
+ static: StaticSchema.optional()
2002
+ }).superRefine((spec, ctx) => {
2003
+ const mappedNames = new Set(Object.values(spec.fields));
2004
+ for (const key of Object.keys(spec.static ?? {})) {
2005
+ if (mappedNames.has(key)) {
2006
+ ctx.addIssue({
2007
+ code: "custom",
2008
+ path: ["static", key],
2009
+ message: `inputSpec.static "${key}" collides with a mapped field name`
2010
+ });
2011
+ }
2012
+ }
2013
+ });
2014
+ function validateInputSpec(raw, row) {
2015
+ const parsed = InputSpecSchema.safeParse(raw);
2016
+ if (!parsed.success) {
2017
+ return {
2018
+ ok: false,
2019
+ issues: parsed.error.issues.map((issue) => ({
2020
+ path: issue.path,
2021
+ message: issue.message
2022
+ }))
2023
+ };
2024
+ }
2025
+ const spec = parsed.data;
2026
+ if (row.adapter !== "replicate") {
2027
+ return {
2028
+ ok: false,
2029
+ issues: [{ path: [], message: "inputSpec is only supported on replicate rows" }]
2030
+ };
2031
+ }
2032
+ const issues = [];
2033
+ if (row.type !== "video" && row.type !== "audio") {
2034
+ issues.push({
2035
+ path: [],
2036
+ message: `inputSpec is not supported for "${row.type}" rows`
2037
+ });
2038
+ } else {
2039
+ const allowed = row.type === "video" ? VIDEO_KEY_SET : AUDIO_KEY_SET;
2040
+ for (const key of Object.keys(spec.fields)) {
2041
+ if (!allowed.has(key)) {
2042
+ issues.push({
2043
+ path: ["fields", key],
2044
+ message: `inputSpec.fields "${key}" is not supported for ${row.type} rows`
2045
+ });
2046
+ }
2047
+ }
2048
+ for (const key of Object.keys(spec.values ?? {})) {
2049
+ if (!allowed.has(key)) {
2050
+ issues.push({
2051
+ path: ["values", key],
2052
+ message: `inputSpec.values "${key}" is not supported for ${row.type} rows`
2053
+ });
2054
+ }
2055
+ }
2056
+ }
2057
+ const seenNames = /* @__PURE__ */ new Map();
2058
+ for (const [key, name] of Object.entries(spec.fields)) {
2059
+ const first = seenNames.get(name);
2060
+ if (first === void 0) seenNames.set(name, key);
2061
+ else {
2062
+ issues.push({
2063
+ path: ["fields", key],
2064
+ message: `inputSpec.fields "${first}" and "${key}" both map to "${name}"`
2065
+ });
2066
+ }
2067
+ }
2068
+ for (const key of Object.keys(spec.values ?? {})) {
2069
+ if (!(key in spec.fields)) {
2070
+ issues.push({
2071
+ path: ["values", key],
2072
+ message: `inputSpec.values "${key}" has no matching fields entry`
2073
+ });
2074
+ }
2075
+ }
2076
+ const supports = row.constraints.supports ?? [];
2077
+ for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
2078
+ if (key in spec.fields && !supports.includes(key)) {
2079
+ issues.push({
2080
+ path: ["fields", key],
2081
+ message: `inputSpec.fields "${key}" needs "${key}" in constraints.supports`
2082
+ });
2083
+ }
2084
+ }
2085
+ if (issues.length > 0) return { ok: false, issues };
2086
+ return { ok: true, spec };
2087
+ }
2088
+
2089
+ // src/catalog/schema.ts
1881
2090
  var ADAPTER_IDS = [
1882
2091
  "ai-sdk-text",
1883
2092
  "google-image",
@@ -1890,16 +2099,16 @@ var ADAPTER_IDS = [
1890
2099
  "higgsfield",
1891
2100
  "xai-video"
1892
2101
  ];
1893
- var ModelTypeSchema = import_zod.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
1894
- var LifecycleSchema = import_zod.z.enum(["active", "deprecated", "retired"]);
1895
- var SurfaceSchema = import_zod.z.enum(["cowork", "space_builder"]);
2102
+ var ModelTypeSchema = import_zod2.z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2103
+ var LifecycleSchema = import_zod2.z.enum(["active", "deprecated", "retired"]);
2104
+ var SurfaceSchema = import_zod2.z.enum(["cowork", "space_builder"]);
1896
2105
  var SURFACES2 = SurfaceSchema.options;
1897
- var ExposureSchema = import_zod.z.preprocess(
2106
+ var ExposureSchema = import_zod2.z.preprocess(
1898
2107
  normalizeExposure,
1899
- import_zod.z.array(SurfaceSchema)
2108
+ import_zod2.z.array(SurfaceSchema)
1900
2109
  );
1901
- var AdapterSchema = import_zod.z.enum(ADAPTER_IDS);
1902
- var AspectRatioSchema = import_zod.z.enum([
2110
+ var AdapterSchema = import_zod2.z.enum(ADAPTER_IDS);
2111
+ var AspectRatioSchema = import_zod2.z.enum([
1903
2112
  "1:1",
1904
2113
  "16:9",
1905
2114
  "9:16",
@@ -1914,12 +2123,12 @@ var AspectRatioSchema = import_zod.z.enum([
1914
2123
  "97:30",
1915
2124
  "adaptive"
1916
2125
  ]);
1917
- var ImageSizeSchema = import_zod.z.enum(["512", "1K", "2K", "4K"]);
1918
- var VideoResolutionSchema = import_zod.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
1919
- var ImageQualitySchema = import_zod.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
1920
- var OutputFormatSchema = import_zod.z.enum(["png", "jpeg", "webp"]);
1921
- var RequiredInputSchema = import_zod.z.enum(["firstFrame", "sourceVideo", "references"]);
1922
- var SupportedOptionSchema = import_zod.z.enum([
2126
+ var ImageSizeSchema = import_zod2.z.enum(["512", "1K", "2K", "4K"]);
2127
+ var VideoResolutionSchema = import_zod2.z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2128
+ var ImageQualitySchema = import_zod2.z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2129
+ var OutputFormatSchema = import_zod2.z.enum(["png", "jpeg", "webp"]);
2130
+ var RequiredInputSchema = import_zod2.z.enum(["firstFrame", "sourceVideo", "references"]);
2131
+ var SupportedOptionSchema = import_zod2.z.enum([
1923
2132
  "seed",
1924
2133
  "quality",
1925
2134
  "negativePrompt",
@@ -1938,128 +2147,128 @@ var SupportedOptionSchema = import_zod.z.enum([
1938
2147
  "taskType",
1939
2148
  "instrumental"
1940
2149
  ]);
1941
- var UsageUnitSchema = import_zod.z.enum([
2150
+ var UsageUnitSchema = import_zod2.z.enum([
1942
2151
  "tokens",
1943
2152
  "images",
1944
2153
  "seconds",
1945
2154
  "reported_cost_usd",
1946
2155
  "compute_seconds"
1947
2156
  ]);
1948
- var PricingKindSchema = import_zod.z.enum(["token", "image_size", "video_per_second", "flat"]);
1949
- var ProviderOptionValueSchema = import_zod.z.lazy(
1950
- () => import_zod.z.union([
1951
- import_zod.z.string(),
1952
- import_zod.z.number(),
1953
- import_zod.z.boolean(),
1954
- import_zod.z.array(ProviderOptionValueSchema),
1955
- import_zod.z.record(import_zod.z.string(), ProviderOptionValueSchema)
2157
+ var PricingKindSchema = import_zod2.z.enum(["token", "image_size", "video_per_second", "flat"]);
2158
+ var ProviderOptionValueSchema = import_zod2.z.lazy(
2159
+ () => import_zod2.z.union([
2160
+ import_zod2.z.string(),
2161
+ import_zod2.z.number(),
2162
+ import_zod2.z.boolean(),
2163
+ import_zod2.z.array(ProviderOptionValueSchema),
2164
+ import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema)
1956
2165
  ])
1957
2166
  );
1958
- var ProviderOptionsSchema = import_zod.z.record(import_zod.z.string(), import_zod.z.record(import_zod.z.string(), ProviderOptionValueSchema));
1959
- var ReferenceLimitsSchema = import_zod.z.looseObject({
1960
- images: import_zod.z.number().optional(),
1961
- imagesWithVideo: import_zod.z.number().optional(),
1962
- videos: import_zod.z.number().optional(),
1963
- audios: import_zod.z.number().optional(),
1964
- total: import_zod.z.number().optional(),
1965
- audioOnly: import_zod.z.boolean().optional()
2167
+ var ProviderOptionsSchema = import_zod2.z.record(import_zod2.z.string(), import_zod2.z.record(import_zod2.z.string(), ProviderOptionValueSchema));
2168
+ var ReferenceLimitsSchema = import_zod2.z.looseObject({
2169
+ images: import_zod2.z.number().optional(),
2170
+ imagesWithVideo: import_zod2.z.number().optional(),
2171
+ videos: import_zod2.z.number().optional(),
2172
+ audios: import_zod2.z.number().optional(),
2173
+ total: import_zod2.z.number().optional(),
2174
+ audioOnly: import_zod2.z.boolean().optional()
1966
2175
  });
1967
- var ModelConstraintsSchema = import_zod.z.looseObject({
1968
- aspectRatios: import_zod.z.array(AspectRatioSchema).optional(),
1969
- sizes: import_zod.z.array(ImageSizeSchema).optional(),
1970
- resolutions: import_zod.z.array(VideoResolutionSchema).optional(),
1971
- durations: import_zod.z.union([import_zod.z.looseObject({ min: import_zod.z.number(), max: import_zod.z.number() }), import_zod.z.array(import_zod.z.number())]).optional(),
1972
- durationPresets: import_zod.z.array(import_zod.z.number()).optional(),
1973
- qualityOptions: import_zod.z.array(import_zod.z.string()).optional(),
1974
- exactSizes: import_zod.z.record(import_zod.z.string(), import_zod.z.string()).optional(),
2176
+ var ModelConstraintsSchema = import_zod2.z.looseObject({
2177
+ aspectRatios: import_zod2.z.array(AspectRatioSchema).optional(),
2178
+ sizes: import_zod2.z.array(ImageSizeSchema).optional(),
2179
+ resolutions: import_zod2.z.array(VideoResolutionSchema).optional(),
2180
+ durations: import_zod2.z.union([import_zod2.z.looseObject({ min: import_zod2.z.number(), max: import_zod2.z.number() }), import_zod2.z.array(import_zod2.z.number())]).optional(),
2181
+ durationPresets: import_zod2.z.array(import_zod2.z.number()).optional(),
2182
+ qualityOptions: import_zod2.z.array(import_zod2.z.string()).optional(),
2183
+ exactSizes: import_zod2.z.record(import_zod2.z.string(), import_zod2.z.string()).optional(),
1975
2184
  references: ReferenceLimitsSchema.optional(),
1976
- requires: import_zod.z.array(RequiredInputSchema).optional(),
1977
- supports: import_zod.z.array(SupportedOptionSchema).optional(),
1978
- ratioIgnoredWith: import_zod.z.array(import_zod.z.enum(["firstFrame", "sourceVideo"])).optional()
2185
+ requires: import_zod2.z.array(RequiredInputSchema).optional(),
2186
+ supports: import_zod2.z.array(SupportedOptionSchema).optional(),
2187
+ ratioIgnoredWith: import_zod2.z.array(import_zod2.z.enum(["firstFrame", "sourceVideo"])).optional()
1979
2188
  });
1980
- var MediaRefSchema = import_zod.z.union([
1981
- import_zod.z.looseObject({ url: import_zod.z.string(), label: import_zod.z.string().optional() }),
1982
- import_zod.z.looseObject({
1983
- bytes: import_zod.z.instanceof(Uint8Array),
1984
- mime: import_zod.z.string(),
1985
- label: import_zod.z.string().optional()
2189
+ var MediaRefSchema = import_zod2.z.union([
2190
+ import_zod2.z.looseObject({ url: import_zod2.z.string(), label: import_zod2.z.string().optional() }),
2191
+ import_zod2.z.looseObject({
2192
+ bytes: import_zod2.z.instanceof(Uint8Array),
2193
+ mime: import_zod2.z.string(),
2194
+ label: import_zod2.z.string().optional()
1986
2195
  })
1987
2196
  ]);
1988
- var ImageSafetySettingSchema = import_zod.z.looseObject({ category: import_zod.z.string(), threshold: import_zod.z.string() });
1989
- var UpscaleOptionsSchema = import_zod.z.looseObject({
1990
- enhanceModel: import_zod.z.string().optional(),
1991
- subjectDetection: import_zod.z.string().optional(),
1992
- faceEnhancement: import_zod.z.boolean().optional(),
1993
- faceEnhancementCreativity: import_zod.z.number().optional(),
1994
- faceEnhancementStrength: import_zod.z.number().optional()
2197
+ var ImageSafetySettingSchema = import_zod2.z.looseObject({ category: import_zod2.z.string(), threshold: import_zod2.z.string() });
2198
+ var UpscaleOptionsSchema = import_zod2.z.looseObject({
2199
+ enhanceModel: import_zod2.z.string().optional(),
2200
+ subjectDetection: import_zod2.z.string().optional(),
2201
+ faceEnhancement: import_zod2.z.boolean().optional(),
2202
+ faceEnhancementCreativity: import_zod2.z.number().optional(),
2203
+ faceEnhancementStrength: import_zod2.z.number().optional()
1995
2204
  });
1996
- var DefaultsSchema = import_zod.z.looseObject({
1997
- references: import_zod.z.array(MediaRefSchema).optional(),
2205
+ var DefaultsSchema = import_zod2.z.looseObject({
2206
+ references: import_zod2.z.array(MediaRefSchema).optional(),
1998
2207
  aspectRatio: AspectRatioSchema.optional(),
1999
2208
  size: ImageSizeSchema.optional(),
2000
- exactSize: import_zod.z.string().optional(),
2209
+ exactSize: import_zod2.z.string().optional(),
2001
2210
  quality: ImageQualitySchema.optional(),
2002
- seed: import_zod.z.number().optional(),
2003
- count: import_zod.z.number().optional(),
2211
+ seed: import_zod2.z.number().optional(),
2212
+ count: import_zod2.z.number().optional(),
2004
2213
  outputFormat: OutputFormatSchema.optional(),
2005
- scaleFactor: import_zod.z.number().optional(),
2006
- safetySettings: import_zod.z.array(ImageSafetySettingSchema).optional(),
2007
- temperature: import_zod.z.number().optional(),
2214
+ scaleFactor: import_zod2.z.number().optional(),
2215
+ safetySettings: import_zod2.z.array(ImageSafetySettingSchema).optional(),
2216
+ temperature: import_zod2.z.number().optional(),
2008
2217
  upscale: UpscaleOptionsSchema.optional(),
2009
2218
  firstFrame: MediaRefSchema.optional(),
2010
2219
  lastFrame: MediaRefSchema.optional(),
2011
2220
  sourceVideo: MediaRefSchema.optional(),
2012
- referenceImages: import_zod.z.array(MediaRefSchema).optional(),
2013
- referenceVideos: import_zod.z.array(MediaRefSchema).optional(),
2014
- referenceAudios: import_zod.z.array(MediaRefSchema).optional(),
2221
+ referenceImages: import_zod2.z.array(MediaRefSchema).optional(),
2222
+ referenceVideos: import_zod2.z.array(MediaRefSchema).optional(),
2223
+ referenceAudios: import_zod2.z.array(MediaRefSchema).optional(),
2015
2224
  resolution: VideoResolutionSchema.optional(),
2016
- durationSeconds: import_zod.z.number().optional(),
2017
- generateAudio: import_zod.z.boolean().optional(),
2018
- negativePrompt: import_zod.z.string().optional(),
2019
- cfgScale: import_zod.z.number().optional(),
2020
- promptExpansion: import_zod.z.enum(["fast", "balanced", "quality"]).optional(),
2021
- watermark: import_zod.z.boolean().optional(),
2022
- safetyChecker: import_zod.z.boolean().optional(),
2023
- taskType: import_zod.z.enum(["reference", "edit", "extend"]).optional(),
2024
- mode: import_zod.z.enum(["standard", "pro"]).optional(),
2025
- instrumental: import_zod.z.boolean().optional()
2225
+ durationSeconds: import_zod2.z.number().optional(),
2226
+ generateAudio: import_zod2.z.boolean().optional(),
2227
+ negativePrompt: import_zod2.z.string().optional(),
2228
+ cfgScale: import_zod2.z.number().optional(),
2229
+ promptExpansion: import_zod2.z.enum(["fast", "balanced", "quality"]).optional(),
2230
+ watermark: import_zod2.z.boolean().optional(),
2231
+ safetyChecker: import_zod2.z.boolean().optional(),
2232
+ taskType: import_zod2.z.enum(["reference", "edit", "extend"]).optional(),
2233
+ mode: import_zod2.z.enum(["standard", "pro"]).optional(),
2234
+ instrumental: import_zod2.z.boolean().optional()
2026
2235
  });
2027
- var CatalogDisplaySchema = import_zod.z.looseObject({
2028
- provider: import_zod.z.string(),
2029
- description: import_zod.z.string(),
2030
- logo: import_zod.z.string().optional(),
2031
- costTier: import_zod.z.union([import_zod.z.literal(1), import_zod.z.literal(2), import_zod.z.literal(3)]).optional(),
2032
- recommended: import_zod.z.boolean().optional(),
2033
- sortOrder: import_zod.z.number().optional(),
2034
- chat: import_zod.z.looseObject({
2236
+ var CatalogDisplaySchema = import_zod2.z.looseObject({
2237
+ provider: import_zod2.z.string(),
2238
+ description: import_zod2.z.string(),
2239
+ logo: import_zod2.z.string().optional(),
2240
+ costTier: import_zod2.z.union([import_zod2.z.literal(1), import_zod2.z.literal(2), import_zod2.z.literal(3)]).optional(),
2241
+ recommended: import_zod2.z.boolean().optional(),
2242
+ sortOrder: import_zod2.z.number().optional(),
2243
+ chat: import_zod2.z.looseObject({
2035
2244
  providerOptions: ProviderOptionsSchema.optional(),
2036
- temperature: import_zod.z.number().optional()
2245
+ temperature: import_zod2.z.number().optional()
2037
2246
  }).optional()
2038
2247
  });
2039
- var CatalogCapabilitiesSchema = import_zod.z.looseObject({
2040
- acceptsSourceVideo: import_zod.z.boolean().optional(),
2041
- framesExcludeReferences: import_zod.z.boolean().optional(),
2042
- reasoning: import_zod.z.boolean().optional(),
2043
- vision: import_zod.z.boolean().optional(),
2044
- contextWindow: import_zod.z.number().optional()
2248
+ var CatalogCapabilitiesSchema = import_zod2.z.looseObject({
2249
+ acceptsSourceVideo: import_zod2.z.boolean().optional(),
2250
+ framesExcludeReferences: import_zod2.z.boolean().optional(),
2251
+ reasoning: import_zod2.z.boolean().optional(),
2252
+ vision: import_zod2.z.boolean().optional(),
2253
+ contextWindow: import_zod2.z.number().optional()
2045
2254
  });
2046
- var CatalogModelSchemaBase = import_zod.z.looseObject({
2047
- id: import_zod.z.string().min(1),
2048
- aliases: import_zod.z.array(import_zod.z.string()).default([]),
2049
- label: import_zod.z.string().min(1),
2255
+ var CatalogModelSchemaBase = import_zod2.z.looseObject({
2256
+ id: import_zod2.z.string().min(1),
2257
+ aliases: import_zod2.z.array(import_zod2.z.string()).default([]),
2258
+ label: import_zod2.z.string().min(1),
2050
2259
  type: ModelTypeSchema,
2051
2260
  adapter: AdapterSchema,
2052
- providerModelId: import_zod.z.string().min(1),
2261
+ providerModelId: import_zod2.z.string().min(1),
2053
2262
  lifecycle: LifecycleSchema,
2054
- replacedBy: import_zod.z.string().optional(),
2263
+ replacedBy: import_zod2.z.string().optional(),
2055
2264
  exposure: ExposureSchema,
2056
2265
  constraints: ModelConstraintsSchema,
2057
2266
  defaults: DefaultsSchema,
2058
2267
  providerOptions: ProviderOptionsSchema.optional(),
2059
- usage: import_zod.z.looseObject({
2268
+ usage: import_zod2.z.looseObject({
2060
2269
  unit: UsageUnitSchema,
2061
- slug: import_zod.z.string().optional(),
2062
- providerLabel: import_zod.z.string().optional()
2270
+ slug: import_zod2.z.string().optional(),
2271
+ providerLabel: import_zod2.z.string().optional()
2063
2272
  }),
2064
2273
  pricingKind: PricingKindSchema,
2065
2274
  display: CatalogDisplaySchema.optional(),
@@ -2097,44 +2306,29 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2097
2306
  message: 'transport must be "direct" or "bedrock"'
2098
2307
  });
2099
2308
  }
2309
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2310
+ if (inputSpecRaw !== void 0) {
2311
+ const result = validateInputSpec(inputSpecRaw, row);
2312
+ if (!result.ok) {
2313
+ for (const issue of result.issues) {
2314
+ ctx.addIssue({
2315
+ code: "custom",
2316
+ path: ["providerOptions", "modelkit", "inputSpec", ...issue.path],
2317
+ message: issue.message
2318
+ });
2319
+ }
2320
+ }
2321
+ }
2100
2322
  }
2101
2323
  );
2102
- var CatalogSchema = import_zod.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2103
- const seenIds = /* @__PURE__ */ new Map();
2104
- rows.forEach((row, index) => {
2105
- if (seenIds.has(row.id)) {
2106
- ctx.addIssue({
2107
- code: "custom",
2108
- path: [index, "id"],
2109
- message: `Duplicate model id "${row.id}"`
2110
- });
2111
- } else {
2112
- seenIds.set(row.id, index);
2113
- }
2114
- });
2115
- const seenAliases = /* @__PURE__ */ new Map();
2116
- rows.forEach((row, index) => {
2117
- row.aliases.forEach((alias, aliasIndex) => {
2118
- const path = [index, "aliases", aliasIndex];
2119
- if (alias === row.id || seenIds.has(alias)) {
2120
- ctx.addIssue({
2121
- code: "custom",
2122
- path,
2123
- message: `Alias "${alias}" collides with a model id`
2124
- });
2125
- return;
2126
- }
2127
- if (seenAliases.has(alias)) {
2128
- ctx.addIssue({
2129
- code: "custom",
2130
- path,
2131
- message: `Duplicate alias "${alias}"`
2132
- });
2133
- } else {
2134
- seenAliases.set(alias, index);
2135
- }
2324
+ var CatalogSchema = import_zod2.z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2325
+ for (const issue of collisionIssues(rows)) {
2326
+ ctx.addIssue({
2327
+ code: "custom",
2328
+ path: [issue.index, ...issue.path],
2329
+ message: issue.message
2136
2330
  });
2137
- });
2331
+ }
2138
2332
  });
2139
2333
 
2140
2334
  // src/catalog/live.ts
@@ -2149,26 +2343,102 @@ var liveState = store[KEY] ??= {
2149
2343
  };
2150
2344
  var liveCatalog = liveState.catalog;
2151
2345
 
2346
+ // src/json.ts
2347
+ var import_zod3 = require("zod");
2348
+ var JsonValueSchema = import_zod3.z.lazy(
2349
+ () => import_zod3.z.union([
2350
+ import_zod3.z.string(),
2351
+ import_zod3.z.number(),
2352
+ import_zod3.z.boolean(),
2353
+ import_zod3.z.null(),
2354
+ import_zod3.z.array(JsonValueSchema),
2355
+ import_zod3.z.record(import_zod3.z.string(), JsonValueSchema)
2356
+ ])
2357
+ );
2358
+ var JsonObjectSchema = import_zod3.z.record(import_zod3.z.string(), JsonValueSchema);
2359
+ var thrownErrorSchema = import_zod3.z.object({
2360
+ message: import_zod3.z.string().optional(),
2361
+ status: import_zod3.z.number().optional(),
2362
+ statusCode: import_zod3.z.number().optional(),
2363
+ responseBody: import_zod3.z.string().optional()
2364
+ });
2365
+
2152
2366
  // src/catalog/load.ts
2153
- var import_zod2 = require("zod");
2367
+ var import_zod4 = require("zod");
2154
2368
  function rowCount() {
2155
2369
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2156
2370
  }
2157
2371
  function authHeaders(auth) {
2158
2372
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2159
2373
  }
2160
- var EnvelopeSchema = import_zod2.z.object({
2161
- rows: CatalogSchema,
2162
- revision: import_zod2.z.string().optional()
2374
+ var EnvelopeSchema = import_zod4.z.object({
2375
+ rows: import_zod4.z.array(JsonValueSchema),
2376
+ revision: import_zod4.z.string().optional()
2163
2377
  });
2164
- function toEnvelope(data) {
2165
- if (data.rows.length === 0) throw new Error("invalid catalog response: no rows");
2166
- const envelope = { rows: data.rows };
2378
+ function dropReason(path, message) {
2379
+ return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
2380
+ }
2381
+ function rowId(raw) {
2382
+ const parsed = import_zod4.z.object({ id: import_zod4.z.string().min(1) }).loose().safeParse(raw);
2383
+ if (!parsed.success) return "?";
2384
+ return parsed.data.id;
2385
+ }
2386
+ function quarantine(rawRows, logger) {
2387
+ const valid = [];
2388
+ let dropped = 0;
2389
+ for (const raw of rawRows) {
2390
+ const parsed = CatalogModelSchemaBase.safeParse(raw);
2391
+ if (!parsed.success) {
2392
+ const first = parsed.error.issues[0];
2393
+ const reason = first ? dropReason(first.path, first.message) : "invalid row";
2394
+ logger.warn(`[modelkit] catalog row dropped id=${rowId(raw)} reason=${reason}`);
2395
+ dropped += 1;
2396
+ continue;
2397
+ }
2398
+ const row = parsed.data;
2399
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2400
+ if (inputSpecRaw !== void 0) {
2401
+ const result = validateInputSpec(inputSpecRaw, row);
2402
+ if (!result.ok) {
2403
+ const first = result.issues[0];
2404
+ const detail = first ? dropReason(first.path, first.message) : "invalid inputSpec";
2405
+ logger.warn(
2406
+ `[modelkit] catalog row ${row.id} has an invalid providerOptions.modelkit.inputSpec: ${detail}; calls fail until it is fixed`
2407
+ );
2408
+ }
2409
+ }
2410
+ valid.push(row);
2411
+ }
2412
+ let kept = valid;
2413
+ for (; ; ) {
2414
+ const issues = collisionIssues(kept);
2415
+ if (issues.length === 0) break;
2416
+ const firstByIndex = /* @__PURE__ */ new Map();
2417
+ for (const issue of issues) {
2418
+ if (!firstByIndex.has(issue.index)) firstByIndex.set(issue.index, issue);
2419
+ }
2420
+ for (const [index, issue] of [...firstByIndex.entries()].sort((a, b) => a[0] - b[0])) {
2421
+ const row = kept[index];
2422
+ if (!row) continue;
2423
+ logger.warn(
2424
+ `[modelkit] catalog row dropped id=${row.id} reason=${String(issue.path[0] ?? "")} ${issue.message}`
2425
+ );
2426
+ }
2427
+ const dropSet = new Set(firstByIndex.keys());
2428
+ kept = kept.filter((_, index) => !dropSet.has(index));
2429
+ dropped += dropSet.size;
2430
+ }
2431
+ return { rows: kept, dropped };
2432
+ }
2433
+ function toEnvelope(data, logger) {
2434
+ const { rows, dropped } = quarantine(data.rows, logger);
2435
+ if (rows.length === 0) throw new Error("invalid catalog response: no rows");
2436
+ const envelope = { rows, dropped };
2167
2437
  if (data.revision !== void 0) envelope.revision = data.revision;
2168
2438
  return envelope;
2169
2439
  }
2170
- function describeError(err) {
2171
- return err instanceof Error ? err.message : String(err);
2440
+ function describeError(cause) {
2441
+ return cause instanceof Error ? cause.message : String(cause);
2172
2442
  }
2173
2443
  function logPrimed(logger, result) {
2174
2444
  const revision = result.revision === void 0 ? "" : ` revision=${result.revision}`;
@@ -2189,9 +2459,9 @@ async function fetchRemote(source, logger) {
2189
2459
  const json = await res.json();
2190
2460
  const parsed = EnvelopeSchema.safeParse(json);
2191
2461
  if (!parsed.success) throw new Error("invalid catalog response: missing rows");
2192
- const { rows, revision: rev } = toEnvelope(parsed.data);
2193
- if (rev === void 0) return { rows, fromCache: false };
2194
- return { rows, revision: rev, fromCache: false };
2462
+ const { rows, revision: rev, dropped } = toEnvelope(parsed.data, logger);
2463
+ if (rev === void 0) return { rows, fromCache: false, dropped };
2464
+ return { rows, revision: rev, fromCache: false, dropped };
2195
2465
  }
2196
2466
  async function writeCache(source, logger, rows, rev) {
2197
2467
  if (!source.cache) return;
@@ -2216,6 +2486,7 @@ async function prime(source, logger) {
2216
2486
  await writeCache(source, logger, fetched.rows, fetched.revision);
2217
2487
  const result = { origin: liveState.origin, rowCount: rowCount() };
2218
2488
  if (fetched.revision !== void 0) result.revision = fetched.revision;
2489
+ if (fetched.dropped > 0) result.droppedRows = fetched.dropped;
2219
2490
  logPrimed(logger, result);
2220
2491
  return result;
2221
2492
  } catch (err) {
@@ -2226,7 +2497,7 @@ async function prime(source, logger) {
2226
2497
  if (!cached) throw new Error("no cached catalog");
2227
2498
  const cachedParsed = EnvelopeSchema.safeParse(JSON.parse(cached));
2228
2499
  if (!cachedParsed.success) throw new Error("invalid catalog response: missing rows");
2229
- const { rows, revision: rev } = toEnvelope(cachedParsed.data);
2500
+ const { rows, revision: rev, dropped } = toEnvelope(cachedParsed.data, logger);
2230
2501
  liveCatalog.replace(rows);
2231
2502
  liveState.origin = "last-good";
2232
2503
  liveState.revision = rev;
@@ -2236,6 +2507,7 @@ async function prime(source, logger) {
2236
2507
  error
2237
2508
  };
2238
2509
  if (rev !== void 0) result.revision = rev;
2510
+ if (dropped > 0) result.droppedRows = dropped;
2239
2511
  logPrimed(logger, result);
2240
2512
  return result;
2241
2513
  } catch (cacheErr) {