@shop-os/modelkit 0.2.12 → 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.js CHANGED
@@ -1824,7 +1824,215 @@ var MODELS = [
1824
1824
  ];
1825
1825
 
1826
1826
  // src/catalog/schema.ts
1827
+ import { z as z2 } from "zod";
1828
+
1829
+ // src/catalog/collisions.ts
1830
+ function collisionIssues(rows) {
1831
+ const issues = [];
1832
+ const seenIds = /* @__PURE__ */ new Map();
1833
+ const seenAliases = /* @__PURE__ */ new Map();
1834
+ rows.forEach((row, index) => {
1835
+ if (seenIds.has(row.id)) {
1836
+ issues.push({
1837
+ index,
1838
+ path: ["id"],
1839
+ message: `Duplicate model id "${row.id}"`
1840
+ });
1841
+ } else {
1842
+ const aliasOwner = seenAliases.get(row.id);
1843
+ if (aliasOwner !== void 0) {
1844
+ issues.push({
1845
+ index: aliasOwner.index,
1846
+ path: ["aliases", aliasOwner.aliasIndex],
1847
+ message: `Alias "${row.id}" collides with a model id`
1848
+ });
1849
+ }
1850
+ seenIds.set(row.id, index);
1851
+ }
1852
+ const local = /* @__PURE__ */ new Set();
1853
+ for (const [aliasIndex, alias] of row.aliases.entries()) {
1854
+ if (alias === row.id || seenIds.has(alias)) {
1855
+ issues.push({
1856
+ index,
1857
+ path: ["aliases", aliasIndex],
1858
+ message: `Alias "${alias}" collides with a model id`
1859
+ });
1860
+ } else if (local.has(alias) || seenAliases.has(alias)) {
1861
+ issues.push({
1862
+ index,
1863
+ path: ["aliases", aliasIndex],
1864
+ message: `Duplicate alias "${alias}"`
1865
+ });
1866
+ }
1867
+ local.add(alias);
1868
+ if (!seenAliases.has(alias)) seenAliases.set(alias, { index, aliasIndex });
1869
+ }
1870
+ });
1871
+ return issues;
1872
+ }
1873
+
1874
+ // src/catalog/input-spec.ts
1827
1875
  import { z } from "zod";
