@shop-os/modelkit 0.1.11 → 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.
@@ -1,4 +1,5 @@
1
1
  import { ImageModel, experimental_generateVideo } from 'ai';
2
+ import { z } from 'zod';
2
3
 
3
4
  /**
4
5
  * Canonical vocabulary shared by every adapter. Adapters translate these
@@ -417,11 +418,50 @@ declare class Catalog {
417
418
  }): CatalogModel[];
418
419
  /** Merge rows by id. Used for catalogOverride. */
419
420
  withOverrides(rows: CatalogModel[]): Catalog;
421
+ /** Atomically swap every row. Builds the maps first so a bad batch throws before anything changes. */
422
+ replace(rows: CatalogModel[]): void;
420
423
  }
421
424
 
422
425
  /** Seeded from Cowork, Space Builder and trigger-workflows. See catalog/*.ts. */
423
426
  declare const MODELS: CatalogModel[];
424
427
 
428
+ declare const ADAPTER_IDS: readonly ["ai-sdk-text", "google-image", "openai-image", "google-genai", "ark", "fal", "replicate", "prodia", "higgsfield", "xai-video"];
429
+ declare const CatalogModelSchema: z.ZodType<CatalogModel>;
430
+ declare const CatalogSchema: z.ZodType<CatalogModel[]>;
431
+
432
+ declare const liveCatalog: Catalog;
433
+
434
+ interface CatalogCache {
435
+ get(): Promise<string | null>;
436
+ set(json: string): Promise<void>;
437
+ }
438
+ type CatalogAuth = {
439
+ bearer: string;
440
+ } | {
441
+ apiKey: string;
442
+ };
443
+ interface CatalogSource {
444
+ baseUrl: string;
445
+ auth: CatalogAuth;
446
+ ttlMs?: number;
447
+ /** Abort a fetch after this many ms. Default 10 s. */
448
+ timeoutMs?: number;
449
+ cache?: CatalogCache;
450
+ fetch?: typeof fetch;
451
+ logger?: Pick<Console, "debug" | "info" | "warn" | "error">;
452
+ }
453
+ type CatalogOrigin = "remote" | "last-good" | "snapshot";
454
+ interface PrimeCatalogResult {
455
+ origin: CatalogOrigin;
456
+ rowCount: number;
457
+ revision?: string;
458
+ error?: string;
459
+ }
460
+ /** Fetch, validate, swap into liveCatalog. Never throws. Second call returns the same promise. */
461
+ declare function primeCatalog(source: CatalogSource): Promise<PrimeCatalogResult>;
462
+ /** Test seam: stop the refresh timer and reset liveCatalog to MODELS and clear the memo. */
463
+ declare function resetLiveCatalog(): void;
464
+
425
465
  declare const IMAGE_MODELS: CatalogModel[];
426
466
 
427
467
  declare const VIDEO_MODELS: CatalogModel[];
@@ -476,4 +516,4 @@ declare function isModelKitError(err: unknown): err is ModelKitError;
476
516
  /** Resolve caller options against a catalog row, dispatching on `model.type`. */
477
517
  declare function resolveOptions(model: CatalogModel, request: ImageRequest | VideoRequest | AudioRequest, onUnsupported?: OnUnsupported): ResolveResult<ImageRequest | VideoRequest | AudioRequest>;
478
518
 
479
- export { type AdapterEndpoints, type AdapterId, type AspectRatio, type AudioRequest, type AudioResult, type CallContext, Catalog, type CatalogCapabilities, type CatalogDisplay, type CatalogModel, type GeneratedImage, IMAGE_MODELS, type ImageBytes, type ImageCallOptions, type ImageCallResult, type ImageQuality, type ImageRequest, type ImageResult, type ImageSafetySetting, type ImageSize, type JsonObject, type JsonPrimitive, type JsonValue, type Lifecycle, MODELS, type MediaPart, type MediaRef, type ModelConstraints, type ModelKitConfig, ModelKitError, type ModelKitErrorCode, type ModelKitErrorInit, type ModelType, OTHER_MODELS, type OnUnsupported, type OutputFormat, type PricingKind, type ProviderErrorBody, type ProviderKeyName, type ProviderKeys, type ProviderOptionValue, type ProviderOptions, type ReferenceLimits, type RequiredInput, type ResolveResult, type Routing, type SupportedOption, TEXT_MODELS, type UpscaleOptions, type UsageEvent, type UsageModality, type UsageUnit, VIDEO_MODELS, type VideoCallJob, type VideoCallOptions, type VideoJob, type VideoModel, type VideoRequest, type VideoResolution, type VideoResult, type Warning, isModelKitError, nearestAspectRatio, resolveAudioOptions, resolveImageOptions, resolveOptions, resolveVideoOptions };
519
+ export { ADAPTER_IDS, type AdapterEndpoints, type AdapterId, type AspectRatio, type AudioRequest, type AudioResult, type CallContext, Catalog, type CatalogAuth, type CatalogCache, type CatalogCapabilities, type CatalogDisplay, type CatalogModel, CatalogModelSchema, type CatalogOrigin, CatalogSchema, type CatalogSource, type GeneratedImage, IMAGE_MODELS, type ImageBytes, type ImageCallOptions, type ImageCallResult, type ImageQuality, type ImageRequest, type ImageResult, type ImageSafetySetting, type ImageSize, type JsonObject, type JsonPrimitive, type JsonValue, type Lifecycle, MODELS, type MediaPart, type MediaRef, type ModelConstraints, type ModelKitConfig, ModelKitError, type ModelKitErrorCode, type ModelKitErrorInit, type ModelType, OTHER_MODELS, type OnUnsupported, type OutputFormat, type PricingKind, type PrimeCatalogResult, type ProviderErrorBody, type ProviderKeyName, type ProviderKeys, type ProviderOptionValue, type ProviderOptions, type ReferenceLimits, type RequiredInput, type ResolveResult, type Routing, type SupportedOption, TEXT_MODELS, type UpscaleOptions, type UsageEvent, type UsageModality, type UsageUnit, VIDEO_MODELS, type VideoCallJob, type VideoCallOptions, type VideoJob, type VideoModel, type VideoRequest, type VideoResolution, type VideoResult, type Warning, isModelKitError, liveCatalog, nearestAspectRatio, primeCatalog, resetLiveCatalog, resolveAudioOptions, resolveImageOptions, resolveOptions, resolveVideoOptions };
package/dist/catalog.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ImageModel, experimental_generateVideo } from 'ai';
2
+ import { z } from 'zod';
2
3
 
3
4
  /**
4
5
  * Canonical vocabulary shared by every adapter. Adapters translate these
@@ -417,11 +418,50 @@ declare class Catalog {
417
418
  }): CatalogModel[];
418
419
  /** Merge rows by id. Used for catalogOverride. */
419
420
  withOverrides(rows: CatalogModel[]): Catalog;
421
+ /** Atomically swap every row. Builds the maps first so a bad batch throws before anything changes. */
422
+ replace(rows: CatalogModel[]): void;
420
423
  }
421
424
 
422
425
  /** Seeded from Cowork, Space Builder and trigger-workflows. See catalog/*.ts. */
423
426
  declare const MODELS: CatalogModel[];
424
427
 
428
+ declare const ADAPTER_IDS: readonly ["ai-sdk-text", "google-image", "openai-image", "google-genai", "ark", "fal", "replicate", "prodia", "higgsfield", "xai-video"];
429
+ declare const CatalogModelSchema: z.ZodType<CatalogModel>;
430
+ declare const CatalogSchema: z.ZodType<CatalogModel[]>;
431
+
432
+ declare const liveCatalog: Catalog;
433
+
434
+ interface CatalogCache {
435
+ get(): Promise<string | null>;
436
+ set(json: string): Promise<void>;
437
+ }
438
+ type CatalogAuth = {
439
+ bearer: string;
440
+ } | {
441
+ apiKey: string;
442
+ };
443
+ interface CatalogSource {
444
+ baseUrl: string;
445
+ auth: CatalogAuth;
446
+ ttlMs?: number;
447
+ /** Abort a fetch after this many ms. Default 10 s. */
448
+ timeoutMs?: number;
449
+ cache?: CatalogCache;
450
+ fetch?: typeof fetch;
451
+ logger?: Pick<Console, "debug" | "info" | "warn" | "error">;
452
+ }
453
+ type CatalogOrigin = "remote" | "last-good" | "snapshot";
454
+ interface PrimeCatalogResult {
455
+ origin: CatalogOrigin;
456
+ rowCount: number;
457
+ revision?: string;
458
+ error?: string;
459
+ }
460
+ /** Fetch, validate, swap into liveCatalog. Never throws. Second call returns the same promise. */
461
+ declare function primeCatalog(source: CatalogSource): Promise<PrimeCatalogResult>;
462
+ /** Test seam: stop the refresh timer and reset liveCatalog to MODELS and clear the memo. */
463
+ declare function resetLiveCatalog(): void;
464
+
425
465
  declare const IMAGE_MODELS: CatalogModel[];
426
466
 
427
467
  declare const VIDEO_MODELS: CatalogModel[];
@@ -476,4 +516,4 @@ declare function isModelKitError(err: unknown): err is ModelKitError;
476
516
  /** Resolve caller options against a catalog row, dispatching on `model.type`. */