1876
+ var VIDEO_INPUT_SPEC_KEYS = [
1877
+ "prompt",
1878
+ "durationSeconds",
1879
+ "aspectRatio",
1880
+ "resolution",
1881
+ "firstFrame",
1882
+ "lastFrame",
1883
+ "seed",
1884
+ "negativePrompt",
1885
+ "generateAudio",
1886
+ "cfgScale",
1887
+ "promptExpansion",
1888
+ "referenceImages"
1889
+ ];
1890
+ var AUDIO_INPUT_SPEC_KEYS = [
1891
+ "prompt",
1892
+ "durationSeconds",
1893
+ "seed",
1894
+ "negativePrompt",
1895
+ "references",
1896
+ "sourceVideo",
1897
+ "instrumental"
1898
+ ];
1899
+ var INPUT_SPEC_SUPPORTS_KEYS = [
1900
+ "lastFrame",
1901
+ "seed",
1902
+ "negativePrompt",
1903
+ "generateAudio",
1904
+ "cfgScale",
1905
+ "promptExpansion",
1906
+ "instrumental"
1907
+ ];
1908
+ var VIDEO_KEY_SET = new Set(VIDEO_INPUT_SPEC_KEYS);
1909
+ var AUDIO_KEY_SET = new Set(AUDIO_INPUT_SPEC_KEYS);
1910
+ var ALL_KEY_SET = /* @__PURE__ */ new Set([
1911
+ ...VIDEO_INPUT_SPEC_KEYS,
1912
+ ...AUDIO_INPUT_SPEC_KEYS
1913
+ ]);
1914
+ var ProviderScalarSchema = z.union([z.string(), z.number(), z.boolean()]);
1915
+ var FieldsSchema = z.record(z.string(), z.string().min(1)).superRefine((fields, ctx) => {
1916
+ const keys = Object.keys(fields);
1917
+ if (keys.length === 0) {
1918
+ ctx.addIssue({
1919
+ code: "custom",
1920
+ message: "inputSpec.fields must name at least one field"
1921
+ });
1922
+ return;
1923
+ }
1924
+ for (const key of keys) {
1925
+ if (!ALL_KEY_SET.has(key)) {
1926
+ ctx.addIssue({
1927
+ code: "custom",
1928
+ message: `inputSpec.fields has unknown canonical key "${key}"`
1929
+ });
1930
+ }
1931
+ }
1932
+ });
1933
+ var ValuesSchema = z.record(z.string(), z.record(z.string(), ProviderScalarSchema)).superRefine((values, ctx) => {
1934
+ for (const key of Object.keys(values)) {
1935
+ if (!ALL_KEY_SET.has(key)) {
1936
+ ctx.addIssue({
1937
+ code: "custom",
1938
+ message: `inputSpec.values has unknown canonical key "${key}"`
1939
+ });
1940
+ }
1941
+ }
1942
+ });
1943
+ var StaticSchema = z.record(z.string(), ProviderScalarSchema);
1944
+ var InputSpecSchema = z.strictObject({
1945
+ fields: FieldsSchema,
1946
+ values: ValuesSchema.optional(),
1947
+ static: StaticSchema.optional()
1948
+ }).superRefine((spec, ctx) => {
1949
+ const mappedNames = new Set(Object.values(spec.fields));
1950
+ for (const key of Object.keys(spec.static ?? {})) {
1951
+ if (mappedNames.has(key)) {
1952
+ ctx.addIssue({
1953
+ code: "custom",
1954
+ path: ["static", key],
1955
+ message: `inputSpec.static "${key}" collides with a mapped field name`
1956
+ });
1957
+ }
1958
+ }
1959
+ });
1960
+ function validateInputSpec(raw, row) {
1961
+ const parsed = InputSpecSchema.safeParse(raw);
1962
+ if (!parsed.success) {
1963
+ return {
1964
+ ok: false,
1965
+ issues: parsed.error.issues.map((issue) => ({
1966
+ path: issue.path,
1967
+ message: issue.message
1968
+ }))
1969
+ };
1970
+ }
1971
+ const spec = parsed.data;
1972
+ if (row.adapter !== "replicate") {
1973
+ return {
1974
+ ok: false,
1975
+ issues: [{ path: [], message: "inputSpec is only supported on replicate rows" }]
1976
+ };
1977
+ }
1978
+ const issues = [];
1979
+ if (row.type !== "video" && row.type !== "audio") {
1980
+ issues.push({
1981
+ path: [],
1982
+ message: `inputSpec is not supported for "${row.type}" rows`
1983
+ });
1984
+ } else {
1985
+ const allowed = row.type === "video" ? VIDEO_KEY_SET : AUDIO_KEY_SET;
1986
+ for (const key of Object.keys(spec.fields)) {
1987
+ if (!allowed.has(key)) {
1988
+ issues.push({
1989
+ path: ["fields", key],
1990
+ message: `inputSpec.fields "${key}" is not supported for ${row.type} rows`
1991
+ });
1992
+ }
1993
+ }
1994
+ for (const key of Object.keys(spec.values ?? {})) {
1995
+ if (!allowed.has(key)) {
1996
+ issues.push({
1997
+ path: ["values", key],
1998
+ message: `inputSpec.values "${key}" is not supported for ${row.type} rows`
1999
+ });
2000
+ }
2001
+ }
2002
+ }
2003
+ const seenNames = /* @__PURE__ */ new Map();
2004
+ for (const [key, name] of Object.entries(spec.fields)) {
2005
+ const first = seenNames.get(name);
2006
+ if (first === void 0) seenNames.set(name, key);
2007
+ else {
2008
+ issues.push({
2009
+ path: ["fields", key],
2010
+ message: `inputSpec.fields "${first}" and "${key}" both map to "${name}"`
2011
+ });
2012
+ }
2013
+ }
2014
+ for (const key of Object.keys(spec.values ?? {})) {
2015
+ if (!(key in spec.fields)) {
2016
+ issues.push({
2017
+ path: ["values", key],
2018
+ message: `inputSpec.values "${key}" has no matching fields entry`
2019
+ });
2020
+ }
2021
+ }
2022
+ const supports = row.constraints.supports ?? [];
2023
+ for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
2024
+ if (key in spec.fields && !supports.includes(key)) {
2025
+ issues.push({
2026
+ path: ["fields", key],
2027
+ message: `inputSpec.fields "${key}" needs "${key}" in constraints.supports`
2028
+ });
2029
+ }
2030
+ }
2031
+ if (issues.length > 0) return { ok: false, issues };
2032
+ return { ok: true, spec };
2033
+ }
2034
+
2035
+ // src/catalog/schema.ts
1828
2036
  var ADAPTER_IDS = [
1829
2037
  "ai-sdk-text",
1830
2038
  "google-image",
@@ -1837,16 +2045,16 @@ var ADAPTER_IDS = [
1837
2045
  "higgsfield",
1838
2046
  "xai-video"
1839
2047
  ];
1840
- var ModelTypeSchema = z.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
1841
- var LifecycleSchema = z.enum(["active", "deprecated", "retired"]);
1842
- var SurfaceSchema = z.enum(["cowork", "space_builder"]);
2048
+ var ModelTypeSchema = z2.enum(["text", "image", "video", "audio", "upscale", "bg-remove"]);
2049
+ var LifecycleSchema = z2.enum(["active", "deprecated", "retired"]);
2050
+ var SurfaceSchema = z2.enum(["cowork", "space_builder"]);
1843
2051
  var SURFACES2 = SurfaceSchema.options;
1844
- var ExposureSchema = z.preprocess(
2052
+ var ExposureSchema = z2.preprocess(
1845
2053
  normalizeExposure,
1846
- z.array(SurfaceSchema)
2054
+ z2.array(SurfaceSchema)
1847
2055
  );
1848
- var AdapterSchema = z.enum(ADAPTER_IDS);
1849
- var AspectRatioSchema = z.enum([
2056
+ var AdapterSchema = z2.enum(ADAPTER_IDS);
2057
+ var AspectRatioSchema = z2.enum([
1850
2058
  "1:1",
1851
2059
  "16:9",
1852
2060
  "9:16",
@@ -1861,12 +2069,12 @@ var AspectRatioSchema = z.enum([
1861
2069
  "97:30",
1862
2070
  "adaptive"
1863
2071
  ]);
1864
- var ImageSizeSchema = z.enum(["512", "1K", "2K", "4K"]);
1865
- var VideoResolutionSchema = z.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
1866
- var ImageQualitySchema = z.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
1867
- var OutputFormatSchema = z.enum(["png", "jpeg", "webp"]);
1868
- var RequiredInputSchema = z.enum(["firstFrame", "sourceVideo", "references"]);
1869
- var SupportedOptionSchema = z.enum([
2072
+ var ImageSizeSchema = z2.enum(["512", "1K", "2K", "4K"]);
2073
+ var VideoResolutionSchema = z2.enum(["360p", "480p", "720p", "768p", "1080p", "2k", "4k"]);
2074
+ var ImageQualitySchema = z2.enum(["auto", "low", "medium", "high", "xhigh", "max"]);
2075
+ var OutputFormatSchema = z2.enum(["png", "jpeg", "webp"]);
2076
+ var RequiredInputSchema = z2.enum(["firstFrame", "sourceVideo", "references"]);
2077
+ var SupportedOptionSchema = z2.enum([
1870
2078
  "seed",
1871
2079
  "quality",
1872
2080
  "negativePrompt",
@@ -1885,128 +2093,128 @@ var SupportedOptionSchema = z.enum([
1885
2093
  "taskType",
1886
2094
  "instrumental"
1887
2095
  ]);
1888
- var UsageUnitSchema = z.enum([
2096
+ var UsageUnitSchema = z2.enum([
1889
2097
  "tokens",
1890
2098
  "images",
1891
2099
  "seconds",
1892
2100
  "reported_cost_usd",
1893
2101
  "compute_seconds"
1894
2102
  ]);
1895
- var PricingKindSchema = z.enum(["token", "image_size", "video_per_second", "flat"]);
1896
- var ProviderOptionValueSchema = z.lazy(
1897
- () => z.union([
1898
- z.string(),
1899
- z.number(),
1900
- z.boolean(),
1901
- z.array(ProviderOptionValueSchema),
1902
- z.record(z.string(), ProviderOptionValueSchema)
2103
+ var PricingKindSchema = z2.enum(["token", "image_size", "video_per_second", "flat"]);
2104
+ var ProviderOptionValueSchema = z2.lazy(
2105
+ () => z2.union([
2106
+ z2.string(),
2107
+ z2.number(),
2108
+ z2.boolean(),
2109
+ z2.array(ProviderOptionValueSchema),
2110
+ z2.record(z2.string(), ProviderOptionValueSchema)
1903
2111
  ])
1904
2112
  );
1905
- var ProviderOptionsSchema = z.record(z.string(), z.record(z.string(), ProviderOptionValueSchema));
1906
- var ReferenceLimitsSchema = z.looseObject({
1907
- images: z.number().optional(),
1908
- imagesWithVideo: z.number().optional(),
1909
- videos: z.number().optional(),
1910
- audios: z.number().optional(),
1911
- total: z.number().optional(),
1912
- audioOnly: z.boolean().optional()
2113
+ var ProviderOptionsSchema = z2.record(z2.string(), z2.record(z2.string(), ProviderOptionValueSchema));
2114
+ var ReferenceLimitsSchema = z2.looseObject({
2115
+ images: z2.number().optional(),
2116
+ imagesWithVideo: z2.number().optional(),
2117
+ videos: z2.number().optional(),
2118
+ audios: z2.number().optional(),
2119
+ total: z2.number().optional(),
2120
+ audioOnly: z2.boolean().optional()
1913
2121
  });
1914
- var ModelConstraintsSchema = z.looseObject({
1915
- aspectRatios: z.array(AspectRatioSchema).optional(),
1916
- sizes: z.array(ImageSizeSchema).optional(),
1917
- resolutions: z.array(VideoResolutionSchema).optional(),
1918
- durations: z.union([z.looseObject({ min: z.number(), max: z.number() }), z.array(z.number())]).optional(),
1919
- durationPresets: z.array(z.number()).optional(),
1920
- qualityOptions: z.array(z.string()).optional(),
1921
- exactSizes: z.record(z.string(), z.string()).optional(),
2122
+ var ModelConstraintsSchema = z2.looseObject({
2123
+ aspectRatios: z2.array(AspectRatioSchema).optional(),
2124
+ sizes: z2.array(ImageSizeSchema).optional(),
2125
+ resolutions: z2.array(VideoResolutionSchema).optional(),
2126
+ durations: z2.union([z2.looseObject({ min: z2.number(), max: z2.number() }), z2.array(z2.number())]).optional(),
2127
+ durationPresets: z2.array(z2.number()).optional(),
2128
+ qualityOptions: z2.array(z2.string()).optional(),
2129
+ exactSizes: z2.record(z2.string(), z2.string()).optional(),
1922
2130
  references: ReferenceLimitsSchema.optional(),
1923
- requires: z.array(RequiredInputSchema).optional(),
1924
- supports: z.array(SupportedOptionSchema).optional(),
1925
- ratioIgnoredWith: z.array(z.enum(["firstFrame", "sourceVideo"])).optional()
2131
+ requires: z2.array(RequiredInputSchema).optional(),
2132
+ supports: z2.array(SupportedOptionSchema).optional(),
2133
+ ratioIgnoredWith: z2.array(z2.enum(["firstFrame", "sourceVideo"])).optional()
1926
2134
  });
1927
- var MediaRefSchema = z.union([
1928
- z.looseObject({ url: z.string(), label: z.string().optional() }),
1929
- z.looseObject({
1930
- bytes: z.instanceof(Uint8Array),
1931
- mime: z.string(),
1932
- label: z.string().optional()
2135
+ var MediaRefSchema = z2.union([
2136
+ z2.looseObject({ url: z2.string(), label: z2.string().optional() }),
2137
+ z2.looseObject({
2138
+ bytes: z2.instanceof(Uint8Array),
2139
+ mime: z2.string(),
2140
+ label: z2.string().optional()
1933
2141
  })
1934
2142
  ]);
1935
- var ImageSafetySettingSchema = z.looseObject({ category: z.string(), threshold: z.string() });
1936
- var UpscaleOptionsSchema = z.looseObject({
1937
- enhanceModel: z.string().optional(),
1938
- subjectDetection: z.string().optional(),
1939
- faceEnhancement: z.boolean().optional(),
1940
- faceEnhancementCreativity: z.number().optional(),
1941
- faceEnhancementStrength: z.number().optional()
2143
+ var ImageSafetySettingSchema = z2.looseObject({ category: z2.string(), threshold: z2.string() });
2144
+ var UpscaleOptionsSchema = z2.looseObject({
2145
+ enhanceModel: z2.string().optional(),
2146
+ subjectDetection: z2.string().optional(),
2147
+ faceEnhancement: z2.boolean().optional(),
2148
+ faceEnhancementCreativity: z2.number().optional(),
2149
+ faceEnhancementStrength: z2.number().optional()
1942
2150
  });
1943
- var DefaultsSchema = z.looseObject({
1944
- references: z.array(MediaRefSchema).optional(),
2151
+ var DefaultsSchema = z2.looseObject({
2152
+ references: z2.array(MediaRefSchema).optional(),
1945
2153
  aspectRatio: AspectRatioSchema.optional(),
1946
2154
  size: ImageSizeSchema.optional(),
1947
- exactSize: z.string().optional(),
2155
+ exactSize: z2.string().optional(),
1948
2156
  quality: ImageQualitySchema.optional(),
1949
- seed: z.number().optional(),
1950
- count: z.number().optional(),
2157
+ seed: z2.number().optional(),
2158
+ count: z2.number().optional(),
1951
2159
  outputFormat: OutputFormatSchema.optional(),
1952
- scaleFactor: z.number().optional(),
1953
- safetySettings: z.array(ImageSafetySettingSchema).optional(),
1954
- temperature: z.number().optional(),
2160
+ scaleFactor: z2.number().optional(),
2161
+ safetySettings: z2.array(ImageSafetySettingSchema).optional(),
2162
+ temperature: z2.number().optional(),
1955
2163
  upscale: UpscaleOptionsSchema.optional(),
1956
2164
  firstFrame: MediaRefSchema.optional(),
1957
2165
  lastFrame: MediaRefSchema.optional(),
1958
2166
  sourceVideo: MediaRefSchema.optional(),
1959
- referenceImages: z.array(MediaRefSchema).optional(),
1960
- referenceVideos: z.array(MediaRefSchema).optional(),
1961
- referenceAudios: z.array(MediaRefSchema).optional(),
2167
+ referenceImages: z2.array(MediaRefSchema).optional(),
2168
+ referenceVideos: z2.array(MediaRefSchema).optional(),
2169
+ referenceAudios: z2.array(MediaRefSchema).optional(),
1962
2170
  resolution: VideoResolutionSchema.optional(),
1963
- durationSeconds: z.number().optional(),
1964
- generateAudio: z.boolean().optional(),
1965
- negativePrompt: z.string().optional(),
1966
- cfgScale: z.number().optional(),
1967
- promptExpansion: z.enum(["fast", "balanced", "quality"]).optional(),
1968
- watermark: z.boolean().optional(),
1969
- safetyChecker: z.boolean().optional(),
1970
- taskType: z.enum(["reference", "edit", "extend"]).optional(),
1971
- mode: z.enum(["standard", "pro"]).optional(),
1972
- instrumental: z.boolean().optional()
2171
+ durationSeconds: z2.number().optional(),
2172
+ generateAudio: z2.boolean().optional(),
2173
+ negativePrompt: z2.string().optional(),
2174
+ cfgScale: z2.number().optional(),
2175
+ promptExpansion: z2.enum(["fast", "balanced", "quality"]).optional(),
2176
+ watermark: z2.boolean().optional(),
2177
+ safetyChecker: z2.boolean().optional(),
2178
+ taskType: z2.enum(["reference", "edit", "extend"]).optional(),
2179
+ mode: z2.enum(["standard", "pro"]).optional(),
2180
+ instrumental: z2.boolean().optional()
1973
2181
  });
1974
- var CatalogDisplaySchema = z.looseObject({
1975
- provider: z.string(),
1976
- description: z.string(),
1977
- logo: z.string().optional(),
1978
- costTier: z.union([z.literal(1), z.literal(2), z.literal(3)]).optional(),
1979
- recommended: z.boolean().optional(),
1980
- sortOrder: z.number().optional(),
1981
- chat: z.looseObject({
2182
+ var CatalogDisplaySchema = z2.looseObject({
2183
+ provider: z2.string(),
2184
+ description: z2.string(),
2185
+ logo: z2.string().optional(),
2186
+ costTier: z2.union([z2.literal(1), z2.literal(2), z2.literal(3)]).optional(),
2187
+ recommended: z2.boolean().optional(),
2188
+ sortOrder: z2.number().optional(),
2189
+ chat: z2.looseObject({
1982
2190
  providerOptions: ProviderOptionsSchema.optional(),
1983
- temperature: z.number().optional()
2191
+ temperature: z2.number().optional()
1984
2192
  }).optional()
1985
2193
  });
1986
- var CatalogCapabilitiesSchema = z.looseObject({
1987
- acceptsSourceVideo: z.boolean().optional(),
1988
- framesExcludeReferences: z.boolean().optional(),
1989
- reasoning: z.boolean().optional(),
1990
- vision: z.boolean().optional(),
1991
- contextWindow: z.number().optional()
2194
+ var CatalogCapabilitiesSchema = z2.looseObject({
2195
+ acceptsSourceVideo: z2.boolean().optional(),
2196
+ framesExcludeReferences: z2.boolean().optional(),
2197
+ reasoning: z2.boolean().optional(),
2198
+ vision: z2.boolean().optional(),
2199
+ contextWindow: z2.number().optional()
1992
2200
  });
1993
- var CatalogModelSchemaBase = z.looseObject({
1994
- id: z.string().min(1),
1995
- aliases: z.array(z.string()).default([]),
1996
- label: z.string().min(1),
2201
+ var CatalogModelSchemaBase = z2.looseObject({
2202
+ id: z2.string().min(1),
2203
+ aliases: z2.array(z2.string()).default([]),
2204
+ label: z2.string().min(1),
1997
2205
  type: ModelTypeSchema,
1998
2206
  adapter: AdapterSchema,
1999
- providerModelId: z.string().min(1),
2207
+ providerModelId: z2.string().min(1),
2000
2208
  lifecycle: LifecycleSchema,
2001
- replacedBy: z.string().optional(),
2209
+ replacedBy: z2.string().optional(),
2002
2210
  exposure: ExposureSchema,
2003
2211
  constraints: ModelConstraintsSchema,
2004
2212
  defaults: DefaultsSchema,
2005
2213
  providerOptions: ProviderOptionsSchema.optional(),
2006
- usage: z.looseObject({
2214
+ usage: z2.looseObject({
2007
2215
  unit: UsageUnitSchema,
2008
- slug: z.string().optional(),
2009
- providerLabel: z.string().optional()
2216
+ slug: z2.string().optional(),
2217
+ providerLabel: z2.string().optional()
2010
2218
  }),
2011
2219
  pricingKind: PricingKindSchema,
2012
2220
  display: CatalogDisplaySchema.optional(),
@@ -2044,44 +2252,29 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
2044
2252
  message: 'transport must be "direct" or "bedrock"'
2045
2253
  });
2046
2254
  }
2255
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2256
+ if (inputSpecRaw !== void 0) {
2257
+ const result = validateInputSpec(inputSpecRaw, row);
2258
+ if (!result.ok) {
2259
+ for (const issue of result.issues) {
2260
+ ctx.addIssue({
2261
+ code: "custom",
2262
+ path: ["providerOptions", "modelkit", "inputSpec", ...issue.path],
2263
+ message: issue.message
2264
+ });
2265
+ }
2266
+ }
2267
+ }
2047
2268
  }
2048
2269
  );
2049
- var CatalogSchema = z.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2050
- const seenIds = /* @__PURE__ */ new Map();
2051
- rows.forEach((row, index) => {
2052
- if (seenIds.has(row.id)) {
2053
- ctx.addIssue({
2054
- code: "custom",
2055
- path: [index, "id"],
2056
- message: `Duplicate model id "${row.id}"`
2057
- });
2058
- } else {
2059
- seenIds.set(row.id, index);
2060
- }
2061
- });
2062
- const seenAliases = /* @__PURE__ */ new Map();
2063
- rows.forEach((row, index) => {
2064
- row.aliases.forEach((alias, aliasIndex) => {
2065
- const path = [index, "aliases", aliasIndex];
2066
- if (alias === row.id || seenIds.has(alias)) {
2067
- ctx.addIssue({
2068
- code: "custom",
2069
- path,
2070
- message: `Alias "${alias}" collides with a model id`
2071
- });
2072
- return;
2073
- }
2074
- if (seenAliases.has(alias)) {
2075
- ctx.addIssue({
2076
- code: "custom",
2077
- path,
2078
- message: `Duplicate alias "${alias}"`
2079
- });
2080
- } else {
2081
- seenAliases.set(alias, index);
2082
- }
2270
+ var CatalogSchema = z2.array(CatalogModelSchemaBase).superRefine((rows, ctx) => {
2271
+ for (const issue of collisionIssues(rows)) {
2272
+ ctx.addIssue({
2273
+ code: "custom",
2274
+ path: [issue.index, ...issue.path],
2275
+ message: issue.message
2083
2276
  });
2084
- });
2277
+ }
2085
2278
  });
2086
2279
 
2087
2280
  // src/catalog/live.ts
@@ -2096,26 +2289,102 @@ var liveState = store[KEY] ??= {
2096
2289
  };
2097
2290
  var liveCatalog = liveState.catalog;
2098
2291
 
2292
+ // src/json.ts
2293
+ import { z as z3 } from "zod";
2294
+ var JsonValueSchema = z3.lazy(
2295
+ () => z3.union([
2296
+ z3.string(),
2297
+ z3.number(),
2298
+ z3.boolean(),
2299
+ z3.null(),
2300
+ z3.array(JsonValueSchema),
2301
+ z3.record(z3.string(), JsonValueSchema)
2302
+ ])
2303
+ );
2304
+ var JsonObjectSchema = z3.record(z3.string(), JsonValueSchema);
2305
+ var thrownErrorSchema = z3.object({
2306
+ message: z3.string().optional(),
2307
+ status: z3.number().optional(),
2308
+ statusCode: z3.number().optional(),
2309
+ responseBody: z3.string().optional()
2310
+ });
2311
+
2099
2312
  // src/catalog/load.ts
2100
- import { z as z2 } from "zod";
2313
+ import { z as z4 } from "zod";
2101
2314
  function rowCount() {
2102
2315
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
2103
2316
  }
2104
2317
  function authHeaders(auth) {
2105
2318
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
2106
2319
  }
2107
- var EnvelopeSchema = z2.object({
2108
- rows: CatalogSchema,
2109
- revision: z2.string().optional()
2320
+ var EnvelopeSchema = z4.object({
2321
+ rows: z4.array(JsonValueSchema),
2322
+ revision: z4.string().optional()
2110
2323
  });
2111
- function toEnvelope(data) {
2112
- if (data.rows.length === 0) throw new Error("invalid catalog response: no rows");
2113
- const envelope = { rows: data.rows };
2324
+ function dropReason(path, message) {
2325
+ return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
2326
+ }
2327
+ function rowId(raw) {
2328
+ const parsed = z4.object({ id: z4.string().min(1) }).loose().safeParse(raw);
2329
+ if (!parsed.success) return "?";
2330
+ return parsed.data.id;
2331
+ }
2332
+ function quarantine(rawRows, logger) {
2333
+ const valid = [];
2334
+ let dropped = 0;
2335
+ for (const raw of rawRows) {
2336
+ const parsed = CatalogModelSchemaBase.safeParse(raw);
2337
+ if (!parsed.success) {
2338
+ const first = parsed.error.issues[0];
2339
+ const reason = first ? dropReason(first.path, first.message) : "invalid row";
2340
+ logger.warn(`[modelkit] catalog row dropped id=${rowId(raw)} reason=${reason}`);
2341
+ dropped += 1;
2342
+ continue;
2343
+ }
2344
+ const row = parsed.data;
2345
+ const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
2346
+ if (inputSpecRaw !== void 0) {
2347
+ const result = validateInputSpec(inputSpecRaw, row);
2348
+ if (!result.ok) {
2349
+ const first = result.issues[0];
2350
+ const detail = first ? dropReason(first.path, first.message) : "invalid inputSpec";
2351
+ logger.warn(
2352
+ `[modelkit] catalog row ${row.id} has an invalid providerOptions.modelkit.inputSpec: ${detail}; calls fail until it is fixed`
2353
+ );
2354
+ }
2355
+ }
2356
+ valid.push(row);
2357
+ }
2358
+ let kept = valid;
2359
+ for (; ; ) {
2360
+ const issues = collisionIssues(kept);
2361
+ if (issues.length === 0) break;
2362
+ const firstByIndex = /* @__PURE__ */ new Map();
2363
+ for (const issue of issues) {
2364
+ if (!firstByIndex.has(issue.index)) firstByIndex.set(issue.index, issue);
2365
+ }
2366
+ for (const [index, issue] of [...firstByIndex.entries()].sort((a, b) => a[0] - b[0])) {
2367
+ const row = kept[index];
2368
+ if (!row) continue;
2369
+ logger.warn(
2370
+ `[modelkit] catalog row dropped id=${row.id} reason=${String(issue.path[0] ?? "")} ${issue.message}`
2371
+ );
2372
+ }
2373
+ const dropSet = new Set(firstByIndex.keys());
2374
+ kept = kept.filter((_, index) => !dropSet.has(index));
2375
+ dropped += dropSet.size;
2376
+ }
2377
+ return { rows: kept, dropped };
2378
+ }
2379
+ function toEnvelope(data, logger) {
2380
+ const { rows, dropped } = quarantine(data.rows, logger);
2381
+ if (rows.length === 0) throw new Error("invalid catalog response: no rows");
2382
+ const envelope = { rows, dropped };
2114
2383
  if (data.revision !== void 0) envelope.revision = data.revision;
2115
2384
  return envelope;
2116
2385
  }
2117
- function describeError(err) {
2118
- return err instanceof Error ? err.message : String(err);
2386
+ function describeError(cause) {
2387
+ return cause instanceof Error ? cause.message : String(cause);
2119
2388
  }
2120
2389
  function logPrimed(logger, result) {
2121
2390
  const revision = result.revision === void 0 ? "" : ` revision=${result.revision}`;
@@ -2136,9 +2405,9 @@ async function fetchRemote(source, logger) {
2136
2405
  const json = await res.json();
2137
2406
  const parsed = EnvelopeSchema.safeParse(json);
2138
2407
  if (!parsed.success) throw new Error("invalid catalog response: missing rows");
2139
- const { rows, revision: rev } = toEnvelope(parsed.data);
2140
- if (rev === void 0) return { rows, fromCache: false };
2141
- return { rows, revision: rev, fromCache: false };
2408
+ const { rows, revision: rev, dropped } = toEnvelope(parsed.data, logger);
2409
+ if (rev === void 0) return { rows, fromCache: false, dropped };
2410
+ return { rows, revision: rev, fromCache: false, dropped };
2142
2411
  }
2143
2412
  async function writeCache(source, logger, rows, rev) {
2144
2413
  if (!source.cache) return;
@@ -2163,6 +2432,7 @@ async function prime(source, logger) {
2163
2432
  await writeCache(source, logger, fetched.rows, fetched.revision);
2164
2433
  const result = { origin: liveState.origin, rowCount: rowCount() };
2165
2434
  if (fetched.revision !== void 0) result.revision = fetched.revision;
2435
+ if (fetched.dropped > 0) result.droppedRows = fetched.dropped;
2166
2436
  logPrimed(logger, result);
2167
2437
  return result;
2168
2438
  } catch (err) {
@@ -2173,7 +2443,7 @@ async function prime(source, logger) {
2173
2443
  if (!cached) throw new Error("no cached catalog");
2174
2444
  const cachedParsed = EnvelopeSchema.safeParse(JSON.parse(cached));
2175
2445
  if (!cachedParsed.success) throw new Error("invalid catalog response: missing rows");
2176
- const { rows, revision: rev } = toEnvelope(cachedParsed.data);
2446
+ const { rows, revision: rev, dropped } = toEnvelope(cachedParsed.data, logger);
2177
2447
  liveCatalog.replace(rows);
2178
2448
  liveState.origin = "last-good";
2179
2449
  liveState.revision = rev;
@@ -2183,6 +2453,7 @@ async function prime(source, logger) {
2183
2453
  error
2184
2454
  };
2185
2455
  if (rev !== void 0) result.revision = rev;
2456
+ if (dropped > 0) result.droppedRows = dropped;
2186
2457
  logPrimed(logger, result);
2187
2458
  return result;
2188
2459
  } catch (cacheErr) {
@@ -2630,6 +2901,7 @@ export {
2630
2901
  ADAPTER_IDS,
2631
2902
  Catalog,
2632
2903
  CatalogModelSchema,
2904
+ CatalogModelSchemaBase,
2633
2905
  CatalogSchema,
2634
2906
  ExposureSchema,
2635
2907
  IMAGE_MODELS,