477
517
  declare function resolveOptions(model: CatalogModel, request: ImageRequest | VideoRequest | AudioRequest, onUnsupported?: OnUnsupported): ResolveResult<ImageRequest | VideoRequest | AudioRequest>;
478
518
 
479
- export { type AdapterEndpoints, type AdapterId, type AspectRatio, type AudioRequest, type AudioResult, type CallContext, Catalog, type CatalogCapabilities, type CatalogDisplay, type CatalogModel, type GeneratedImage, IMAGE_MODELS, type ImageBytes, type ImageCallOptions, type ImageCallResult, type ImageQuality, type ImageRequest, type ImageResult, type ImageSafetySetting, type ImageSize, type JsonObject, type JsonPrimitive, type JsonValue, type Lifecycle, MODELS, type MediaPart, type MediaRef, type ModelConstraints, type ModelKitConfig, ModelKitError, type ModelKitErrorCode, type ModelKitErrorInit, type ModelType, OTHER_MODELS, type OnUnsupported, type OutputFormat, type PricingKind, type ProviderErrorBody, type ProviderKeyName, type ProviderKeys, type ProviderOptionValue, type ProviderOptions, type ReferenceLimits, type RequiredInput, type ResolveResult, type Routing, type SupportedOption, TEXT_MODELS, type UpscaleOptions, type UsageEvent, type UsageModality, type UsageUnit, VIDEO_MODELS, type VideoCallJob, type VideoCallOptions, type VideoJob, type VideoModel, type VideoRequest, type VideoResolution, type VideoResult, type Warning, isModelKitError, nearestAspectRatio, resolveAudioOptions, resolveImageOptions, resolveOptions, resolveVideoOptions };
519
+ export { ADAPTER_IDS, type AdapterEndpoints, type AdapterId, type AspectRatio, type AudioRequest, type AudioResult, type CallContext, Catalog, type CatalogAuth, type CatalogCache, type CatalogCapabilities, type CatalogDisplay, type CatalogModel, CatalogModelSchema, type CatalogOrigin, CatalogSchema, type CatalogSource, type GeneratedImage, IMAGE_MODELS, type ImageBytes, type ImageCallOptions, type ImageCallResult, type ImageQuality, type ImageRequest, type ImageResult, type ImageSafetySetting, type ImageSize, type JsonObject, type JsonPrimitive, type JsonValue, type Lifecycle, MODELS, type MediaPart, type MediaRef, type ModelConstraints, type ModelKitConfig, ModelKitError, type ModelKitErrorCode, type ModelKitErrorInit, type ModelType, OTHER_MODELS, type OnUnsupported, type OutputFormat, type PricingKind, type PrimeCatalogResult, type ProviderErrorBody, type ProviderKeyName, type ProviderKeys, type ProviderOptionValue, type ProviderOptions, type ReferenceLimits, type RequiredInput, type ResolveResult, type Routing, type SupportedOption, TEXT_MODELS, type UpscaleOptions, type UsageEvent, type UsageModality, type UsageUnit, VIDEO_MODELS, type VideoCallJob, type VideoCallOptions, type VideoJob, type VideoModel, type VideoRequest, type VideoResolution, type VideoResult, type Warning, isModelKitError, liveCatalog, nearestAspectRatio, primeCatalog, resetLiveCatalog, resolveAudioOptions, resolveImageOptions, resolveOptions, resolveVideoOptions };
package/dist/catalog.js CHANGED
@@ -93,6 +93,14 @@ 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
@@ -1783,6 +1791,387 @@ var MODELS = [
1783
1791
  ...OTHER_MODELS
1784
1792
  ];
1785
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
+
1786
2175
  // src/resolve-options.ts
1787
2176
  var SIZE_ORDER = ["512", "1K", "2K", "4K"];
1788
2177
  var RESOLUTION_ORDER = ["360p", "480p", "720p", "768p", "1080p", "2k", "4k"];
@@ -2165,7 +2554,10 @@ function resolveOptions(model, request, onUnsupported = "error") {
2165
2554
  }
2166
2555
  }
2167
2556
  export {
2557
+ ADAPTER_IDS,
2168
2558
  Catalog,
2559
+ CatalogModelSchema,
2560
+ CatalogSchema,
2169
2561
  IMAGE_MODELS,
2170
2562
  MODELS,
2171
2563
  ModelKitError,
@@ -2173,7 +2565,10 @@ export {
2173
2565
  TEXT_MODELS,
2174
2566
  VIDEO_MODELS,
2175
2567
  isModelKitError,
2568
+ liveCatalog,
2176
2569
  nearestAspectRatio,
2570
+ primeCatalog,
2571
+ resetLiveCatalog,
2177
2572
  resolveAudioOptions,
2178
2573
  resolveImageOptions,
2179
2574
  resolveOptions,