@shop-os/modelkit 0.5.0 → 0.6.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/index.cjs CHANGED
@@ -46,6 +46,8 @@ __export(index_exports, {
46
46
  InputSpecSchema: () => InputSpecSchema,
47
47
  JsonObjectSchema: () => JsonObjectSchema,
48
48
  JsonValueSchema: () => JsonValueSchema,
49
+ MODEL3D_IMAGE_SLOTS: () => MODEL3D_IMAGE_SLOTS,
50
+ MODEL3D_MODELS: () => MODEL3D_MODELS,
49
51
  MODELS: () => MODELS,
50
52
  ModelKitError: () => ModelKitError,
51
53
  SURFACES: () => SURFACES2,
@@ -88,6 +90,14 @@ __export(index_exports, {
88
90
  liveState: () => liveState,
89
91
  mergeTextProviderOptions: () => mergeTextProviderOptions,
90
92
  missingTierKeys: () => missingTierKeys,
93
+ model3dCall: () => model3dCall,
94
+ model3dConstraints: () => model3dConstraints,
95
+ model3dInputRefusal: () => model3dInputRefusal,
96
+ model3dPricingSku: () => model3dPricingSku,
97
+ model3dResolution: () => model3dResolution,
98
+ model3dSeedFits: () => model3dSeedFits,
99
+ model3dSkus: () => model3dSkus,
100
+ model3dTexture: () => model3dTexture,
91
101
  nearestAspectRatio: () => nearestAspectRatio,
92
102
  normalizeExposure: () => normalizeExposure,
93
103
  openaiImageAdapter: () => openaiImageAdapter,
@@ -265,18 +275,18 @@ function normalizeExposure(value) {
265
275
  if (value.every(
266
276
  (entry) => SURFACES.includes(entry)
267
277
  )) {
268
- const present = new Set(value);
269
- return SURFACES.filter((surface) => present.has(surface));
278
+ const present2 = new Set(value);
279
+ return SURFACES.filter((surface) => present2.has(surface));
270
280
  }
271
281
  return value;
272
282
  }
273
283
  return value;
274
284
  }
275
- function isListedOn(row, surface) {
276
- return row.lifecycle === "active" && row.exposure.includes(surface);
285
+ function isListedOn(row2, surface) {
286
+ return row2.lifecycle === "active" && row2.exposure.includes(surface);
277
287
  }
278
- function isListed(row) {
279
- return row.lifecycle === "active" && row.exposure.length > 0;
288
+ function isListed(row2) {
289
+ return row2.lifecycle === "active" && row2.exposure.length > 0;
280
290
  }
281
291
 
282
292
  // src/catalog/image-fal.ts
@@ -3678,6 +3688,197 @@ var MEDIA_NODE_MODELS = [
3678
3688
  SAM_3_IMAGE
3679
3689
  ];
3680
3690
 
3691
+ // src/catalog/model3d.ts
3692
+ var REQUEST_USAGE = { unit: "requests" };
3693
+ function row(id, label, spec, display) {
3694
+ return {
3695
+ id,
3696
+ aliases: [],
3697
+ label,
3698
+ type: "model3d",
3699
+ adapter: "fal",
3700
+ // The single-image endpoint; the adapter picks the endpoint a request needs.
3701
+ providerModelId: spec.endpoints.image ?? id,
3702
+ lifecycle: "active",
3703
+ exposure: ["space_builder"],
3704
+ constraints: { supports: [], model3d: spec },
3705
+ defaults: {},
3706
+ usage: REQUEST_USAGE,
3707
+ pricingKind: "flat",
3708
+ display
3709
+ };
3710
+ }
3711
+ var MODEL3D_MODELS = [
3712
+ row(
3713
+ "trellis-2",
3714
+ "Trellis 2",
3715
+ {
3716
+ family: "trellis",
3717
+ endpoints: { image: "fal-ai/trellis-2" },
3718
+ text: false,
3719
+ imageRequired: true,
3720
+ views: "none",
3721
+ maxImages: 1,
3722
+ texture: [],
3723
+ pbr: false,
3724
+ textureRef: false,
3725
+ seed: true,
3726
+ resolutions: { label: "Resolution", options: ["512", "1024", "1536"], default: "1024" }
3727
+ },
3728
+ {
3729
+ provider: "microsoft",
3730
+ description: "One photo to a detailed textured model. Fast and the best value.",
3731
+ sortOrder: 70
3732
+ }
3733
+ ),
3734
+ row(
3735
+ "hunyuan3d-3.1-pro",
3736
+ "Hunyuan3D 3.1 Pro",
3737
+ {
3738
+ family: "hunyuan",
3739
+ endpoints: {
3740
+ text: "fal-ai/hunyuan-3d/v3.1/pro/text-to-3d",
3741
+ image: "fal-ai/hunyuan-3d/v3.1/pro/image-to-3d"
3742
+ },
3743
+ text: true,
3744
+ imageRequired: false,
3745
+ views: "named",
3746
+ maxImages: 4,
3747
+ texture: ["none", "standard"],
3748
+ pbr: true,
3749
+ textureRef: false,
3750
+ seed: false
3751
+ },
3752
+ {
3753
+ provider: "tencent",
3754
+ description: "Photo-faithful models from a prompt, a photo, or a photo with back and side views.",
3755
+ sortOrder: 60
3756
+ }
3757
+ ),
3758
+ row(
3759
+ "tripo-h3.1",
3760
+ "Tripo H3.1",
3761
+ {
3762
+ family: "tripo",
3763
+ endpoints: {
3764
+ text: "tripo3d/h3.1/text-to-3d",
3765
+ image: "tripo3d/h3.1/image-to-3d",
3766
+ multiImage: "tripo3d/h3.1/multiview-to-3d"
3767
+ },
3768
+ text: true,
3769
+ imageRequired: false,
3770
+ views: "ordered",
3771
+ maxImages: 4,
3772
+ texture: ["none", "standard", "detailed"],
3773
+ pbr: true,
3774
+ textureRef: false,
3775
+ seed: true
3776
+ },
3777
+ {
3778
+ provider: "tripo",
3779
+ description: "Clean, game-ready models from a prompt, a photo or four views.",
3780
+ sortOrder: 50
3781
+ }
3782
+ ),
3783
+ row(
3784
+ "rodin-gen-2.5",
3785
+ "Rodin Gen-2.5",
3786
+ {
3787
+ family: "rodin",
3788
+ endpoints: {
3789
+ text: "fal-ai/hyper3d/rodin/v2.5/text-to-3d",
3790
+ image: "fal-ai/hyper3d/rodin/v2.5"
3791
+ },
3792
+ text: true,
3793
+ imageRequired: false,
3794
+ views: "unordered",
3795
+ maxImages: 5,
3796
+ texture: [],
3797
+ pbr: false,
3798
+ textureRef: false,
3799
+ seed: true,
3800
+ seedMax: 65535
3801
+ },
3802
+ {
3803
+ provider: "hyper3d",
3804
+ description: "Detailed PBR models from a prompt or up to five photos.",
3805
+ sortOrder: 40
3806
+ }
3807
+ ),
3808
+ row(
3809
+ "meshy-7.1",
3810
+ "Meshy 7.1",
3811
+ {
3812
+ family: "meshy",
3813
+ endpoints: {
3814
+ text: "meshy/v7.1/text-to-3d",
3815
+ image: "meshy/v7.1/image-to-3d",
3816
+ multiImage: "meshy/v7.1/multi-image-to-3d"
3817
+ },
3818
+ text: true,
3819
+ imageRequired: false,
3820
+ views: "unordered",
3821
+ maxImages: 4,
3822
+ texture: ["none", "standard"],
3823
+ pbr: true,
3824
+ textureRef: true,
3825
+ seed: true
3826
+ },
3827
+ {
3828
+ provider: "meshy",
3829
+ description: "Models from a prompt or photos, with a texture prompt or texture image to restyle.",
3830
+ sortOrder: 30
3831
+ }
3832
+ ),
3833
+ row(
3834
+ "hi3d-3.0",
3835
+ "Hi3D 3.0",
3836
+ {
3837
+ family: "hi3d",
3838
+ endpoints: {
3839
+ image: "hitem3d/hi3d/v3.0/image-to-3d",
3840
+ multiImage: "hitem3d/hi3d/v3.0/multi-view-to-3d"
3841
+ },
3842
+ text: false,
3843
+ imageRequired: true,
3844
+ views: "named",
3845
+ maxImages: 4,
3846
+ texture: ["none", "standard"],
3847
+ pbr: true,
3848
+ textureRef: false,
3849
+ seed: false,
3850
+ resolutions: { label: "Quality", options: ["quality", "master"], default: "quality" }
3851
+ },
3852
+ {
3853
+ provider: "hitem3d",
3854
+ description: "Highest-fidelity product models from a photo or four views. Slowest.",
3855
+ sortOrder: 20
3856
+ }
3857
+ ),
3858
+ row(
3859
+ "sam-3d-objects",
3860
+ "SAM 3D Objects",
3861
+ {
3862
+ family: "sam",
3863
+ endpoints: { image: "fal-ai/sam-3/3d-objects" },
3864
+ text: true,
3865
+ imageRequired: true,
3866
+ promptRequired: true,
3867
+ views: "none",
3868
+ maxImages: 1,
3869
+ texture: [],
3870
+ pbr: false,
3871
+ textureRef: false,
3872
+ seed: true
3873
+ },
3874
+ {
3875
+ provider: "meta",
3876
+ description: "Lifts one named object out of a real photo into a 3D model.",
3877
+ sortOrder: 10
3878
+ }
3879
+ )
3880
+ ];
3881
+
3681
3882
  // src/catalog/other.ts
3682
3883
  var GOOGLE_LOGO2 = "https://d31vvfpk2ppdyq.cloudfront.net/assets/image/192485d2-a76a-4657-9c06-930b2c70badd_compressed.png";
3683
3884
  var ELEVENLABS_LOGO2 = "https://cdn.jsdelivr.net/npm/@lobehub/icons-static-png@1.97.0/light/elevenlabs.png";
@@ -5996,6 +6197,7 @@ var MODELS = [
5996
6197
  ...IMAGE_MODELS,
5997
6198
  ...VIDEO_MODELS,
5998
6199
  ...VIDEO_TOOL_MODELS,
6200
+ ...MODEL3D_MODELS,
5999
6201
  ...OTHER_MODELS,
6000
6202
  ...MEDIA_NODE_MODELS
6001
6203
  ];
@@ -6004,11 +6206,11 @@ var MODELS = [
6004
6206
  var import_zod3 = require("zod");
6005
6207
 
6006
6208
  // src/resolve-provider-rules.ts
6007
- function ruleRefusal(row, message, code) {
6209
+ function ruleRefusal(row2, message, code) {
6008
6210
  return new ModelKitError({
6009
6211
  code,
6010
- message: `${row.label}: ${message}`,
6011
- model: row.id,
6212
+ message: `${row2.label}: ${message}`,
6213
+ model: row2.id,
6012
6214
  retryable: false
6013
6215
  });
6014
6216
  }
@@ -6167,27 +6369,27 @@ function collisionIssues(rows) {
6167
6369
  const issues = [];
6168
6370
  const seenIds = /* @__PURE__ */ new Map();
6169
6371
  const seenAliases = /* @__PURE__ */ new Map();
6170
- rows.forEach((row, index) => {
6171
- if (seenIds.has(row.id)) {
6372
+ rows.forEach((row2, index) => {
6373
+ if (seenIds.has(row2.id)) {
6172
6374
  issues.push({
6173
6375
  index,
6174
6376
  path: ["id"],
6175
- message: `Duplicate model id "${row.id}"`
6377
+ message: `Duplicate model id "${row2.id}"`
6176
6378
  });
6177
6379
  } else {
6178
- const aliasOwner = seenAliases.get(row.id);
6380
+ const aliasOwner = seenAliases.get(row2.id);
6179
6381
  if (aliasOwner !== void 0) {
6180
6382
  issues.push({
6181
6383
  index: aliasOwner.index,
6182
6384
  path: ["aliases", aliasOwner.aliasIndex],
6183
- message: `Alias "${row.id}" collides with a model id`
6385
+ message: `Alias "${row2.id}" collides with a model id`
6184
6386
  });
6185
6387
  }
6186
- seenIds.set(row.id, index);
6388
+ seenIds.set(row2.id, index);
6187
6389
  }
6188
6390
  const local = /* @__PURE__ */ new Set();
6189
- for (const [aliasIndex, alias] of row.aliases.entries()) {
6190
- if (alias === row.id || seenIds.has(alias)) {
6391
+ for (const [aliasIndex, alias] of row2.aliases.entries()) {
6392
+ if (alias === row2.id || seenIds.has(alias)) {
6191
6393
  issues.push({
6192
6394
  index,
6193
6395
  path: ["aliases", aliasIndex],
@@ -6229,8 +6431,8 @@ var DEFAULT_CONVENTIONS = { referenceSyntax: "numbered" };
6229
6431
  var DefaultsReadView = import_zod.z.looseObject({
6230
6432
  generateAudio: import_zod.z.boolean().optional().catch(void 0)
6231
6433
  });
6232
- function promptConventions(row) {
6233
- const view = ConstraintsReadView.safeParse(row.constraints);
6434
+ function promptConventions(row2) {
6435
+ const view = ConstraintsReadView.safeParse(row2.constraints);
6234
6436
  const prompt = view.success ? view.data.prompt : void 0;
6235
6437
  if (prompt === void 0) return { ...DEFAULT_CONVENTIONS };
6236
6438
  const result = { referenceSyntax: prompt.referenceSyntax };
@@ -6241,22 +6443,111 @@ var RawConventionsView = import_zod.z.looseObject({
6241
6443
  audio: import_zod.z.unknown().optional(),
6242
6444
  prompt: import_zod.z.unknown().optional()
6243
6445
  });
6244
- function normaliseConventions(row) {
6245
- const view = RawConventionsView.safeParse(row.constraints);
6246
- if (!view.success) return { row, invalidKeys: [] };
6446
+ function normaliseConventions(row2) {
6447
+ const view = RawConventionsView.safeParse(row2.constraints);
6448
+ if (!view.success) return { row: row2, invalidKeys: [] };
6247
6449
  const { audio, prompt } = view.data;
6248
6450
  const badAudio = audio !== void 0 && !AudioOutputSchema.safeParse(audio).success;
6249
6451
  const badPrompt = prompt !== void 0 && !PromptConventionsSchema.safeParse(prompt).success;
6250
- if (!badAudio && !badPrompt) return { row, invalidKeys: [] };
6452
+ if (!badAudio && !badPrompt) return { row: row2, invalidKeys: [] };
6251
6453
  const invalidKeys = [];
6252
6454
  if (badAudio) invalidKeys.push("constraints.audio");
6253
6455
  if (badPrompt) invalidKeys.push("constraints.prompt");
6254
- const entries = Object.entries(row.constraints).flatMap(([key, value]) => {
6456
+ const entries = Object.entries(row2.constraints).flatMap(([key, value]) => {
6255
6457
  if (key === "audio" && badAudio) return [];
6256
- if (key === "prompt" && badPrompt) return [[key, promptConventions(row)]];
6458
+ if (key === "prompt" && badPrompt) return [[key, promptConventions(row2)]];
6257
6459
  return [[key, value]];
6258
6460
  });
6259
- return { row: { ...row, constraints: Object.fromEntries(entries) }, invalidKeys };
6461
+ return { row: { ...row2, constraints: Object.fromEntries(entries) }, invalidKeys };
6462
+ }
6463
+
6464
+ // src/catalog/model3d-spec.ts
6465
+ function model3dConstraints(row2) {
6466
+ if (row2.type !== "model3d") return void 0;
6467
+ return row2.constraints.model3d;
6468
+ }
6469
+ var MODEL3D_IMAGE_SLOTS = {
6470
+ none: ["image"],
6471
+ named: ["image", "back", "left", "right"],
6472
+ ordered: ["image", "left", "back", "right"],
6473
+ unordered: ["image", "back", "left", "right", "top"]
6474
+ };
6475
+ function model3dInputRefusal(spec, wired) {
6476
+ const top = spec.views === "unordered" && wired.top === true;
6477
+ const anyView = spec.views !== "none" && (wired.back || wired.left || wired.right || top);
6478
+ if (anyView && !wired.image) return "model3d_views_need_image";
6479
+ if (spec.imageRequired && !wired.image) return "model3d_needs_image";
6480
+ if (spec.promptRequired && !wired.prompt) return "model3d_needs_prompt";
6481
+ if (!wired.image && !(spec.text && wired.prompt)) return "model3d_needs_input";
6482
+ if (spec.views === "ordered") {
6483
+ if ((wired.back || wired.right) && !wired.left) return "model3d_views_out_of_order";
6484
+ if (wired.right && !wired.back) return "model3d_views_out_of_order";
6485
+ }
6486
+ return null;
6487
+ }
6488
+ function model3dSeedFits(spec, seed) {
6489
+ return Number.isSafeInteger(seed) && seed >= 0 && seed <= (spec.seedMax ?? Number.MAX_SAFE_INTEGER);
6490
+ }
6491
+ function model3dTexture(spec, requested) {
6492
+ if (requested !== void 0 && spec.texture.includes(requested)) return requested;
6493
+ return spec.texture.includes("standard") ? "standard" : spec.texture[0] ?? "standard";
6494
+ }
6495
+ function model3dResolution(spec, requested) {
6496
+ const res = spec.resolutions;
6497
+ if (res === void 0) return void 0;
6498
+ return requested !== void 0 && res.options.includes(requested) ? requested : res.default;
6499
+ }
6500
+ function model3dPricingSku(row2, options, inputs) {
6501
+ const spec = model3dConstraints(row2);
6502
+ if (spec === void 0) throw new Error(`${row2.id} is not a 3D model`);
6503
+ const texture = model3dTexture(spec, options.texture);
6504
+ const textured = spec.texture.length > 0 && texture !== "none";
6505
+ const pbr = spec.pbr && textured && options.pbr === true;
6506
+ const resolution = model3dResolution(spec, options.resolution);
6507
+ switch (spec.family) {
6508
+ case "meshy":
6509
+ return `${row2.id}__${textured ? "textured" : "untextured"}`;
6510
+ case "tripo":
6511
+ return `${row2.id}__${inputs.image ? "image" : "text"}__${texture}`;
6512
+ case "hunyuan":
6513
+ return `${row2.id}${pbr ? "__pbr" : ""}${inputs.views ? "__views" : ""}`;
6514
+ case "trellis":
6515
+ return `${row2.id}__${resolution}`;
6516
+ case "hi3d":
6517
+ return `${row2.id}__${resolution}__${textured ? pbr ? "texture-pbr" : "texture" : "geometry"}`;
6518
+ case "rodin":
6519
+ case "sam":
6520
+ return row2.id;
6521
+ }
6522
+ }
6523
+ function model3dSkus(row2) {
6524
+ const spec = model3dConstraints(row2);
6525
+ if (spec === void 0) return [];
6526
+ const textures = spec.texture.length > 0 ? spec.texture : [void 0];
6527
+ const pbrs = spec.pbr ? [false, true] : [false];
6528
+ const resolutions = spec.resolutions?.options ?? [void 0];
6529
+ const images = spec.text && !spec.imageRequired ? [true, false] : [true];
6530
+ const views = spec.views === "none" ? [false] : [false, true];
6531
+ const skus = /* @__PURE__ */ new Set();
6532
+ for (const texture of textures)
6533
+ for (const pbr of pbrs)
6534
+ for (const resolution of resolutions)
6535
+ for (const image of images)
6536
+ for (const view of views) {
6537
+ if (view && !image) continue;
6538
+ skus.add(
6539
+ model3dPricingSku(
6540
+ row2,
6541
+ {
6542
+ ...texture !== void 0 && { texture },
6543
+ pbr,
6544
+ ...resolution !== void 0 && { resolution }
6545
+ },
6546
+ { image, views: view }
6547
+ )
6548
+ );
6549
+ }
6550
+ return [...skus].sort();
6260
6551
  }
6261
6552
 
6262
6553
  // src/catalog/input-spec.ts
@@ -6407,7 +6698,7 @@ function isInputSpecKey(key) {
6407
6698
  function isArrayInputSpecKey(key) {
6408
6699
  return ARRAY_KEY_SET.has(key);
6409
6700
  }
6410
- function validateInputSpec(raw, row) {
6701
+ function validateInputSpec(raw, row2) {
6411
6702
  const parsed = InputSpecSchema.safeParse(raw);
6412
6703
  if (!parsed.success) {
6413
6704
  return {
@@ -6419,7 +6710,7 @@ function validateInputSpec(raw, row) {
6419
6710
  };
6420
6711
  }
6421
6712
  const spec = parsed.data;
6422
- const supportedTypes = TYPES_BY_ADAPTER.get(row.adapter);
6713
+ const supportedTypes = TYPES_BY_ADAPTER.get(row2.adapter);
6423
6714
  if (supportedTypes === void 0) {
6424
6715
  return {
6425
6716
  ok: false,
@@ -6432,18 +6723,18 @@ function validateInputSpec(raw, row) {
6432
6723
  };
6433
6724
  }
6434
6725
  const issues = [];
6435
- const allowed = ALLOWED_KEYS_BY_TYPE.get(row.type);
6436
- if (allowed === void 0 || !supportedTypes.includes(row.type)) {
6726
+ const allowed = ALLOWED_KEYS_BY_TYPE.get(row2.type);
6727
+ if (allowed === void 0 || !supportedTypes.includes(row2.type)) {
6437
6728
  issues.push({
6438
6729
  path: [],
6439
- message: row.adapter === "fal" ? `inputSpec on fal rows is only supported for image rows, not "${row.type}"` : `inputSpec is not supported for "${row.type}" rows`
6730
+ message: row2.adapter === "fal" ? `inputSpec on fal rows is only supported for image rows, not "${row2.type}"` : `inputSpec is not supported for "${row2.type}" rows`
6440
6731
  });
6441
6732
  } else {
6442
6733
  for (const key of Object.keys(spec.fields)) {
6443
6734
  if (!allowed.has(key)) {
6444
6735
  issues.push({
6445
6736
  path: ["fields", key],
6446
- message: `inputSpec.fields "${key}" is not supported for ${row.type} rows`
6737
+ message: `inputSpec.fields "${key}" is not supported for ${row2.type} rows`
6447
6738
  });
6448
6739
  }
6449
6740
  }
@@ -6451,13 +6742,13 @@ function validateInputSpec(raw, row) {
6451
6742
  if (!allowed.has(key)) {
6452
6743
  issues.push({
6453
6744
  path: ["values", key],
6454
- message: `inputSpec.values "${key}" is not supported for ${row.type} rows`
6745
+ message: `inputSpec.values "${key}" is not supported for ${row2.type} rows`
6455
6746
  });
6456
6747
  }
6457
6748
  }
6458
6749
  }
6459
6750
  if (spec.editEndpoint !== void 0) {
6460
- if (row.adapter !== "fal") {
6751
+ if (row2.adapter !== "fal") {
6461
6752
  issues.push({
6462
6753
  path: ["editEndpoint"],
6463
6754
  message: "inputSpec.editEndpoint is only supported on fal rows"
@@ -6501,7 +6792,7 @@ function validateInputSpec(raw, row) {
6501
6792
  if (allowed !== void 0 && !allowed.has(key)) {
6502
6793
  issues.push({
6503
6794
  path: ["arrays", name],
6504
- message: `inputSpec.arrays "${key}" is not supported for ${row.type} rows`
6795
+ message: `inputSpec.arrays "${key}" is not supported for ${row2.type} rows`
6505
6796
  });
6506
6797
  }
6507
6798
  if (key in spec.fields) {
@@ -6521,7 +6812,7 @@ function validateInputSpec(raw, row) {
6521
6812
  }
6522
6813
  }
6523
6814
  if (spec.dimensions !== void 0) {
6524
- if (row.type !== "image") {
6815
+ if (row2.type !== "image") {
6525
6816
  issues.push({
6526
6817
  path: ["dimensions"],
6527
6818
  message: "inputSpec.dimensions is only supported on image rows"
@@ -6543,7 +6834,7 @@ function validateInputSpec(raw, row) {
6543
6834
  });
6544
6835
  }
6545
6836
  }
6546
- const supports = row.constraints.supports ?? [];
6837
+ const supports = row2.constraints.supports ?? [];
6547
6838
  for (const key of INPUT_SPEC_SUPPORTS_KEYS) {
6548
6839
  if (supports.includes(key)) continue;
6549
6840
  if (key in spec.fields) {
@@ -6588,8 +6879,8 @@ function listIssues(name, values, fallback, defaultKey) {
6588
6879
  }
6589
6880
  return issues;
6590
6881
  }
6591
- function optionListIssues(row) {
6592
- const { constraints, defaults } = row;
6882
+ function optionListIssues(row2) {
6883
+ const { constraints, defaults } = row2;
6593
6884
  const issues = [
6594
6885
  ...listIssues(
6595
6886
  "voices",
@@ -6647,7 +6938,8 @@ var ModelTypeSchema = import_zod3.z.enum([
6647
6938
  "voice-change",
6648
6939
  "dubbing",
6649
6940
  "lipsync",
6650
- "transcription"
6941
+ "transcription",
6942
+ "model3d"
6651
6943
  ]);
6652
6944
  var LifecycleSchema = import_zod3.z.enum(["active", "deprecated", "retired"]);
6653
6945
  var SurfaceSchema = import_zod3.z.enum(["cowork", "space_builder"]);
@@ -6711,7 +7003,8 @@ var UsageUnitSchema = import_zod3.z.enum([
6711
7003
  "images",
6712
7004
  "seconds",
6713
7005
  "reported_cost_usd",
6714
- "compute_seconds"
7006
+ "compute_seconds",
7007
+ "requests"
6715
7008
  ]);
6716
7009
  var PricingKindSchema = import_zod3.z.enum(["token", "image_size", "video_per_second", "flat"]);
6717
7010
  var ProviderOptionValueSchema = import_zod3.z.lazy(
@@ -6765,6 +7058,156 @@ var LanguageOptionSchema = import_zod3.z.looseObject({
6765
7058
  code: import_zod3.z.string().min(1),
6766
7059
  name: import_zod3.z.string().min(1)
6767
7060
  });
7061
+ var MODEL3D_FAMILY_RULES = {
7062
+ trellis: {
7063
+ textPath: false,
7064
+ views: ["none"],
7065
+ multiImage: false,
7066
+ texture: null,
7067
+ pbr: false,
7068
+ seed: true,
7069
+ textureRef: false,
7070
+ resolutions: "integer"
7071
+ },
7072
+ hunyuan: {
7073
+ textPath: true,
7074
+ views: ["none", "named"],
7075
+ multiImage: false,
7076
+ texture: ["none", "standard"],
7077
+ pbr: true,
7078
+ seed: false,
7079
+ textureRef: false,
7080
+ resolutions: null
7081
+ },
7082
+ tripo: {
7083
+ textPath: true,
7084
+ views: ["none", "ordered"],
7085
+ multiImage: true,
7086
+ texture: ["none", "standard", "detailed"],
7087
+ pbr: true,
7088
+ seed: true,
7089
+ textureRef: false,
7090
+ resolutions: null
7091
+ },
7092
+ rodin: {
7093
+ textPath: true,
7094
+ views: ["none", "unordered"],
7095
+ multiImage: false,
7096
+ texture: null,
7097
+ pbr: false,
7098
+ seed: true,
7099
+ textureRef: false,
7100
+ resolutions: null
7101
+ },
7102
+ meshy: {
7103
+ textPath: true,
7104
+ views: ["none", "unordered"],
7105
+ multiImage: true,
7106
+ texture: ["none", "standard"],
7107
+ pbr: true,
7108
+ seed: true,
7109
+ textureRef: true,
7110
+ resolutions: null
7111
+ },
7112
+ hi3d: {
7113
+ textPath: false,
7114
+ views: ["none", "named"],
7115
+ multiImage: true,
7116
+ texture: ["none", "standard"],
7117
+ pbr: true,
7118
+ seed: false,
7119
+ textureRef: false,
7120
+ resolutions: ["quality", "master"]
7121
+ },
7122
+ sam: {
7123
+ textPath: false,
7124
+ views: ["none"],
7125
+ multiImage: false,
7126
+ texture: null,
7127
+ pbr: false,
7128
+ seed: true,
7129
+ textureRef: false,
7130
+ resolutions: null
7131
+ }
7132
+ };
7133
+ function model3dSpecIssues(spec) {
7134
+ const issues = [];
7135
+ const add = (path, message) => issues.push({ path, message });
7136
+ const rules = MODEL3D_FAMILY_RULES[spec.family];
7137
+ const promptOnly = spec.text && !spec.imageRequired;
7138
+ if (spec.endpoints.image === void 0)
7139
+ add(["endpoints", "image"], "every row needs an image endpoint");
7140
+ if (promptOnly && !rules.textPath) {
7141
+ add(
7142
+ ["imageRequired"],
7143
+ `${spec.family} has no text-to-3D endpoint; a text row needs an image`
7144
+ );
7145
+ }
7146
+ if (promptOnly && spec.endpoints.text === void 0) {
7147
+ add(["endpoints", "text"], "a text row needs a text endpoint");
7148
+ }
7149
+ if (!rules.views.includes(spec.views)) {
7150
+ add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
7151
+ }
7152
+ if (spec.views === "none" && spec.maxImages !== 1) {
7153
+ add(["maxImages"], "a row without views takes 1 image");
7154
+ }
7155
+ if (spec.views === "unordered" && spec.maxImages < 2) {
7156
+ add(["maxImages"], "a row with views takes at least 2 images");
7157
+ }
7158
+ const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
7159
+ if (spec.views !== "none" && spec.maxImages > slots) {
7160
+ add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
7161
+ }
7162
+ if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
7163
+ add(
7164
+ ["maxImages"],
7165
+ `a row with ${spec.views} views takes ${slots} images (front and three sides)`
7166
+ );
7167
+ }
7168
+ if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
7169
+ add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
7170
+ }
7171
+ if (rules.texture === null) {
7172
+ if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
7173
+ } else {
7174
+ const allowed = rules.texture;
7175
+ if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
7176
+ if (new Set(spec.texture).size !== spec.texture.length)
7177
+ add(["texture"], "texture options repeat");
7178
+ for (const t of spec.texture) {
7179
+ if (!allowed.includes(t)) add(["texture"], `${spec.family} has no "${t}" texture`);
7180
+ }
7181
+ }
7182
+ if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
7183
+ if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
7184
+ add(["pbr"], "PBR needs a textured option");
7185
+ }
7186
+ if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
7187
+ if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
7188
+ if (spec.textureRef && !rules.textureRef)
7189
+ add(["textureRef"], `${spec.family} takes no texture reference`);
7190
+ const res = spec.resolutions;
7191
+ if (rules.resolutions === null) {
7192
+ if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
7193
+ } else if (res === void 0) {
7194
+ add(["resolutions"], `${spec.family} needs its resolution options`);
7195
+ } else {
7196
+ if (!res.options.includes(res.default)) {
7197
+ add(["resolutions", "default"], "default must be an option");
7198
+ }
7199
+ if (new Set(res.options).size !== res.options.length) {
7200
+ add(["resolutions", "options"], "resolution options repeat");
7201
+ }
7202
+ const allowed = rules.resolutions;
7203
+ for (const option of res.options) {
7204
+ const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : allowed.includes(option);
7205
+ if (!ok)
7206
+ add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
7207
+ }
7208
+ }
7209
+ return issues;
7210
+ }
6768
7211
  var VideoToolConstraintsSchema = import_zod3.z.looseObject({
6769
7212
  kind: import_zod3.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
6770
7213
  upscaleFactor: RangeSchema.optional(),
@@ -6781,6 +7224,30 @@ var VideoToolConstraintsSchema = import_zod3.z.looseObject({
6781
7224
  translationLanguages: import_zod3.z.array(import_zod3.z.string().min(1)).min(1).optional(),
6782
7225
  maxSecondsAbove1080p: import_zod3.z.number().positive().optional()
6783
7226
  });
7227
+ var Model3dTextureSchema = import_zod3.z.enum(["none", "standard", "detailed"]);
7228
+ var Model3dConstraintsSchema = import_zod3.z.looseObject({
7229
+ family: import_zod3.z.enum(["trellis", "hunyuan", "tripo", "rodin", "meshy", "hi3d", "sam"]),
7230
+ endpoints: import_zod3.z.looseObject({
7231
+ text: import_zod3.z.string().min(1).optional(),
7232
+ image: import_zod3.z.string().min(1).optional(),
7233
+ multiImage: import_zod3.z.string().min(1).optional()
7234
+ }),
7235
+ text: import_zod3.z.boolean(),
7236
+ imageRequired: import_zod3.z.boolean(),
7237
+ promptRequired: import_zod3.z.boolean().optional(),
7238
+ views: import_zod3.z.enum(["none", "unordered", "ordered", "named"]),
7239
+ maxImages: import_zod3.z.number().int().positive(),
7240
+ texture: import_zod3.z.array(Model3dTextureSchema),
7241
+ pbr: import_zod3.z.boolean(),
7242
+ textureRef: import_zod3.z.boolean(),
7243
+ seed: import_zod3.z.boolean(),
7244
+ seedMax: import_zod3.z.number().int().positive().optional(),
7245
+ resolutions: import_zod3.z.looseObject({
7246
+ label: import_zod3.z.string().min(1),
7247
+ options: import_zod3.z.array(import_zod3.z.string().min(1)).min(1),
7248
+ default: import_zod3.z.string().min(1)
7249
+ }).optional()
7250
+ });
6784
7251
  var ModelConstraintsSchema = import_zod3.z.looseObject({
6785
7252
  aspectRatios: import_zod3.z.array(AspectRatioSchema).optional(),
6786
7253
  sizes: import_zod3.z.array(ImageSizeSchema).optional(),
@@ -6808,6 +7275,7 @@ var ModelConstraintsSchema = import_zod3.z.looseObject({
6808
7275
  returns: import_zod3.z.enum(["new", "joined"]).optional()
6809
7276
  }).optional(),
6810
7277
  tool: VideoToolConstraintsSchema.optional(),
7278
+ model3d: Model3dConstraintsSchema.optional(),
6811
7279
  // Loose on purpose: the read path keeps a row whose value is invalid (the accessors in
6812
7280
  // conventions.ts read it as "not set"); CatalogModelSchema below rejects it on write.
6813
7281
  audio: import_zod3.z.unknown().optional(),
@@ -6923,29 +7391,47 @@ var CatalogModelSchemaBase = import_zod3.z.looseObject({
6923
7391
  pricingKind: PricingKindSchema,
6924
7392
  display: CatalogDisplaySchema.optional(),
6925
7393
  capabilities: CatalogCapabilitiesSchema.optional()
6926
- }).superRefine((row, ctx) => {
6927
- if (row.lifecycle === "active" && !row.display) {
7394
+ }).superRefine((row2, ctx) => {
7395
+ if (row2.lifecycle === "active" && !row2.display) {
6928
7396
  ctx.addIssue({
6929
7397
  code: "custom",
6930
7398
  path: ["display"],
6931
7399
  message: "active rows need display"
6932
7400
  });
6933
7401
  }
6934
- if (row.lifecycle === "active" && row.type === "text" && !row.capabilities?.contextWindow) {
7402
+ if (row2.lifecycle === "active" && row2.type === "text" && !row2.capabilities?.contextWindow) {
6935
7403
  ctx.addIssue({
6936
7404
  code: "custom",
6937
7405
  path: ["capabilities", "contextWindow"],
6938
7406
  message: "active text rows need contextWindow"
6939
7407
  });
6940
7408
  }
6941
- if (row.type === "video-tool" && row.constraints.tool === void 0) {
7409
+ if (row2.type === "video-tool" && row2.constraints.tool === void 0) {
6942
7410
  ctx.addIssue({
6943
7411
  code: "custom",
6944
7412
  path: ["constraints", "tool"],
6945
7413
  message: "video-tool rows need constraints.tool"
6946
7414
  });
6947
7415
  }
6948
- if (row.replacedBy !== void 0 && row.replacedBy === row.id) {
7416
+ if (row2.type === "model3d") {
7417
+ const spec = row2.constraints.model3d;
7418
+ if (spec === void 0) {
7419
+ ctx.addIssue({
7420
+ code: "custom",
7421
+ path: ["constraints", "model3d"],
7422
+ message: "model3d rows need constraints.model3d"
7423
+ });
7424
+ } else {
7425
+ for (const issue of model3dSpecIssues(spec)) {
7426
+ ctx.addIssue({
7427
+ code: "custom",
7428
+ path: ["constraints", "model3d", ...issue.path],
7429
+ message: issue.message
7430
+ });
7431
+ }
7432
+ }
7433
+ }
7434
+ if (row2.replacedBy !== void 0 && row2.replacedBy === row2.id) {
6949
7435
  ctx.addIssue({
6950
7436
  code: "custom",
6951
7437
  path: ["replacedBy"],
@@ -6954,8 +7440,8 @@ var CatalogModelSchemaBase = import_zod3.z.looseObject({
6954
7440
  }
6955
7441
  });
6956
7442
  var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
6957
- (row, ctx) => {
6958
- const transport = row.providerOptions?.["modelkit"]?.["transport"];
7443
+ (row2, ctx) => {
7444
+ const transport = row2.providerOptions?.["modelkit"]?.["transport"];
6959
7445
  if (transport !== void 0 && transport !== "direct" && transport !== "bedrock") {
6960
7446
  ctx.addIssue({
6961
7447
  code: "custom",
@@ -6963,9 +7449,9 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
6963
7449
  message: 'transport must be "direct" or "bedrock"'
6964
7450
  });
6965
7451
  }
6966
- const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
7452
+ const inputSpecRaw = row2.providerOptions?.["modelkit"]?.["inputSpec"];
6967
7453
  if (inputSpecRaw !== void 0) {
6968
- const result = validateInputSpec(inputSpecRaw, row);
7454
+ const result = validateInputSpec(inputSpecRaw, row2);
6969
7455
  if (!result.ok) {
6970
7456
  for (const issue of result.issues) {
6971
7457
  ctx.addIssue({
@@ -6976,7 +7462,7 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
6976
7462
  }
6977
7463
  }
6978
7464
  }
6979
- const audio = row.constraints.audio;
7465
+ const audio = row2.constraints.audio;
6980
7466
  if (audio !== void 0 && !AudioOutputSchema.safeParse(audio).success) {
6981
7467
  ctx.addIssue({
6982
7468
  code: "custom",
@@ -6984,7 +7470,7 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
6984
7470
  message: 'audio must be "always", "optional" or "never"'
6985
7471
  });
6986
7472
  }
6987
- const refs = row.constraints.references;
7473
+ const refs = row2.constraints.references;
6988
7474
  for (const kind of ["images", "videos", "audios"]) {
6989
7475
  const least = refs?.min?.[kind];
6990
7476
  const most = refs?.[kind];
@@ -6996,10 +7482,10 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
6996
7482
  });
6997
7483
  }
6998
7484
  }
6999
- for (const issue of optionListIssues(row)) {
7485
+ for (const issue of optionListIssues(row2)) {
7000
7486
  ctx.addIssue({ code: "custom", path: issue.path, message: issue.message });
7001
7487
  }
7002
- const prompt = row.constraints.prompt;
7488
+ const prompt = row2.constraints.prompt;
7003
7489
  if (prompt !== void 0) {
7004
7490
  const parsed = PromptConventionsSchema.safeParse(prompt);
7005
7491
  if (!parsed.success) {
@@ -7014,7 +7500,7 @@ var CatalogModelSchema = CatalogModelSchemaBase.superRefine(
7014
7500
  }
7015
7501
  }
7016
7502
  );
7017
- var CatalogSchema = import_zod3.z.array(CatalogModelSchemaBase.transform((row) => normaliseConventions(row).row)).superRefine((rows, ctx) => {
7503
+ var CatalogSchema = import_zod3.z.array(CatalogModelSchemaBase.transform((row2) => normaliseConventions(row2).row)).superRefine((rows, ctx) => {
7018
7504
  for (const issue of collisionIssues(rows)) {
7019
7505
  ctx.addIssue({
7020
7506
  code: "custom",
@@ -8017,7 +8503,7 @@ async function generateSeedanceVideo(req, ctx) {
8017
8503
  }
8018
8504
 
8019
8505
  // src/adapters/fal.ts
8020
- var import_zod18 = require("zod");
8506
+ var import_zod20 = require("zod");
8021
8507
  var import_client = require("@fal-ai/client");
8022
8508
 
8023
8509
  // src/adapters/fal-http.ts
@@ -8322,7 +8808,7 @@ async function passthroughVideoJob(ctx, endpoint, input, decode) {
8322
8808
  }
8323
8809
 
8324
8810
  // src/adapters/fal-video-tools.ts
8325
- var import_zod12 = require("zod");
8811
+ var import_zod13 = require("zod");
8326
8812
 
8327
8813
  // src/video-length.ts
8328
8814
  function tenths(seconds3) {
@@ -8413,28 +8899,99 @@ function subtitleFields(tool, options) {
8413
8899
  return out;
8414
8900
  }
8415
8901
 
8416
- // src/catalog/video-tools-spec.ts
8902
+ // src/adapters/fal-queue.ts
8417
8903
  var import_zod11 = require("zod");
8418
- var RangeSchema2 = import_zod11.z.object({ min: import_zod11.z.number(), max: import_zod11.z.number() });
8419
- var ToolSchema = import_zod11.z.object({
8420
- kind: import_zod11.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
8904
+ var FAL_QUEUE_ORIGIN = "https://queue.fal.run";
8905
+ var queueUrlSchema = import_zod11.z.url().refine((value) => new URL(value).origin === FAL_QUEUE_ORIGIN, {
8906
+ message: "not a fal queue URL"
8907
+ });
8908
+ var submitResponseSchema = import_zod11.z.object({
8909
+ request_id: import_zod11.z.string().min(1),
8910
+ status_url: queueUrlSchema,
8911
+ response_url: queueUrlSchema,
8912
+ cancel_url: queueUrlSchema
8913
+ });
8914
+ var statusResponseSchema = import_zod11.z.object({ status: import_zod11.z.string() });
8915
+ var falWebhookBodySchema = import_zod11.z.object({
8916
+ request_id: import_zod11.z.string().min(1),
8917
+ gateway_request_id: import_zod11.z.string().nullish(),
8918
+ status: import_zod11.z.enum(["OK", "ERROR"]),
8919
+ payload: JsonValueSchema.nullish(),
8920
+ error: import_zod11.z.string().nullish(),
8921
+ payload_error: JsonValueSchema.nullish()
8922
+ });
8923
+ async function queueFetch(ctx, url, method, body) {
8924
+ const payload = body === void 0 ? void 0 : JSON.stringify(body);
8925
+ try {
8926
+ if (ctx.routing.fal === "cloudflare-passthrough") {
8927
+ return await gatewayFetch(gatewayConfig(ctx), ctx.fetch, url, {
8928
+ method,
8929
+ ...payload !== void 0 && { body: payload }
8930
+ });
8931
+ }
8932
+ const falKey = ctx.keys.fal;
8933
+ if (!falKey) {
8934
+ throw new ModelKitError({
8935
+ code: "auth",
8936
+ message: "Missing API key for fal",
8937
+ provider: "fal",
8938
+ model: ctx.model.id,
8939
+ retryable: false
8940
+ });
8941
+ }
8942
+ return await ctx.fetch(url, {
8943
+ method,
8944
+ headers: {
8945
+ Authorization: `Key ${falKey}`,
8946
+ ...payload !== void 0 && { "Content-Type": "application/json" }
8947
+ },
8948
+ ...payload !== void 0 && { body: payload },
8949
+ ...ctx.signal !== void 0 && { signal: ctx.signal }
8950
+ });
8951
+ } catch (cause) {
8952
+ if (cause instanceof ModelKitError) throw cause;
8953
+ throw classifyThrown("fal", cause, ctx.model.id);
8954
+ }
8955
+ }
8956
+ async function readJson(ctx, res) {
8957
+ if (!res.ok) throw falError(res.status, await readBody(res), ctx.model.id);
8958
+ return JsonValueSchema.parse(await res.json());
8959
+ }
8960
+ function checkedQueueUrl(ctx, url, what) {
8961
+ if (!queueUrlSchema.safeParse(url).success) {
8962
+ throw new ModelKitError({
8963
+ code: "provider_rejected",
8964
+ message: `${what} submission carries a URL outside fal's queue`,
8965
+ provider: "fal",
8966
+ model: ctx.model.id,
8967
+ retryable: false
8968
+ });
8969
+ }
8970
+ return url;
8971
+ }
8972
+
8973
+ // src/catalog/video-tools-spec.ts
8974
+ var import_zod12 = require("zod");
8975
+ var RangeSchema2 = import_zod12.z.object({ min: import_zod12.z.number(), max: import_zod12.z.number() });
8976
+ var ToolSchema = import_zod12.z.object({
8977
+ kind: import_zod12.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
8421
8978
  upscaleFactor: RangeSchema2.optional(),
8422
- maxOutputLongEdge: import_zod11.z.number().positive().optional(),
8423
- prompt: import_zod11.z.boolean().optional(),
8979
+ maxOutputLongEdge: import_zod12.z.number().positive().optional(),
8980
+ prompt: import_zod12.z.boolean().optional(),
8424
8981
  fps: RangeSchema2.optional(),
8425
- outputFormats: import_zod11.z.array(import_zod11.z.enum(["h265", "prores", "exr"])).min(1).optional(),
8426
- maxOutputShortEdge: import_zod11.z.number().positive().optional(),
8427
- maxOutputFrames: import_zod11.z.number().positive().optional(),
8428
- minOutputFrames: import_zod11.z.number().positive().optional(),
8429
- maxOutputFps: import_zod11.z.number().positive().optional(),
8430
- presets: import_zod11.z.array(import_zod11.z.string().min(1)).min(1).optional(),
8431
- languages: import_zod11.z.array(import_zod11.z.string().min(1)).min(1).optional(),
8432
- translationLanguages: import_zod11.z.array(import_zod11.z.string().min(1)).min(1).optional(),
8433
- maxSecondsAbove1080p: import_zod11.z.number().positive().optional()
8982
+ outputFormats: import_zod12.z.array(import_zod12.z.enum(["h265", "prores", "exr"])).min(1).optional(),
8983
+ maxOutputShortEdge: import_zod12.z.number().positive().optional(),
8984
+ maxOutputFrames: import_zod12.z.number().positive().optional(),
8985
+ minOutputFrames: import_zod12.z.number().positive().optional(),
8986
+ maxOutputFps: import_zod12.z.number().positive().optional(),
8987
+ presets: import_zod12.z.array(import_zod12.z.string().min(1)).min(1).optional(),
8988
+ languages: import_zod12.z.array(import_zod12.z.string().min(1)).min(1).optional(),
8989
+ translationLanguages: import_zod12.z.array(import_zod12.z.string().min(1)).min(1).optional(),
8990
+ maxSecondsAbove1080p: import_zod12.z.number().positive().optional()
8434
8991
  });
8435
- function videoToolConstraints(row) {
8436
- if (row.type !== "video-tool") return void 0;
8437
- const parsed = ToolSchema.safeParse(row.constraints.tool);
8992
+ function videoToolConstraints(row2) {
8993
+ if (row2.type !== "video-tool") return void 0;
8994
+ const parsed = ToolSchema.safeParse(row2.constraints.tool);
8438
8995
  if (!parsed.success) return void 0;
8439
8996
  const {
8440
8997
  kind,
@@ -8481,16 +9038,16 @@ function resolutionTier(width, height) {
8481
9038
  function fail(error) {
8482
9039
  return { ok: false, error };
8483
9040
  }
8484
- function planVideoTool(row, req) {
8485
- const tool = videoToolConstraints(row);
8486
- if (!tool) return fail(`${row.id} is not a video tool`);
9041
+ function planVideoTool(row2, req) {
9042
+ const tool = videoToolConstraints(row2);
9043
+ if (!tool) return fail(`${row2.id} is not a video tool`);
8487
9044
  const { width, height, durationSeconds, fps } = req.source;
8488
9045
  if (!(width > 0 && height > 0 && durationSeconds > 0)) {
8489
9046
  return fail("The source video's width, height and duration are required");
8490
9047
  }
8491
- const maxSeconds = row.constraints.sourceVideoSeconds?.max;
9048
+ const maxSeconds = row2.constraints.sourceVideoSeconds?.max;
8492
9049
  if (maxSeconds !== void 0 && overMax(durationSeconds, maxSeconds)) {
8493
- return fail(`${row.label} takes source videos up to ${maxSeconds} seconds.`);
9050
+ return fail(`${row2.label} takes source videos up to ${maxSeconds} seconds.`);
8494
9051
  }
8495
9052
  const base = {
8496
9053
  durationSeconds,
@@ -8501,7 +9058,7 @@ function planVideoTool(row, req) {
8501
9058
  if (factor === void 0) return fail("An upscale factor is required");
8502
9059
  const range2 = tool.upscaleFactor;
8503
9060
  if (range2 && (factor < range2.min || factor > range2.max)) {
8504
- return fail(`${row.label} upscales by ${range2.min}x to ${range2.max}x.`);
9061
+ return fail(`${row2.label} upscales by ${range2.min}x to ${range2.max}x.`);
8505
9062
  }
8506
9063
  const outWidth = Math.round(width * factor);
8507
9064
  const outHeight = Math.round(height * factor);
@@ -8529,7 +9086,7 @@ function planVideoTool(row, req) {
8529
9086
  }
8530
9087
  const range2 = tool.fps;
8531
9088
  if (range2 && (target < range2.min || target > range2.max)) {
8532
- return fail(`${row.label} outputs ${range2.min} to ${range2.max} fps.`);
9089
+ return fail(`${row2.label} outputs ${range2.min} to ${range2.max} fps.`);
8533
9090
  }
8534
9091
  return {
8535
9092
  ok: true,
@@ -8558,7 +9115,7 @@ function planVideoTool(row, req) {
8558
9115
  if (tool.kind === "subtitles") {
8559
9116
  const resolution = resolutionTier(width, height);
8560
9117
  const problem = subtitleProblem(
8561
- row.label,
9118
+ row2.label,
8562
9119
  tool,
8563
9120
  req.subtitles,
8564
9121
  resolution,
@@ -8570,9 +9127,9 @@ function planVideoTool(row, req) {
8570
9127
  const formats = tool.outputFormats ?? ["h265"];
8571
9128
  const format = req.outputFormat ?? formats[0] ?? "h265";
8572
9129
  if (!formats.includes(format)) {
8573
- return fail(`${row.label} writes ${formats.join(" or ")}.`);
9130
+ return fail(`${row2.label} writes ${formats.join(" or ")}.`);
8574
9131
  }
8575
- const timing = renderedTiming(row, tool, durationSeconds, fps);
9132
+ const timing = renderedTiming(row2, tool, durationSeconds, fps);
8576
9133
  if (!timing.ok) return fail(timing.error);
8577
9134
  const out = shrinkToShortEdge(width, height, tool.maxOutputShortEdge);
8578
9135
  return {
@@ -8588,7 +9145,7 @@ function planVideoTool(row, req) {
8588
9145
  };
8589
9146
  }
8590
9147
  var DEFAULT_FPS = 24;
8591
- function renderedTiming(row, tool, durationSeconds, fps) {
9148
+ function renderedTiming(row2, tool, durationSeconds, fps) {
8592
9149
  const { maxOutputFps, minOutputFrames, maxOutputFrames } = tool;
8593
9150
  if (maxOutputFps === void 0 && minOutputFrames === void 0 && maxOutputFrames === void 0) {
8594
9151
  return fps !== void 0 ? { ok: true, fps } : { ok: true };
@@ -8597,7 +9154,7 @@ function renderedTiming(row, tool, durationSeconds, fps) {
8597
9154
  const frames = Math.max(minOutputFrames ?? 1, Math.round(durationSeconds * rate));
8598
9155
  if (maxOutputFrames !== void 0 && frames > maxOutputFrames) {
8599
9156
  const limit = `${maxOutputFrames} frames (${seconds(maxOutputFrames, rate)})`;
8600
- return { ok: false, error: `${row.label} renders up to ${limit}.` };
9157
+ return { ok: false, error: `${row2.label} renders up to ${limit}.` };
8601
9158
  }
8602
9159
  return { ok: true, fps: rate, frames, durationSeconds: frames / rate };
8603
9160
  }
@@ -8612,76 +9169,20 @@ function shrinkToShortEdge(width, height, limit) {
8612
9169
  }
8613
9170
 
8614
9171
  // src/adapters/fal-video-tools.ts
8615
- var FAL_QUEUE_ORIGIN = "https://queue.fal.run";
8616
- var queueUrlSchema = import_zod12.z.url().refine((value) => new URL(value).origin === FAL_QUEUE_ORIGIN, {
8617
- message: "not a fal queue URL"
8618
- });
8619
- var submitResponseSchema = import_zod12.z.object({
8620
- request_id: import_zod12.z.string().min(1),
8621
- status_url: queueUrlSchema,
8622
- response_url: queueUrlSchema,
8623
- cancel_url: queueUrlSchema
9172
+ var videoFileSchema = import_zod13.z.object({
9173
+ url: import_zod13.z.url(),
9174
+ content_type: import_zod13.z.string().nullish(),
9175
+ file_size: import_zod13.z.number().nullish()
8624
9176
  });
8625
- var statusResponseSchema = import_zod12.z.object({ status: import_zod12.z.string() });
8626
- var videoFileSchema = import_zod12.z.object({
8627
- url: import_zod12.z.url(),
8628
- content_type: import_zod12.z.string().nullish(),
8629
- file_size: import_zod12.z.number().nullish()
9177
+ var toolOutputSchema = import_zod13.z.object({
9178
+ video: import_zod13.z.union([videoFileSchema, import_zod13.z.array(videoFileSchema).min(1)])
8630
9179
  });
8631
- var toolOutputSchema = import_zod12.z.object({
8632
- video: import_zod12.z.union([videoFileSchema, import_zod12.z.array(videoFileSchema).min(1)])
8633
- });
8634
- var exrOutputSchema = import_zod12.z.object({
9180
+ var exrOutputSchema = import_zod13.z.object({
8635
9181
  preview_video: videoFileSchema,
8636
9182
  exr_frames_url: videoFileSchema
8637
9183
  });
8638
- var falWebhookBodySchema = import_zod12.z.object({
8639
- request_id: import_zod12.z.string().min(1),
8640
- gateway_request_id: import_zod12.z.string().nullish(),
8641
- status: import_zod12.z.enum(["OK", "ERROR"]),
8642
- payload: JsonValueSchema.nullish(),
8643
- error: import_zod12.z.string().nullish(),
8644
- payload_error: JsonValueSchema.nullish()
8645
- });
8646
- async function queueFetch(ctx, url, method, body) {
8647
- const payload = body === void 0 ? void 0 : JSON.stringify(body);
8648
- try {
8649
- if (ctx.routing.fal === "cloudflare-passthrough") {
8650
- return await gatewayFetch(gatewayConfig(ctx), ctx.fetch, url, {
8651
- method,
8652
- ...payload !== void 0 && { body: payload }
8653
- });
8654
- }
8655
- const falKey = ctx.keys.fal;
8656
- if (!falKey) {
8657
- throw new ModelKitError({
8658
- code: "auth",
8659
- message: "Missing API key for fal",
8660
- provider: "fal",
8661
- model: ctx.model.id,
8662
- retryable: false
8663
- });
8664
- }
8665
- return await ctx.fetch(url, {
8666
- method,
8667
- headers: {
8668
- Authorization: `Key ${falKey}`,
8669
- ...payload !== void 0 && { "Content-Type": "application/json" }
8670
- },
8671
- ...payload !== void 0 && { body: payload },
8672
- ...ctx.signal !== void 0 && { signal: ctx.signal }
8673
- });
8674
- } catch (cause) {
8675
- if (cause instanceof ModelKitError) throw cause;
8676
- throw classifyThrown("fal", cause, ctx.model.id);
8677
- }
8678
- }
8679
- async function readJson(ctx, res) {
8680
- if (!res.ok) throw falError(res.status, await readBody(res), ctx.model.id);
8681
- return JsonValueSchema.parse(await res.json());
8682
- }
8683
9184
  function providerModelName(ctx) {
8684
- return import_zod12.z.string().safeParse(ctx.model.providerOptions?.["fal"]?.["model"]).data;
9185
+ return import_zod13.z.string().safeParse(ctx.model.providerOptions?.["fal"]?.["model"]).data;
8685
9186
  }
8686
9187
  function staticInput(ctx) {
8687
9188
  return JsonObjectSchema.safeParse(ctx.model.providerOptions?.["fal"]?.["input"]).data ?? {};
@@ -8752,20 +9253,8 @@ async function submitFalVideoTool(req, ctx, opts) {
8752
9253
  output: plan3.output
8753
9254
  };
8754
9255
  }
8755
- function checkedQueueUrl(ctx, url) {
8756
- if (!queueUrlSchema.safeParse(url).success) {
8757
- throw new ModelKitError({
8758
- code: "provider_rejected",
8759
- message: "Video-tool submission carries a URL outside fal's queue",
8760
- provider: "fal",
8761
- model: ctx.model.id,
8762
- retryable: false
8763
- });
8764
- }
8765
- return url;
8766
- }
8767
9256
  async function falVideoToolStatus(sub, ctx) {
8768
- const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.statusUrl), "GET");
9257
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.statusUrl, "Video-tool"), "GET");
8769
9258
  const { status } = statusResponseSchema.parse(await readJson(ctx, res));
8770
9259
  if (status === "IN_QUEUE") return "queued";
8771
9260
  if (status === "COMPLETED") return "completed";
@@ -8862,18 +9351,18 @@ async function falVideoToolResult(sub, ctx, webhook) {
8862
9351
  }
8863
9352
  return resultOf(ctx, sub, webhook.payload);
8864
9353
  }
8865
- const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.responseUrl), "GET");
9354
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.responseUrl, "Video-tool"), "GET");
8866
9355
  return resultOf(ctx, sub, await readJson(ctx, res));
8867
9356
  }
8868
9357
  async function cancelFalVideoTool(sub, ctx) {
8869
- const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.cancelUrl), "PUT");
9358
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.cancelUrl, "Video-tool"), "PUT");
8870
9359
  if (res.ok) return true;
8871
9360
  if (res.status === 400) return false;
8872
9361
  throw falError(res.status, await readBody(res), ctx.model.id);
8873
9362
  }
8874
9363
 
8875
9364
  // src/adapters/fal-image.ts
8876
- var import_zod13 = require("zod");
9365
+ var import_zod14 = require("zod");
8877
9366
 
8878
9367
  // src/resolve-image-rules.ts
8879
9368
  var WIDE_RATIOS = [
@@ -9459,9 +9948,9 @@ function planFalImage(req, providerModelId, model) {
9459
9948
  if (built.imageSize !== void 0) plan3.imageSize = built.imageSize;
9460
9949
  return plan3;
9461
9950
  }
9462
- var FalFileSchema = import_zod13.z.object({ url: import_zod13.z.string(), content_type: import_zod13.z.string().nullish() });
9463
- var ImagesPayloadSchema = import_zod13.z.object({ images: import_zod13.z.array(FalFileSchema) });
9464
- var ImagePayloadSchema = import_zod13.z.object({ image: FalFileSchema });
9951
+ var FalFileSchema = import_zod14.z.object({ url: import_zod14.z.string(), content_type: import_zod14.z.string().nullish() });
9952
+ var ImagesPayloadSchema = import_zod14.z.object({ images: import_zod14.z.array(FalFileSchema) });
9953
+ var ImagePayloadSchema = import_zod14.z.object({ image: FalFileSchema });
9465
9954
  function decodeDataUri(url) {
9466
9955
  const comma = url.indexOf(",");
9467
9956
  const meta = url.slice(5, comma);
@@ -9520,15 +10009,15 @@ async function generateFalFamilyImage(req, ctx, run) {
9520
10009
  }
9521
10010
 
9522
10011
  // src/adapters/fal-mask.ts
9523
- var import_zod14 = require("zod");
10012
+ var import_zod15 = require("zod");
9524
10013
  var SAM3_IMAGE = "fal-ai/sam-3/image";
9525
10014
  var MAX_MASKS = 32;
9526
- function fail3(row, message, code) {
10015
+ function fail3(row2, message, code) {
9527
10016
  return new ModelKitError({
9528
10017
  code,
9529
- message: `${row.label}: ${message}`,
10018
+ message: `${row2.label}: ${message}`,
9530
10019
  provider: "fal",
9531
- model: row.id,
10020
+ model: row2.id,
9532
10021
  retryable: false
9533
10022
  });
9534
10023
  }
@@ -9538,22 +10027,22 @@ function pointPrompts(points) {
9538
10027
  function boxPrompts(boxes) {
9539
10028
  return boxes.map((b) => ({ x_min: b.xMin, y_min: b.yMin, x_max: b.xMax, y_max: b.yMax }));
9540
10029
  }
9541
- function planFalMask(row, req) {
9542
- if (row.providerModelId !== SAM3_IMAGE) {
10030
+ function planFalMask(row2, req) {
10031
+ if (row2.providerModelId !== SAM3_IMAGE) {
9543
10032
  throw fail3(
9544
- row,
9545
- `fal has no mask mapper for "${row.providerModelId}"`,
10033
+ row2,
10034
+ `fal has no mask mapper for "${row2.providerModelId}"`,
9546
10035
  "unsupported_option"
9547
10036
  );
9548
10037
  }
9549
10038
  const refs = req.references ?? [];
9550
10039
  const [image] = refs;
9551
- if (image === void 0) throw fail3(row, "needs one source image", "missing_input");
10040
+ if (image === void 0) throw fail3(row2, "needs one source image", "missing_input");
9552
10041
  if (refs.length > 1) {
9553
- throw fail3(row, `takes one source image; got ${refs.length}`, "unsupported_option");
10042
+ throw fail3(row2, `takes one source image; got ${refs.length}`, "unsupported_option");
9554
10043
  }
9555
10044
  const problem = maskProblem(req);
9556
- if (problem !== void 0) throw fail3(row, problem.message, problem.code);
10045
+ if (problem !== void 0) throw fail3(row2, problem.message, problem.code);
9557
10046
  const input = {
9558
10047
  image_url: refToUrl(image),
9559
10048
  prompt: req.prompt.trim(),
@@ -9570,17 +10059,17 @@ function planFalMask(row, req) {
9570
10059
  }
9571
10060
  return { endpoint: SAM3_IMAGE, input };
9572
10061
  }
9573
- var masksSchema = import_zod14.z.object({
9574
- masks: import_zod14.z.array(import_zod14.z.object({ url: import_zod14.z.string().min(1), content_type: import_zod14.z.string().nullish() }))
10062
+ var masksSchema = import_zod15.z.object({
10063
+ masks: import_zod15.z.array(import_zod15.z.object({ url: import_zod15.z.string().min(1), content_type: import_zod15.z.string().nullish() }))
9575
10064
  });
9576
- function parseFalMasks(row, payload) {
10065
+ function parseFalMasks(row2, payload) {
9577
10066
  const parsed = masksSchema.safeParse(payload);
9578
10067
  if (!parsed.success) {
9579
10068
  throw new ModelKitError({
9580
10069
  code: "provider_rejected",
9581
10070
  message: `fal ${SAM3_IMAGE} returned no mask list`,
9582
10071
  provider: "fal",
9583
- model: row.id,
10072
+ model: row2.id,
9584
10073
  retryable: false
9585
10074
  });
9586
10075
  }
@@ -9613,7 +10102,7 @@ async function generateFalMask(req, ctx, run) {
9613
10102
  }
9614
10103
 
9615
10104
  // src/adapters/fal-audio-plan.ts
9616
- var import_zod15 = require("zod");
10105
+ var import_zod16 = require("zod");
9617
10106
  var ELEVENLABS_MUSIC = FAL_AUDIO.elevenLabsMusic;
9618
10107
  var MINIMAX_MUSIC_32 = FAL_AUDIO.minimaxMusic;
9619
10108
  var ELEVENLABS_SFX = FAL_AUDIO.elevenLabsSfx;
@@ -9660,65 +10149,65 @@ var FAL_MEDIA_TYPES = /* @__PURE__ */ new Set([
9660
10149
  function isFalMediaKnown(type, providerModelId) {
9661
10150
  return KNOWN[type]?.has(providerModelId) ?? false;
9662
10151
  }
9663
- function falMediaError(row, message, code) {
10152
+ function falMediaError(row2, message, code) {
9664
10153
  return new ModelKitError({
9665
10154
  code,
9666
- message: `${row.label}: ${message}`,
10155
+ message: `${row2.label}: ${message}`,
9667
10156
  provider: "fal",
9668
- model: row.id,
10157
+ model: row2.id,
9669
10158
  retryable: false
9670
10159
  });
9671
10160
  }
9672
- function refuseMedia(row, present) {
9673
- const extra = Object.entries(present).find(([, set]) => set);
9674
- if (extra) throw falMediaError(row, `does not take ${extra[0]}`, "unsupported_option");
10161
+ function refuseMedia(row2, present2) {
10162
+ const extra = Object.entries(present2).find(([, set]) => set);
10163
+ if (extra) throw falMediaError(row2, `does not take ${extra[0]}`, "unsupported_option");
9675
10164
  }
9676
10165
  function setIf(input, key, value) {
9677
10166
  if (value !== void 0) input[key] = value;
9678
10167
  }
9679
- function unmapped(row) {
10168
+ function unmapped(row2) {
9680
10169
  return falMediaError(
9681
- row,
9682
- `fal has no ${row.type} mapper for "${row.providerModelId}"`,
10170
+ row2,
10171
+ `fal has no ${row2.type} mapper for "${row2.providerModelId}"`,
9683
10172
  "unsupported_option"
9684
10173
  );
9685
10174
  }
9686
- function mediaUrl(row, field, ref) {
9687
- if (ref === void 0) throw falMediaError(row, `needs ${field}`, "missing_input");
10175
+ function mediaUrl(row2, field, ref) {
10176
+ if (ref === void 0) throw falMediaError(row2, `needs ${field}`, "missing_input");
9688
10177
  return refToUrl(ref);
9689
10178
  }
9690
10179
  function trimmed(text2) {
9691
10180
  const value = text2?.trim();
9692
10181
  return value ? value : void 0;
9693
10182
  }
9694
- function requireText(row, text2, what) {
10183
+ function requireText(row2, text2, what) {
9695
10184
  const value = trimmed(text2);
9696
- if (value === void 0) throw falMediaError(row, `needs ${what}`, "missing_input");
10185
+ if (value === void 0) throw falMediaError(row2, `needs ${what}`, "missing_input");
9697
10186
  return value;
9698
10187
  }
9699
- function planMirelo(row, req) {
9700
- const id = row.providerModelId;
10188
+ function planMirelo(row2, req) {
10189
+ const id = row2.providerModelId;
9701
10190
  const input = { num_samples: 1 };
9702
10191
  setIf(input, "duration", req.durationSeconds);
9703
10192
  setIf(input, "negative_prompt", req.negativePrompt);
9704
10193
  setIf(input, "seed", req.seed);
9705
10194
  setIf(input, "upload_audio_format", req.outputFormat);
9706
10195
  if (id === MIRELO_VIDEO) {
9707
- input["video_url"] = mediaUrl(row, "sourceVideo", req.sourceVideo);
10196
+ input["video_url"] = mediaUrl(row2, "sourceVideo", req.sourceVideo);
9708
10197
  setIf(input, "text_prompt", trimmed(req.prompt));
9709
10198
  return { endpoint: id, input };
9710
10199
  }
9711
10200
  input["prompt"] = req.prompt.trim();
9712
10201
  return { endpoint: id, input };
9713
10202
  }
9714
- function planFalAudio(row, req) {
9715
- if (row.type !== "audio" && row.type !== "sound-effect") {
9716
- throw falMediaError(row, `${row.type} rows do not generate audio`, "unsupported_option");
10203
+ function planFalAudio(row2, req) {
10204
+ if (row2.type !== "audio" && row2.type !== "sound-effect") {
10205
+ throw falMediaError(row2, `${row2.type} rows do not generate audio`, "unsupported_option");
9717
10206
  }
9718
- const id = row.providerModelId;
10207
+ const id = row2.providerModelId;
9719
10208
  const problem = falAudioProblem(id, req);
9720
- if (problem !== void 0) throw falMediaError(row, problem.message, problem.code);
9721
- if (id === MIRELO_TEXT || id === MIRELO_VIDEO) return planMirelo(row, req);
10209
+ if (problem !== void 0) throw falMediaError(row2, problem.message, problem.code);
10210
+ if (id === MIRELO_TEXT || id === MIRELO_VIDEO) return planMirelo(row2, req);
9722
10211
  const prompt = req.prompt.trim();
9723
10212
  if (id === ELEVENLABS_MUSIC) {
9724
10213
  const input = { prompt };
@@ -9743,12 +10232,12 @@ function planFalAudio(row, req) {
9743
10232
  setIf(input, "output_format", req.outputFormat);
9744
10233
  return { endpoint: id, input };
9745
10234
  }
9746
- throw unmapped(row);
10235
+ throw unmapped(row2);
9747
10236
  }
9748
- function planFalSpeech(row, req) {
9749
- const id = row.providerModelId;
9750
- if (row.type !== "speech") throw unmapped(row);
9751
- const script = requireText(row, req.text, "text");
10237
+ function planFalSpeech(row2, req) {
10238
+ const id = row2.providerModelId;
10239
+ if (row2.type !== "speech") throw unmapped(row2);
10240
+ const script = requireText(row2, req.text, "text");
9752
10241
  if (ELEVENLABS_TTS.has(id)) {
9753
10242
  const input = { text: script };
9754
10243
  setIf(input, "voice", req.voice);
@@ -9768,31 +10257,31 @@ function planFalSpeech(row, req) {
9768
10257
  setIf(input, "language_boost", req.language);
9769
10258
  return { endpoint: id, input };
9770
10259
  }
9771
- throw unmapped(row);
10260
+ throw unmapped(row2);
9772
10261
  }
9773
- function planFalVoiceChange(row, req) {
9774
- if (row.type !== "voice-change" || row.providerModelId !== VOICE_CHANGER) throw unmapped(row);
9775
- const input = { audio_url: mediaUrl(row, "sourceAudio", req.sourceAudio) };
10262
+ function planFalVoiceChange(row2, req) {
10263
+ if (row2.type !== "voice-change" || row2.providerModelId !== VOICE_CHANGER) throw unmapped(row2);
10264
+ const input = { audio_url: mediaUrl(row2, "sourceAudio", req.sourceAudio) };
9776
10265
  setIf(input, "voice", req.voice);
9777
10266
  setIf(input, "output_format", req.outputFormat);
9778
10267
  return { endpoint: VOICE_CHANGER, input };
9779
10268
  }
9780
- var fileSchema = import_zod15.z.object({
9781
- url: import_zod15.z.string().min(1),
9782
- content_type: import_zod15.z.string().nullish()
10269
+ var fileSchema = import_zod16.z.object({
10270
+ url: import_zod16.z.string().min(1),
10271
+ content_type: import_zod16.z.string().nullish()
9783
10272
  });
9784
- var audioOutputSchema = import_zod15.z.object({
9785
- audio: import_zod15.z.union([fileSchema, import_zod15.z.array(fileSchema).min(1)]),
9786
- duration: import_zod15.z.number().nullish(),
9787
- duration_ms: import_zod15.z.number().nullish(),
9788
- lyrics: import_zod15.z.string().nullish()
10273
+ var audioOutputSchema = import_zod16.z.object({
10274
+ audio: import_zod16.z.union([fileSchema, import_zod16.z.array(fileSchema).min(1)]),
10275
+ duration: import_zod16.z.number().nullish(),
10276
+ duration_ms: import_zod16.z.number().nullish(),
10277
+ lyrics: import_zod16.z.string().nullish()
9789
10278
  });
9790
- function noFalOutput(row, what, endpoint) {
10279
+ function noFalOutput(row2, what, endpoint) {
9791
10280
  return new ModelKitError({
9792
10281
  code: "provider_rejected",
9793
10282
  message: `fal ${endpoint} returned no ${what}`,
9794
10283
  provider: "fal",
9795
- model: row.id,
10284
+ model: row2.id,
9796
10285
  retryable: false
9797
10286
  });
9798
10287
  }
@@ -9800,12 +10289,12 @@ function reportedSeconds(seconds3, ms) {
9800
10289
  if (seconds3 != null) return seconds3;
9801
10290
  return ms != null ? ms / 1e3 : void 0;
9802
10291
  }
9803
- function parseFalAudio(row, endpoint, payload) {
10292
+ function parseFalAudio(row2, endpoint, payload) {
9804
10293
  const parsed = audioOutputSchema.safeParse(payload);
9805
- if (!parsed.success) throw noFalOutput(row, "audio", endpoint);
10294
+ if (!parsed.success) throw noFalOutput(row2, "audio", endpoint);
9806
10295
  const { audio, duration, duration_ms: durationMs, lyrics } = parsed.data;
9807
10296
  const file = Array.isArray(audio) ? audio[0] : audio;
9808
- if (file === void 0) throw noFalOutput(row, "audio", endpoint);
10297
+ if (file === void 0) throw noFalOutput(row2, "audio", endpoint);
9809
10298
  const seconds3 = reportedSeconds(duration, durationMs);
9810
10299
  return {
9811
10300
  url: file.url,
@@ -9816,114 +10305,114 @@ function parseFalAudio(row, endpoint, payload) {
9816
10305
  }
9817
10306
 
9818
10307
  // src/adapters/fal-media-plan.ts
9819
- var import_zod16 = require("zod");
10308
+ var import_zod17 = require("zod");
9820
10309
  var MINIMAX_LIPSYNC_RESOLUTIONS = {
9821
10310
  "480p": "480P",
9822
10311
  "768p": "768P",
9823
10312
  "1080p": "1080P",
9824
10313
  "2k": "2K"
9825
10314
  };
9826
- function syncModelName(row) {
9827
- return import_zod16.z.string().safeParse(row.providerOptions?.["fal"]?.["model"]).data;
10315
+ function syncModelName(row2) {
10316
+ return import_zod17.z.string().safeParse(row2.providerOptions?.["fal"]?.["model"]).data;
9828
10317
  }
9829
- function planFalLipsync(row, req) {
9830
- const id = row.providerModelId;
9831
- if (row.type !== "lipsync") throw unmapped(row);
9832
- const audio = mediaUrl(row, "audio", req.audio);
10318
+ function planFalLipsync(row2, req) {
10319
+ const id = row2.providerModelId;
10320
+ if (row2.type !== "lipsync") throw unmapped(row2);
10321
+ const audio = mediaUrl(row2, "audio", req.audio);
9833
10322
  if (id === FAL_LIPSYNC.minimax) {
9834
- refuseMedia(row, { sourceVideo: req.sourceVideo !== void 0 });
10323
+ refuseMedia(row2, { sourceVideo: req.sourceVideo !== void 0 });
9835
10324
  const input = {
9836
- image_url: mediaUrl(row, "image", req.image),
10325
+ image_url: mediaUrl(row2, "image", req.image),
9837
10326
  audio_url: audio
9838
10327
  };
9839
10328
  if (req.resolution !== void 0) {
9840
10329
  const resolution = MINIMAX_LIPSYNC_RESOLUTIONS[req.resolution];
9841
10330
  if (resolution === void 0) {
9842
- throw falMediaError(row, `does not render ${req.resolution}`, "unsupported_option");
10331
+ throw falMediaError(row2, `does not render ${req.resolution}`, "unsupported_option");
9843
10332
  }
9844
10333
  input["resolution"] = resolution;
9845
10334
  }
9846
10335
  return { endpoint: id, input };
9847
10336
  }
9848
- refuseMedia(row, { image: req.image !== void 0 });
9849
- const video = mediaUrl(row, "sourceVideo", req.sourceVideo);
10337
+ refuseMedia(row2, { image: req.image !== void 0 });
10338
+ const video = mediaUrl(row2, "sourceVideo", req.sourceVideo);
9850
10339
  if (id === FAL_LIPSYNC.veed) {
9851
10340
  return { endpoint: id, input: { video_url: video, audio_url: audio } };
9852
10341
  }
9853
10342
  if (id === FAL_LIPSYNC.syncV2 || id === FAL_LIPSYNC.syncV3) {
9854
10343
  const input = { video_url: video, audio_url: audio, sync_mode: "cut_off" };
9855
- const model = syncModelName(row);
10344
+ const model = syncModelName(row2);
9856
10345
  if (id === FAL_LIPSYNC.syncV2 && model !== void 0) input["model"] = model;
9857
10346
  return { endpoint: id, input };
9858
10347
  }
9859
- throw unmapped(row);
10348
+ throw unmapped(row2);
9860
10349
  }
9861
- function planFalDubbing(row, req) {
9862
- if (row.type !== "dubbing" || row.providerModelId !== FAL_DUBBING) throw unmapped(row);
10350
+ function planFalDubbing(row2, req) {
10351
+ if (row2.type !== "dubbing" || row2.providerModelId !== FAL_DUBBING) throw unmapped(row2);
9863
10352
  if (req.sourceVideo !== void 0 && req.sourceAudio !== void 0) {
9864
10353
  throw falMediaError(
9865
- row,
10354
+ row2,
9866
10355
  "takes sourceVideo or sourceAudio, not both",
9867
10356
  "unsupported_option"
9868
10357
  );
9869
10358
  }
9870
10359
  const target = req.targetLanguage.trim();
9871
- if (!target) throw falMediaError(row, "needs targetLanguage", "missing_input");
10360
+ if (!target) throw falMediaError(row2, "needs targetLanguage", "missing_input");
9872
10361
  const input = { target_lang: target };
9873
10362
  if (req.sourceVideo !== void 0) input["video_url"] = refToUrl(req.sourceVideo);
9874
- else input["audio_url"] = mediaUrl(row, "sourceVideo or sourceAudio", req.sourceAudio);
10363
+ else input["audio_url"] = mediaUrl(row2, "sourceVideo or sourceAudio", req.sourceAudio);
9875
10364
  return { endpoint: FAL_DUBBING, input };
9876
10365
  }
9877
- function planFalTranscription(row, req) {
9878
- if (row.type !== "transcription" || row.providerModelId !== FAL_SCRIBE) throw unmapped(row);
9879
- const input = { audio_url: mediaUrl(row, "source", req.source) };
10366
+ function planFalTranscription(row2, req) {
10367
+ if (row2.type !== "transcription" || row2.providerModelId !== FAL_SCRIBE) throw unmapped(row2);
10368
+ const input = { audio_url: mediaUrl(row2, "source", req.source) };
9880
10369
  setIf(input, "language_code", req.language?.trim() || void 0);
9881
10370
  return { endpoint: FAL_SCRIBE, input };
9882
10371
  }
9883
- var fileSchema2 = import_zod16.z.object({
9884
- url: import_zod16.z.string().min(1),
9885
- content_type: import_zod16.z.string().nullish()
10372
+ var fileSchema2 = import_zod17.z.object({
10373
+ url: import_zod17.z.string().min(1),
10374
+ content_type: import_zod17.z.string().nullish()
9886
10375
  });
9887
- var videoOutputSchema = import_zod16.z.object({
10376
+ var videoOutputSchema = import_zod17.z.object({
9888
10377
  video: fileSchema2,
9889
- duration: import_zod16.z.number().nullish()
10378
+ duration: import_zod17.z.number().nullish()
9890
10379
  });
9891
- var dubbingOutputSchema = import_zod16.z.object({
10380
+ var dubbingOutputSchema = import_zod17.z.object({
9892
10381
  video: fileSchema2.nullish(),
9893
10382
  audio: fileSchema2.nullish()
9894
10383
  });
9895
- var transcriptSchema = import_zod16.z.object({
9896
- text: import_zod16.z.string(),
9897
- language_code: import_zod16.z.string().nullish(),
9898
- words: import_zod16.z.array(
9899
- import_zod16.z.object({
9900
- text: import_zod16.z.string(),
9901
- type: import_zod16.z.string(),
9902
- start: import_zod16.z.number().nullish(),
9903
- end: import_zod16.z.number().nullish(),
9904
- speaker_id: import_zod16.z.string().nullish()
10384
+ var transcriptSchema = import_zod17.z.object({
10385
+ text: import_zod17.z.string(),
10386
+ language_code: import_zod17.z.string().nullish(),
10387
+ words: import_zod17.z.array(
10388
+ import_zod17.z.object({
10389
+ text: import_zod17.z.string(),
10390
+ type: import_zod17.z.string(),
10391
+ start: import_zod17.z.number().nullish(),
10392
+ end: import_zod17.z.number().nullish(),
10393
+ speaker_id: import_zod17.z.string().nullish()
9905
10394
  })
9906
10395
  ).nullish()
9907
10396
  });
9908
- function parseFalVideo(row, endpoint, payload) {
10397
+ function parseFalVideo(row2, endpoint, payload) {
9909
10398
  const parsed = videoOutputSchema.safeParse(payload);
9910
- if (!parsed.success) throw noFalOutput(row, "video", endpoint);
10399
+ if (!parsed.success) throw noFalOutput(row2, "video", endpoint);
9911
10400
  const { video, duration } = parsed.data;
9912
10401
  return { url: video.url, ...duration != null && { durationSeconds: duration } };
9913
10402
  }
9914
- function parseFalDubbing(row, kind, payload) {
10403
+ function parseFalDubbing(row2, kind, payload) {
9915
10404
  const parsed = dubbingOutputSchema.safeParse(payload);
9916
10405
  const file = parsed.success ? parsed.data[kind] : void 0;
9917
- if (file == null) throw noFalOutput(row, kind, FAL_DUBBING);
10406
+ if (file == null) throw noFalOutput(row2, kind, FAL_DUBBING);
9918
10407
  return {
9919
10408
  kind,
9920
10409
  url: file.url,
9921
10410
  ...file.content_type != null && { mime: file.content_type }
9922
10411
  };
9923
10412
  }
9924
- function parseFalTranscript(row, endpoint, payload) {
10413
+ function parseFalTranscript(row2, endpoint, payload) {
9925
10414
  const parsed = transcriptSchema.safeParse(payload);
9926
- if (!parsed.success) throw noFalOutput(row, "transcript", endpoint);
10415
+ if (!parsed.success) throw noFalOutput(row2, "transcript", endpoint);
9927
10416
  const words = (parsed.data.words ?? []).map(
9928
10417
  (w) => ({
9929
10418
  text: w.text,
@@ -10086,8 +10575,313 @@ async function transcribeFal(req, ctx, run) {
10086
10575
  };
10087
10576
  }
10088
10577
 
10578
+ // src/adapters/fal-model3d.ts
10579
+ var import_zod18 = require("zod");
10580
+ var fileSchema3 = import_zod18.z.object({
10581
+ url: import_zod18.z.url(),
10582
+ content_type: import_zod18.z.string().nullish(),
10583
+ file_size: import_zod18.z.number().nullish()
10584
+ });
10585
+ var resultSchema = import_zod18.z.looseObject({
10586
+ model_glb: fileSchema3.nullish(),
10587
+ model_mesh: fileSchema3.nullish(),
10588
+ thumbnail: fileSchema3.nullish(),
10589
+ rendered_image: fileSchema3.nullish()
10590
+ });
10591
+ function rejected(ctx, message) {
10592
+ return new ModelKitError({
10593
+ code: "provider_rejected",
10594
+ message,
10595
+ provider: "fal",
10596
+ model: ctx.model.id,
10597
+ retryable: false
10598
+ });
10599
+ }
10600
+ function specOf(ctx) {
10601
+ const spec = model3dConstraints(ctx.model);
10602
+ if (spec === void 0) {
10603
+ throw new ModelKitError({
10604
+ code: "unsupported_option",
10605
+ message: `${ctx.model.id} is not a 3D model`,
10606
+ model: ctx.model.id
10607
+ });
10608
+ }
10609
+ return spec;
10610
+ }
10611
+ var present = (v) => v !== void 0 && v.length > 0;
10612
+ function model3dCall(row2, spec, req) {
10613
+ const prompt = req.prompt?.trim() || void 0;
10614
+ const texture = model3dTexture(spec, req.texture);
10615
+ const textured = spec.texture.length > 0 && texture !== "none";
10616
+ const pbr = spec.pbr && textured && req.pbr === true;
10617
+ const resolution = model3dResolution(spec, req.resolution);
10618
+ const views = spec.views === "none" ? {} : req.views ?? {};
10619
+ const seed = spec.seed && req.seed !== void 0 ? req.seed : void 0;
10620
+ const endpoint = (path) => {
10621
+ if (path === void 0) {
10622
+ throw new ModelKitError({
10623
+ code: "unsupported_option",
10624
+ message: `${row2.id} has no endpoint for this request`,
10625
+ provider: "fal",
10626
+ model: row2.id,
10627
+ retryable: false
10628
+ });
10629
+ }
10630
+ return path;
10631
+ };
10632
+ const slotted = (kind) => MODEL3D_IMAGE_SLOTS[kind].map((slot) => slot === "image" ? req.image : views[slot]).filter(present).slice(0, spec.maxImages);
10633
+ const images = slotted("unordered");
10634
+ switch (spec.family) {
10635
+ case "trellis":
10636
+ return {
10637
+ endpoint: endpoint(spec.endpoints.image),
10638
+ input: {
10639
+ image_url: req.image ?? "",
10640
+ resolution: Number(resolution),
10641
+ ...seed !== void 0 && { seed }
10642
+ }
10643
+ };
10644
+ case "sam":
10645
+ return {
10646
+ endpoint: endpoint(spec.endpoints.image),
10647
+ input: {
10648
+ image_url: req.image ?? "",
10649
+ ...prompt !== void 0 && { prompt },
10650
+ export_textured_glb: true,
10651
+ ...seed !== void 0 && { seed }
10652
+ }
10653
+ };
10654
+ case "hunyuan": {
10655
+ const opts = { generate_type: textured ? "Normal" : "Geometry", enable_pbr: pbr };
10656
+ if (!present(req.image)) {
10657
+ return {
10658
+ endpoint: endpoint(spec.endpoints.text),
10659
+ input: { prompt: prompt ?? "", ...opts }
10660
+ };
10661
+ }
10662
+ return {
10663
+ endpoint: endpoint(spec.endpoints.image),
10664
+ input: {
10665
+ input_image_url: req.image,
10666
+ ...present(views.back) && { back_image_url: views.back },
10667
+ ...present(views.left) && { left_image_url: views.left },
10668
+ ...present(views.right) && { right_image_url: views.right },
10669
+ ...opts
10670
+ }
10671
+ };
10672
+ }
10673
+ case "tripo": {
10674
+ const opts = {
10675
+ texture: textured,
10676
+ pbr,
10677
+ ...textured && {
10678
+ texture_quality: texture === "detailed" ? "detailed" : "standard"
10679
+ },
10680
+ ...seed !== void 0 && { model_seed: seed }
10681
+ };
10682
+ if (!present(req.image)) {
10683
+ return {
10684
+ endpoint: endpoint(spec.endpoints.text),
10685
+ input: { prompt: prompt ?? "", ...opts }
10686
+ };
10687
+ }
10688
+ const ordered = slotted("ordered");
10689
+ return ordered.length > 1 ? {
10690
+ endpoint: endpoint(spec.endpoints.multiImage),
10691
+ input: { image_urls: ordered, ...opts }
10692
+ } : {
10693
+ endpoint: endpoint(spec.endpoints.image),
10694
+ input: { image_url: req.image, ...opts }
10695
+ };
10696
+ }
10697
+ case "rodin": {
10698
+ const opts = {
10699
+ geometry_file_format: "glb",
10700
+ material: "PBR",
10701
+ ...seed !== void 0 && { seed }
10702
+ };
10703
+ if (images.length === 0) {
10704
+ return {
10705
+ endpoint: endpoint(spec.endpoints.text),
10706
+ input: { prompt: prompt ?? "", ...opts }
10707
+ };
10708
+ }
10709
+ return {
10710
+ endpoint: endpoint(spec.endpoints.image),
10711
+ input: { image_urls: images, ...prompt !== void 0 && { prompt }, ...opts }
10712
+ };
10713
+ }
10714
+ case "meshy": {
10715
+ const texturePrompt = req.texturePrompt?.trim() || void 0;
10716
+ const opts = {
10717
+ enable_pbr: pbr,
10718
+ ...spec.textureRef && texturePrompt !== void 0 && { texture_prompt: texturePrompt },
10719
+ ...spec.textureRef && present(req.textureImage) && { texture_image_url: req.textureImage }
10720
+ };
10721
+ if (images.length === 0) {
10722
+ return {
10723
+ endpoint: endpoint(spec.endpoints.text),
10724
+ input: {
10725
+ prompt: prompt ?? "",
10726
+ mode: textured ? "full" : "preview",
10727
+ ...opts,
10728
+ ...seed !== void 0 && { seed }
10729
+ }
10730
+ };
10731
+ }
10732
+ return images.length > 1 ? {
10733
+ endpoint: endpoint(spec.endpoints.multiImage),
10734
+ input: { image_urls: images, should_texture: textured, ...opts }
10735
+ } : {
10736
+ endpoint: endpoint(spec.endpoints.image),
10737
+ input: { image_url: req.image ?? "", should_texture: textured, ...opts }
10738
+ };
10739
+ }
10740
+ case "hi3d": {
10741
+ const opts = {
10742
+ resolution: resolution === "master" ? "2048master" : "2048quality",
10743
+ enable_texture: textured,
10744
+ enable_pbr: pbr,
10745
+ export_format: "glb"
10746
+ };
10747
+ const anyView = present(views.back) || present(views.left) || present(views.right);
10748
+ return anyView ? {
10749
+ endpoint: endpoint(spec.endpoints.multiImage),
10750
+ input: {
10751
+ front_image_url: req.image ?? "",
10752
+ ...present(views.back) && { back_image_url: views.back },
10753
+ ...present(views.left) && { left_image_url: views.left },
10754
+ ...present(views.right) && { right_image_url: views.right },
10755
+ ...opts
10756
+ }
10757
+ } : {
10758
+ endpoint: endpoint(spec.endpoints.image),
10759
+ input: { image_url: req.image ?? "", ...opts }
10760
+ };
10761
+ }
10762
+ }
10763
+ }
10764
+ async function submitFalModel3d(req, ctx, opts) {
10765
+ const spec = specOf(ctx);
10766
+ const views = req.views ?? {};
10767
+ const refusal2 = model3dInputRefusal(spec, {
10768
+ prompt: present(req.prompt?.trim()),
10769
+ image: present(req.image),
10770
+ back: present(views.back),
10771
+ left: present(views.left),
10772
+ right: present(views.right),
10773
+ top: present(views.top)
10774
+ });
10775
+ if (refusal2 !== null) {
10776
+ throw new ModelKitError({
10777
+ code: "unsupported_option",
10778
+ message: `${ctx.model.id}: ${refusal2}`,
10779
+ provider: "fal",
10780
+ model: ctx.model.id,
10781
+ retryable: false
10782
+ });
10783
+ }
10784
+ if (spec.seed && req.seed !== void 0 && !model3dSeedFits(spec, req.seed)) {
10785
+ throw new ModelKitError({
10786
+ code: "unsupported_option",
10787
+ message: `${ctx.model.id} takes a seed from 0 to ${spec.seedMax ?? Number.MAX_SAFE_INTEGER}`,
10788
+ provider: "fal",
10789
+ model: ctx.model.id,
10790
+ retryable: false
10791
+ });
10792
+ }
10793
+ const call = model3dCall(ctx.model, spec, req);
10794
+ const sku = model3dPricingSku(
10795
+ ctx.model,
10796
+ {
10797
+ ...req.texture !== void 0 && { texture: req.texture },
10798
+ ...req.pbr !== void 0 && { pbr: req.pbr },
10799
+ ...req.resolution !== void 0 && { resolution: req.resolution }
10800
+ },
10801
+ {
10802
+ image: present(req.image),
10803
+ views: spec.views !== "none" && (present(views.back) || present(views.left) || present(views.right) || spec.views === "unordered" && present(views.top))
10804
+ }
10805
+ );
10806
+ const target = new URL(`${FAL_QUEUE_ORIGIN}/${call.endpoint}`);
10807
+ if (opts.webhookUrl !== void 0) target.searchParams.set("fal_webhook", opts.webhookUrl);
10808
+ const res = await queueFetch(ctx, target.toString(), "POST", call.input);
10809
+ const parsed = submitResponseSchema.safeParse(await readJson(ctx, res));
10810
+ if (!parsed.success) throw rejected(ctx, `fal ${call.endpoint} submit returned no queue URLs`);
10811
+ return {
10812
+ model: ctx.model.id,
10813
+ provider: "fal",
10814
+ endpoint: call.endpoint,
10815
+ sku,
10816
+ requestId: parsed.data.request_id,
10817
+ statusUrl: parsed.data.status_url,
10818
+ responseUrl: parsed.data.response_url,
10819
+ cancelUrl: parsed.data.cancel_url
10820
+ };
10821
+ }
10822
+ async function falModel3dStatus(sub, ctx) {
10823
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.statusUrl, "3D"), "GET");
10824
+ const { status } = statusResponseSchema.parse(await readJson(ctx, res));
10825
+ if (status === "IN_QUEUE") return "queued";
10826
+ if (status === "COMPLETED") return "completed";
10827
+ return "running";
10828
+ }
10829
+ function httpsUrl(ctx, sub, url, what) {
10830
+ if (new URL(url).protocol === "https:") return url;
10831
+ throw rejected(ctx, `fal ${sub.endpoint} returned a ${what} URL that is not https`);
10832
+ }
10833
+ function resultOf2(ctx, sub, payload) {
10834
+ const parsed = resultSchema.safeParse(payload);
10835
+ const glb = parsed.success ? parsed.data.model_glb ?? parsed.data.model_mesh : void 0;
10836
+ if (!glb) throw rejected(ctx, `fal ${sub.endpoint} returned no GLB`);
10837
+ const still = parsed.success ? parsed.data.thumbnail ?? parsed.data.rendered_image : void 0;
10838
+ const glbUrl = httpsUrl(ctx, sub, glb.url, "GLB");
10839
+ const stillUrl = still ? httpsUrl(ctx, sub, still.url, "thumbnail") : void 0;
10840
+ return {
10841
+ glb: {
10842
+ url: glbUrl,
10843
+ ...glb.content_type != null && { mime: glb.content_type },
10844
+ ...glb.file_size != null && { bytes: glb.file_size }
10845
+ },
10846
+ ...stillUrl !== void 0 && { thumbnail: { url: stillUrl } },
10847
+ sku: sub.sku,
10848
+ usage: {
10849
+ model: ctx.model.id,
10850
+ provider: "fal",
10851
+ // The sink has no 3D modality; IMAGE is the nearest. The unit is what bills it.
10852
+ modality: "IMAGE",
10853
+ unit: "requests",
10854
+ quantity: 1
10855
+ },
10856
+ raw: payload
10857
+ };
10858
+ }
10859
+ async function falModel3dResult(sub, ctx, webhook) {
10860
+ if (webhook !== void 0) {
10861
+ if (webhook.request_id !== sub.requestId) {
10862
+ throw rejected(ctx, "fal webhook is for a different request");
10863
+ }
10864
+ if (webhook.status === "ERROR") {
10865
+ throw falError(
10866
+ void 0,
10867
+ webhook.payload ?? webhook.error ?? "fal job failed",
10868
+ ctx.model.id
10869
+ );
10870
+ }
10871
+ return resultOf2(ctx, sub, webhook.payload);
10872
+ }
10873
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.responseUrl, "3D"), "GET");
10874
+ return resultOf2(ctx, sub, await readJson(ctx, res));
10875
+ }
10876
+ async function cancelFalModel3d(sub, ctx) {
10877
+ const res = await queueFetch(ctx, checkedQueueUrl(ctx, sub.cancelUrl, "3D"), "PUT");
10878
+ if (res.ok) return true;
10879
+ if (res.status === 400) return false;
10880
+ throw falError(res.status, await readBody(res), ctx.model.id);
10881
+ }
10882
+
10089
10883
  // src/adapters/fal-video-plan.ts
10090
- var import_zod17 = require("zod");
10884
+ var import_zod19 = require("zod");
10091
10885
  function refusal(ctx, message, code = "unsupported_option") {
10092
10886
  return new ModelKitError({
10093
10887
  code,
@@ -10124,9 +10918,9 @@ function wholeSeconds(req, ctx) {
10124
10918
  if (!Number.isInteger(duration)) throw refusal(ctx, "takes whole-second durations");
10125
10919
  return duration;
10126
10920
  }
10127
- var lengthSchema = import_zod17.z.object({
10128
- duration: import_zod17.z.number().positive().optional(),
10129
- video: import_zod17.z.object({ duration: import_zod17.z.number().positive().nullish() }).optional()
10921
+ var lengthSchema = import_zod19.z.object({
10922
+ duration: import_zod19.z.number().positive().optional(),
10923
+ video: import_zod19.z.object({ duration: import_zod19.z.number().positive().nullish() }).optional()
10130
10924
  });
10131
10925
  function reportedSeconds2(payload) {
10132
10926
  const parsed = lengthSchema.safeParse(payload);
@@ -10639,7 +11433,7 @@ var MUSE_T2I_ENDPOINT = "meta/muse-image/text-to-image";
10639
11433
  var MUSE_EDIT_ENDPOINT = "meta/muse-image/edit";
10640
11434
  var KLING_O1_ENDPOINT = "fal-ai/kling-video/o1/video-to-video/reference";
10641
11435
  var PASSTHROUGH_MAX_WAIT_MS = 18e4;
10642
- var falSubscribePayloadSchema = import_zod18.z.object({ data: JsonValueSchema });
11436
+ var falSubscribePayloadSchema = import_zod20.z.object({ data: JsonValueSchema });
10643
11437
  function defaultCreateFalClient(opts) {
10644
11438
  if (opts.maxRetries !== void 0)
10645
11439
  return createFalHttpClient({
@@ -10717,7 +11511,11 @@ function createFalAdapter(deps = defaultDeps) {
10717
11511
  submitVideoTool: submitFalVideoTool,
10718
11512
  videoToolStatus: falVideoToolStatus,
10719
11513
  videoToolResult: falVideoToolResult,
10720
- cancelVideoTool: cancelFalVideoTool
11514
+ cancelVideoTool: cancelFalVideoTool,
11515
+ submitModel3d: submitFalModel3d,
11516
+ model3dStatus: falModel3dStatus,
11517
+ model3dResult: falModel3dResult,
11518
+ cancelModel3d: cancelFalModel3d
10721
11519
  };
10722
11520
  }
10723
11521
  function falRun(ctx, deps) {
@@ -10865,11 +11663,11 @@ async function decodeImage(ctx, url, contentType) {
10865
11663
  const mime = res.headers.get("content-type") ?? contentType ?? "image/png";
10866
11664
  return { bytes: new Uint8Array(await res.arrayBuffer()), mime };
10867
11665
  }
10868
- var museImageResultSchema = import_zod18.z.object({
10869
- images: import_zod18.z.array(
10870
- import_zod18.z.object({
10871
- url: import_zod18.z.string().optional(),
10872
- content_type: import_zod18.z.string().nullable().optional()
11666
+ var museImageResultSchema = import_zod20.z.object({
11667
+ images: import_zod20.z.array(
11668
+ import_zod20.z.object({
11669
+ url: import_zod20.z.string().optional(),
11670
+ content_type: import_zod20.z.string().nullable().optional()
10873
11671
  })
10874
11672
  ).optional()
10875
11673
  });
@@ -11069,8 +11867,8 @@ function klingO1Input(req) {
11069
11867
  if (refs.length > 0) input.image_urls = refs;
11070
11868
  return input;
11071
11869
  }
11072
- var falVideoResultSchema = import_zod18.z.object({
11073
- video: import_zod18.z.object({ url: import_zod18.z.string().optional() }).optional()
11870
+ var falVideoResultSchema = import_zod20.z.object({
11871
+ video: import_zod20.z.object({ url: import_zod20.z.string().optional() }).optional()
11074
11872
  });
11075
11873
  function extractVideoUrl(result, endpoint, model) {
11076
11874
  const parsed = falVideoResultSchema.safeParse(result);
@@ -11162,11 +11960,11 @@ function planUsage(ctx, plan3) {
11162
11960
  }
11163
11961
 
11164
11962
  // src/adapters/google-genai.ts
11165
- var import_zod20 = require("zod");
11963
+ var import_zod22 = require("zod");
11166
11964
  var import_genai = require("@google/genai");
11167
11965
 
11168
11966
  // src/adapters/google-files.ts
11169
- var import_zod19 = require("zod");
11967
+ var import_zod21 = require("zod");
11170
11968
  var GOOGLE_FILES_BASE = "https://generativelanguage.googleapis.com";
11171
11969
  var GOOGLE_FILES_POLL_INTERVAL_MS = 2e3;
11172
11970
  var GOOGLE_FILES_POLL_TIMEOUT_MS = 5 * 60 * 1e3;
@@ -11176,17 +11974,17 @@ var GENERIC_MEDIA_TYPES = /* @__PURE__ */ new Set([
11176
11974
  "binary/octet-stream",
11177
11975
  "application/binary"
11178
11976
  ]);
11179
- var uploadedFileSchema = import_zod19.z.object({
11180
- file: import_zod19.z.object({
11181
- uri: import_zod19.z.string().optional(),
11182
- name: import_zod19.z.string().optional(),
11183
- state: import_zod19.z.string().optional(),
11184
- mimeType: import_zod19.z.string().optional()
11977
+ var uploadedFileSchema = import_zod21.z.object({
11978
+ file: import_zod21.z.object({
11979
+ uri: import_zod21.z.string().optional(),
11980
+ name: import_zod21.z.string().optional(),
11981
+ state: import_zod21.z.string().optional(),
11982
+ mimeType: import_zod21.z.string().optional()
11185
11983
  }).optional()
11186
11984
  });
11187
- var fileStateSchema = import_zod19.z.object({
11188
- state: import_zod19.z.string().optional(),
11189
- error: import_zod19.z.object({ message: import_zod19.z.string().optional() }).optional()
11985
+ var fileStateSchema = import_zod21.z.object({
11986
+ state: import_zod21.z.string().optional(),
11987
+ error: import_zod21.z.object({ message: import_zod21.z.string().optional() }).optional()
11190
11988
  });
11191
11989
  function resolveMime(declared, fallback) {
11192
11990
  const clean = declared?.split(";")[0]?.trim().toLowerCase();
@@ -11407,7 +12205,7 @@ var OMNI_POLL_INTERVAL_MS = 1e4;
11407
12205
  var RESULT_TIMEOUT_MS3 = 15 * 60 * 1e3;
11408
12206
  var OMNI_INLINE_LIMIT_BYTES = 4 * 1024 * 1024;
11409
12207
  var MEDIA_PART_INLINE_LIMIT_BYTES = 20 * 1024 * 1024;
11410
- var errorTextSchema = import_zod20.z.string();
12208
+ var errorTextSchema = import_zod22.z.string();
11411
12209
  function isGoogleGenaiVideoKnown(providerModelId) {
11412
12210
  return providerModelId.startsWith("veo-") || providerModelId.startsWith("gemini-omni");
11413
12211
  }
@@ -12071,15 +12869,15 @@ async function prepareGoogleMediaPart(ref, mediaType, ctx) {
12071
12869
  // src/adapters/google-image.ts
12072
12870
  var import_google2 = require("@ai-sdk/google");
12073
12871
  var import_ai2 = require("ai");
12074
- var import_zod21 = require("zod");
12872
+ var import_zod23 = require("zod");
12075
12873
  var GEMINI_IMAGE_TIMEOUT_MS = 6e5;
12076
12874
  var defaultGoogleImageDeps = {
12077
12875
  createGoogleClient: (opts) => (0, import_google2.createGoogleGenerativeAI)(opts),
12078
12876
  runTextGeneration: (opts) => (0, import_ai2.generateText)(opts)
12079
12877
  };
12080
- var causeChainNodeSchema = import_zod21.z.object({
12081
- message: import_zod21.z.string().optional(),
12082
- cause: import_zod21.z.unknown().optional()
12878
+ var causeChainNodeSchema = import_zod23.z.object({
12879
+ message: import_zod23.z.string().optional(),
12880
+ cause: import_zod23.z.unknown().optional()
12083
12881
  });
12084
12882
  function extractBlockReason(cause) {
12085
12883
  let current = cause;
@@ -12199,7 +12997,7 @@ function createGoogleImageAdapter(deps = defaultGoogleImageDeps) {
12199
12997
  var googleImageAdapter = createGoogleImageAdapter();
12200
12998
 
12201
12999
  // src/adapters/higgsfield.ts
12202
- var import_zod22 = require("zod");
13000
+ var import_zod24 = require("zod");
12203
13001
 
12204
13002
  // src/adapters/higgsfield-motions.ts
12205
13003
  var MOTION_MAP = {
@@ -12418,14 +13216,14 @@ function klingEndpointFields(providerModelId) {
12418
13216
  const path = (providerModelId.startsWith("/") ? providerModelId.slice(1) : providerModelId).toLowerCase();
12419
13217
  return KLING_ENDPOINT_FIELDS.get(path) ?? UNLISTED_KLING_FIELDS;
12420
13218
  }
12421
- var klingCreateSchema = import_zod22.z.object({ status_url: import_zod22.z.string() });
12422
- var klingStatusSchema = import_zod22.z.object({
12423
- status: import_zod22.z.string().optional(),
12424
- video: import_zod22.z.object({ url: import_zod22.z.string().optional() }).optional(),
13219
+ var klingCreateSchema = import_zod24.z.object({ status_url: import_zod24.z.string() });
13220
+ var klingStatusSchema = import_zod24.z.object({
13221
+ status: import_zod24.z.string().optional(),
13222
+ video: import_zod24.z.object({ url: import_zod24.z.string().optional() }).optional(),
12425
13223
  error: JsonValueSchema.optional()
12426
13224
  });
12427
- var errorMessageSchema = import_zod22.z.object({ message: import_zod22.z.string().optional() });
12428
- var textValueSchema = import_zod22.z.string();
13225
+ var errorMessageSchema = import_zod24.z.object({ message: import_zod24.z.string().optional() });
13226
+ var textValueSchema = import_zod24.z.string();
12429
13227
  function klingErrorDetail(error) {
12430
13228
  if (error === void 0) return "unknown_error";
12431
13229
  const asText = textValueSchema.safeParse(error);
@@ -12581,8 +13379,8 @@ async function generateKlingVideo(req, ctx) {
12581
13379
  }
12582
13380
  };
12583
13381
  }
12584
- var dopMotionOptionsSchema = import_zod22.z.object({
12585
- modelkit: import_zod22.z.object({ motion: import_zod22.z.string().optional() }).optional()
13382
+ var dopMotionOptionsSchema = import_zod24.z.object({
13383
+ modelkit: import_zod24.z.object({ motion: import_zod24.z.string().optional() }).optional()
12586
13384
  });
12587
13385
  function dopMotionId(ctx) {
12588
13386
  const parsed = dopMotionOptionsSchema.safeParse(ctx.model.providerOptions);
@@ -12598,7 +13396,7 @@ function dopMotionId(ctx) {
12598
13396
  });
12599
13397
  return id;
12600
13398
  }
12601
- var jsonRecordSchema = import_zod22.z.record(import_zod22.z.string(), JsonValueSchema);
13399
+ var jsonRecordSchema = import_zod24.z.record(import_zod24.z.string(), JsonValueSchema);
12602
13400
  var DOP_URL_KEYS = ["url", "video_url", "output_url", "result_url", "download_url"];
12603
13401
  var DOP_NESTED_KEYS = ["video", "result", "results"];
12604
13402
  function dopUrl(body) {
@@ -12626,8 +13424,8 @@ function dopUrl(body) {
12626
13424
  }
12627
13425
  return void 0;
12628
13426
  }
12629
- var dopCreateSchema = import_zod22.z.object({ id: import_zod22.z.string() });
12630
- var dopStatusSchema = import_zod22.z.object({ status: import_zod22.z.string().optional() });
13427
+ var dopCreateSchema = import_zod24.z.object({ id: import_zod24.z.string() });
13428
+ var dopStatusSchema = import_zod24.z.object({ status: import_zod24.z.string().optional() });
12631
13429
  async function generateDopVideo(req, ctx) {
12632
13430
  const firstFrame = req.firstFrame ? refToUrl(req.firstFrame) : void 0;
12633
13431
  if (!firstFrame) {
@@ -12755,7 +13553,7 @@ var higgsfieldAdapter = {
12755
13553
 
12756
13554
  // src/adapters/openai-image.ts
12757
13555
  var import_openai2 = __toESM(require("openai"), 1);
12758
- var import_zod23 = require("zod");
13556
+ var import_zod25 = require("zod");
12759
13557
  var MAX_EDIT_REFERENCES = 16;
12760
13558
  function aspectRatioToSize(ratio, tier) {
12761
13559
  const TIER_LONG_EDGE = {
@@ -12838,9 +13636,9 @@ function toProviderError2(cause, ctx) {
12838
13636
  ctx.model.id
12839
13637
  );
12840
13638
  }
12841
- var openaiUsageSchema = import_zod23.z.object({
12842
- input_tokens: import_zod23.z.number().optional(),
12843
- output_tokens: import_zod23.z.number().optional()
13639
+ var openaiUsageSchema = import_zod25.z.object({
13640
+ input_tokens: import_zod25.z.number().optional(),
13641
+ output_tokens: import_zod25.z.number().optional()
12844
13642
  });
12845
13643
  var openaiImageAdapter = {
12846
13644
  id: "openai-image",
@@ -13252,13 +14050,13 @@ var prodiaAdapter = {
13252
14050
  var import_replicate = __toESM(require("replicate"), 1);
13253
14051
 
13254
14052
  // src/adapters/replicate-http.ts
13255
- var import_zod24 = require("zod");
13256
- var predictionSchema = import_zod24.z.object({
13257
- id: import_zod24.z.string(),
13258
- status: import_zod24.z.string(),
14053
+ var import_zod26 = require("zod");
14054
+ var predictionSchema = import_zod26.z.object({
14055
+ id: import_zod26.z.string(),
14056
+ status: import_zod26.z.string(),
13259
14057
  output: JsonValueSchema.optional(),
13260
14058
  error: JsonValueSchema.optional(),
13261
- metrics: import_zod24.z.object({ predict_time: import_zod24.z.number().optional() }).optional()
14059
+ metrics: import_zod26.z.object({ predict_time: import_zod26.z.number().optional() }).optional()
13262
14060
  });
13263
14061
  function createReplicateHttpClient(opts) {
13264
14062
  async function request(path, body, signal) {
@@ -13309,7 +14107,7 @@ function createReplicateHttpClient(opts) {
13309
14107
  }
13310
14108
 
13311
14109
  // src/adapters/replicate.ts
13312
- var import_zod25 = require("zod");
14110
+ var import_zod27 = require("zod");
13313
14111
  var POLL_INTERVAL_MS = 1e3;
13314
14112
  var POLL_TIMEOUT_MS = 15 * 6e4;
13315
14113
  var defaultReplicateDeps = {
@@ -13349,8 +14147,8 @@ function route(providerModelId) {
13349
14147
  if (!providerModelId.includes("/")) return { version: providerModelId };
13350
14148
  return { model: providerModelId };
13351
14149
  }
13352
- var replicateResponseStatusSchema = import_zod25.z.object({
13353
- response: import_zod25.z.object({ status: import_zod25.z.number() }).partial()
14150
+ var replicateResponseStatusSchema = import_zod27.z.object({
14151
+ response: import_zod27.z.object({ status: import_zod27.z.number() }).partial()
13354
14152
  });
13355
14153
  function replicateError(cause, ctx) {
13356
14154
  if (isModelKitError(cause)) return cause;
@@ -13377,7 +14175,7 @@ function isUrlFn(value) {
13377
14175
  function extractOutputUrl(output) {
13378
14176
  const root = Array.isArray(output) ? output[0] : output;
13379
14177
  if (root === void 0) throw noOutput();
13380
- const asString = import_zod25.z.string().safeParse(root);
14178
+ const asString = import_zod27.z.string().safeParse(root);
13381
14179
  if (asString.success && asString.data) return asString.data;
13382
14180
  if (root instanceof URL) return root.href;
13383
14181
  if (isObjectOutput(root)) {
@@ -13386,15 +14184,15 @@ function extractOutputUrl(output) {
13386
14184
  if (urlValue !== void 0 && isUrlFn(urlValue)) {
13387
14185
  const called = urlValue();
13388
14186
  if (called instanceof URL) return called.href;
13389
- const calledString = import_zod25.z.string().safeParse(called);
14187
+ const calledString = import_zod27.z.string().safeParse(called);
13390
14188
  if (calledString.success && calledString.data) return calledString.data;
13391
14189
  } else {
13392
- const direct = import_zod25.z.string().safeParse(urlValue);
14190
+ const direct = import_zod27.z.string().safeParse(urlValue);
13393
14191
  if (direct.success && direct.data) return direct.data;
13394
14192
  }
13395
14193
  }
13396
14194
  if ("default" in root) {
13397
- const fallback = import_zod25.z.string().safeParse(root.default);
14195
+ const fallback = import_zod27.z.string().safeParse(root.default);
13398
14196
  if (fallback.success && fallback.data) return fallback.data;
13399
14197
  }
13400
14198
  }
@@ -13455,7 +14253,7 @@ async function runPrediction(ctx, input, deps) {
13455
14253
  }
13456
14254
  return void 0;
13457
14255
  }, pollOpts);
13458
- const predictTime = import_zod25.z.number().safeParse(done.metrics?.predict_time);
14256
+ const predictTime = import_zod27.z.number().safeParse(done.metrics?.predict_time);
13459
14257
  if (done.output === void 0) throw noOutput();
13460
14258
  return {
13461
14259
  url: extractOutputUrl(done.output),
@@ -13826,7 +14624,7 @@ async function generateReplicateVideo(req, ctx, deps) {
13826
14624
  throw replicateError(cause, ctx);
13827
14625
  }
13828
14626
  if (current.status === "succeeded") {
13829
- const predictTime = import_zod25.z.number().safeParse(current.metrics?.predict_time);
14627
+ const predictTime = import_zod27.z.number().safeParse(current.metrics?.predict_time);
13830
14628
  if (current.output === void 0) throw noOutput();
13831
14629
  return {
13832
14630
  url: extractOutputUrl(current.output),
@@ -13968,7 +14766,7 @@ async function generateReplicateAudio(req, ctx, deps) {
13968
14766
  // src/adapters/xai-video.ts
13969
14767
  var import_ai3 = require("ai");
13970
14768
  var import_xai2 = require("@ai-sdk/xai");
13971
- var import_zod26 = require("zod");
14769
+ var import_zod28 = require("zod");
13972
14770
  var POLL_INTERVAL_MS2 = 1e4;
13973
14771
  var POLL_TIMEOUT_MS2 = 15 * 6e4;
13974
14772
  var defaultXaiDeps = {
@@ -13981,8 +14779,8 @@ function createXaiVideoAdapter(deps = defaultXaiDeps) {
13981
14779
  };
13982
14780
  }
13983
14781
  var xaiVideoAdapter = createXaiVideoAdapter();
13984
- var xaiResponseStatusSchema = import_zod26.z.object({
13985
- response: import_zod26.z.object({ status: import_zod26.z.number() }).partial()
14782
+ var xaiResponseStatusSchema = import_zod28.z.object({
14783
+ response: import_zod28.z.object({ status: import_zod28.z.number() }).partial()
13986
14784
  });
13987
14785
  function xaiError(cause, ctx) {
13988
14786
  const info = describeThrown(cause);
@@ -13990,12 +14788,12 @@ function xaiError(cause, ctx) {
13990
14788
  const status = info.status ?? (nested.success ? nested.data.response?.status : void 0);
13991
14789
  return classifyThrown("xai-video", cause, ctx.model.id, { status, body: info.body });
13992
14790
  }
13993
- var xaiMetaSchema = import_zod26.z.object({
14791
+ var xaiMetaSchema = import_zod28.z.object({
13994
14792
  videoUrl: JsonValueSchema.optional(),
13995
14793
  costInUsdTicks: JsonValueSchema.optional(),
13996
14794
  duration: JsonValueSchema.optional()
13997
14795
  });
13998
- var xaiProviderMetadataSchema = import_zod26.z.object({ xai: xaiMetaSchema });
14796
+ var xaiProviderMetadataSchema = import_zod28.z.object({ xai: xaiMetaSchema });
13999
14797
  function metaOf(result) {
14000
14798
  const parsed = xaiProviderMetadataSchema.partial().safeParse(result.providerMetadata);
14001
14799
  if (!parsed.success) return {};
@@ -14111,7 +14909,7 @@ async function mapResult(ctx, req, result) {
14111
14909
  };
14112
14910
  }
14113
14911
  const meta = metaOf(result);
14114
- const videoUrl = import_zod26.z.string().safeParse(meta.videoUrl);
14912
+ const videoUrl = import_zod28.z.string().safeParse(meta.videoUrl);
14115
14913
  if (videoUrl.success && videoUrl.data) {
14116
14914
  const res = await ctx.fetch(videoUrl.data);
14117
14915
  if (!res.ok) {
@@ -14134,7 +14932,7 @@ async function mapResult(ctx, req, result) {
14134
14932
  });
14135
14933
  }
14136
14934
  function usage2(ctx, req, meta) {
14137
- const costTicks = import_zod26.z.number().safeParse(meta.costInUsdTicks);
14935
+ const costTicks = import_zod28.z.number().safeParse(meta.costInUsdTicks);
14138
14936
  const cost = costTicks.success ? costTicks.data / 1e10 : void 0;
14139
14937
  const event = {
14140
14938
  model: ctx.model.id,
@@ -14186,10 +14984,10 @@ var DEFAULT_ADAPTERS = {
14186
14984
  };
14187
14985
 
14188
14986
  // src/catalog/data-only.ts
14189
- function hasValidInputSpec(row) {
14190
- const raw = row.providerOptions?.["modelkit"]?.["inputSpec"];
14987
+ function hasValidInputSpec(row2) {
14988
+ const raw = row2.providerOptions?.["modelkit"]?.["inputSpec"];
14191
14989
  if (raw === void 0) return false;
14192
- return validateInputSpec(raw, row).ok;
14990
+ return validateInputSpec(raw, row2).ok;
14193
14991
  }
14194
14992
  function assertNever(value) {
14195
14993
  throw new Error(`Unhandled adapter: ${String(value)}`);
@@ -14207,6 +15005,7 @@ function adapterServesType(adapter, type) {
14207
15005
  if (type === "lipsync") return adapter.lipsync !== void 0;
14208
15006
  if (type === "transcription") return adapter.transcribe !== void 0;
14209
15007
  if (type === "video-tool") return adapter.submitVideoTool !== void 0;
15008
+ if (type === "model3d") return adapter.submitModel3d !== void 0;
14210
15009
  return adapter.languageModel !== void 0;
14211
15010
  }
14212
15011
  var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
@@ -14218,18 +15017,18 @@ var FAL_NODE_TYPES = /* @__PURE__ */ new Set([
14218
15017
  "transcription",
14219
15018
  "mask"
14220
15019
  ]);
14221
- function dataOnlyCapable(row) {
14222
- const adapter = DEFAULT_ADAPTERS[row.adapter];
14223
- if (!adapterServesType(adapter, row.type)) {
14224
- return { ok: false, reason: `${row.adapter} cannot serve ${row.type} rows` };
15020
+ function dataOnlyCapable(row2) {
15021
+ const adapter = DEFAULT_ADAPTERS[row2.adapter];
15022
+ if (!adapterServesType(adapter, row2.type)) {
15023
+ return { ok: false, reason: `${row2.adapter} cannot serve ${row2.type} rows` };
14225
15024
  }
14226
- if (FAL_NODE_TYPES.has(row.type) && row.adapter !== "fal") {
14227
- return { ok: false, reason: `only fal serves ${row.type} rows` };
15025
+ if (FAL_NODE_TYPES.has(row2.type) && row2.adapter !== "fal") {
15026
+ return { ok: false, reason: `only fal serves ${row2.type} rows` };
14228
15027
  }
14229
- switch (row.adapter) {
15028
+ switch (row2.adapter) {
14230
15029
  case "ai-sdk-text": {
14231
15030
  try {
14232
- textProviderOf(row);
15031
+ textProviderOf(row2);
14233
15032
  return { ok: true };
14234
15033
  } catch {
14235
15034
  return {
@@ -14247,14 +15046,14 @@ function dataOnlyCapable(row) {
14247
15046
  return { ok: true };
14248
15047
  }
14249
15048
  case "google-genai": {
14250
- if (row.type === "video") {
14251
- return isGoogleGenaiVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "google-genai video needs a veo- or gemini-omni id" };
15049
+ if (row2.type === "video") {
15050
+ return isGoogleGenaiVideoKnown(row2.providerModelId) ? { ok: true } : { ok: false, reason: "google-genai video needs a veo- or gemini-omni id" };
14252
15051
  }
14253
- return isGoogleGenaiAudioKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "google-genai audio needs a lyria- id" };
15052
+ return isGoogleGenaiAudioKnown(row2.providerModelId) ? { ok: true } : { ok: false, reason: "google-genai audio needs a lyria- id" };
14254
15053
  }
14255
15054
  case "replicate": {
14256
- if (row.type === "video") {
14257
- if (isReplicateVideoKnown(row.providerModelId) || hasValidInputSpec(row)) {
15055
+ if (row2.type === "video") {
15056
+ if (isReplicateVideoKnown(row2.providerModelId) || hasValidInputSpec(row2)) {
14258
15057
  return { ok: true };
14259
15058
  }
14260
15059
  return {
@@ -14262,8 +15061,8 @@ function dataOnlyCapable(row) {
14262
15061
  reason: "replicate video needs a known kind or a valid inputSpec"
14263
15062
  };
14264
15063
  }
14265
- if (row.type === "audio") {
14266
- if (isReplicateAudioKnown(row.providerModelId) || hasValidInputSpec(row)) {
15064
+ if (row2.type === "audio") {
15065
+ if (isReplicateAudioKnown(row2.providerModelId) || hasValidInputSpec(row2)) {
14267
15066
  return { ok: true };
14268
15067
  }
14269
15068
  return {
@@ -14274,31 +15073,31 @@ function dataOnlyCapable(row) {
14274
15073
  return { ok: true };
14275
15074
  }
14276
15075
  case "fal": {
14277
- if (row.type === "video") {
14278
- return isFalVideoKnown(row.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs an id from a fal video family" };
15076
+ if (row2.type === "video") {
15077
+ return isFalVideoKnown(row2.providerModelId) ? { ok: true } : { ok: false, reason: "fal video needs an id from a fal video family" };
14279
15078
  }
14280
- if (row.type === "mask") {
14281
- return row.providerModelId === SAM3_IMAGE ? { ok: true } : { ok: false, reason: `fal maps mask rows only to ${SAM3_IMAGE}` };
15079
+ if (row2.type === "mask") {
15080
+ return row2.providerModelId === SAM3_IMAGE ? { ok: true } : { ok: false, reason: `fal maps mask rows only to ${SAM3_IMAGE}` };
14282
15081
  }
14283
- if (row.type === "video-tool" && row.constraints.tool?.kind === "subtitles") {
14284
- return row.providerModelId === VEED_SUBTITLES2 ? { ok: true } : { ok: false, reason: `fal maps subtitles only to ${VEED_SUBTITLES2}` };
15082
+ if (row2.type === "video-tool" && row2.constraints.tool?.kind === "subtitles") {
15083
+ return row2.providerModelId === VEED_SUBTITLES2 ? { ok: true } : { ok: false, reason: `fal maps subtitles only to ${VEED_SUBTITLES2}` };
14285
15084
  }
14286
- if (FAL_MEDIA_TYPES.has(row.type)) {
14287
- return isFalMediaKnown(row.type, row.providerModelId) ? { ok: true } : { ok: false, reason: `fal has no ${row.type} mapping for this id` };
15085
+ if (FAL_MEDIA_TYPES.has(row2.type)) {
15086
+ return isFalMediaKnown(row2.type, row2.providerModelId) ? { ok: true } : { ok: false, reason: `fal has no ${row2.type} mapping for this id` };
14288
15087
  }
14289
15088
  return { ok: true };
14290
15089
  }
14291
15090
  case "prodia": {
14292
- return isProdiaCapable(row.providerModelId) ? { ok: true } : { ok: false, reason: "prodia has no job mapping for this id" };
15091
+ return isProdiaCapable(row2.providerModelId) ? { ok: true } : { ok: false, reason: "prodia has no job mapping for this id" };
14293
15092
  }
14294
15093
  case "higgsfield": {
14295
- return isHiggsfieldCapable(row.providerModelId) ? { ok: true } : {
15094
+ return isHiggsfieldCapable(row2.providerModelId) ? { ok: true } : {
14296
15095
  ok: false,
14297
15096
  reason: "higgsfield providerModelId must be a platform path, not a URL"
14298
15097
  };
14299
15098
  }
14300
15099
  default: {
14301
- return assertNever(row.adapter);
15100
+ return assertNever(row2.adapter);
14302
15101
  }
14303
15102
  }
14304
15103
  }
@@ -14316,22 +15115,22 @@ var liveState = store[KEY] ??= {
14316
15115
  var liveCatalog = liveState.catalog;
14317
15116
 
14318
15117
  // src/catalog/load.ts
14319
- var import_zod27 = require("zod");
15118
+ var import_zod29 = require("zod");
14320
15119
  function rowCount() {
14321
15120
  return liveCatalog.list({ lifecycle: ["active", "deprecated", "retired"] }).length;
14322
15121
  }
14323
15122
  function authHeaders(auth) {
14324
15123
  return "bearer" in auth ? { Authorization: `Bearer ${auth.bearer}` } : { "x-api-key": auth.apiKey };
14325
15124
  }
14326
- var EnvelopeSchema = import_zod27.z.object({
14327
- rows: import_zod27.z.array(JsonValueSchema),
14328
- revision: import_zod27.z.string().optional()
15125
+ var EnvelopeSchema = import_zod29.z.object({
15126
+ rows: import_zod29.z.array(JsonValueSchema),
15127
+ revision: import_zod29.z.string().optional()
14329
15128
  });
14330
15129
  function dropReason(path, message) {
14331
15130
  return path.length === 0 ? message : `${path.map((part) => String(part)).join(".")} ${message}`;
14332
15131
  }
14333
15132
  function rowId(raw) {
14334
- const parsed = import_zod27.z.object({ id: import_zod27.z.string().min(1) }).loose().safeParse(raw);
15133
+ const parsed = import_zod29.z.object({ id: import_zod29.z.string().min(1) }).loose().safeParse(raw);
14335
15134
  if (!parsed.success) return "?";
14336
15135
  return parsed.data.id;
14337
15136
  }
@@ -14347,22 +15146,22 @@ function quarantine(rawRows, logger) {
14347
15146
  dropped += 1;
14348
15147
  continue;
14349
15148
  }
14350
- const row = parsed.data;
14351
- const inputSpecRaw = row.providerOptions?.["modelkit"]?.["inputSpec"];
15149
+ const row2 = parsed.data;
15150
+ const inputSpecRaw = row2.providerOptions?.["modelkit"]?.["inputSpec"];
14352
15151
  if (inputSpecRaw !== void 0) {
14353
- const result = validateInputSpec(inputSpecRaw, row);
15152
+ const result = validateInputSpec(inputSpecRaw, row2);
14354
15153
  if (!result.ok) {
14355
15154
  const first = result.issues[0];
14356
15155
  const detail = first ? dropReason(first.path, first.message) : "invalid inputSpec";
14357
15156
  logger.warn(
14358
- `[modelkit] catalog row ${row.id} has an invalid providerOptions.modelkit.inputSpec: ${detail}; calls fail until it is fixed`
15157
+ `[modelkit] catalog row ${row2.id} has an invalid providerOptions.modelkit.inputSpec: ${detail}; calls fail until it is fixed`
14359
15158
  );
14360
15159
  }
14361
15160
  }
14362
- const normalised = normaliseConventions(row);
15161
+ const normalised = normaliseConventions(row2);
14363
15162
  if (normalised.invalidKeys.length > 0) {
14364
15163
  logger.warn(
14365
- `[modelkit] catalog row ${row.id} has an invalid ${normalised.invalidKeys.join(", ")}; read as not set`
15164
+ `[modelkit] catalog row ${row2.id} has an invalid ${normalised.invalidKeys.join(", ")}; read as not set`
14366
15165
  );
14367
15166
  }
14368
15167
  valid.push(normalised.row);
@@ -14376,10 +15175,10 @@ function quarantine(rawRows, logger) {
14376
15175
  if (!firstByIndex.has(issue.index)) firstByIndex.set(issue.index, issue);
14377
15176
  }
14378
15177
  for (const [index, issue] of [...firstByIndex.entries()].sort((a, b) => a[0] - b[0])) {
14379
- const row = kept[index];
14380
- if (!row) continue;
15178
+ const row2 = kept[index];
15179
+ if (!row2) continue;
14381
15180
  logger.warn(
14382
- `[modelkit] catalog row dropped id=${row.id} reason=${String(issue.path[0] ?? "")} ${issue.message}`
15181
+ `[modelkit] catalog row dropped id=${row2.id} reason=${String(issue.path[0] ?? "")} ${issue.message}`
14383
15182
  );
14384
15183
  }
14385
15184
  const dropSet = new Set(firstByIndex.keys());
@@ -15079,16 +15878,16 @@ function resolveVideoOptions(model, request, onUnsupported = "error") {
15079
15878
  }
15080
15879
  function checkVideoRequired(model, req) {
15081
15880
  const c = model.constraints;
15082
- const present = (input) => input === "references" ? compact(req.referenceImages).length + compact(req.referenceVideos).length + compact(req.referenceAudios).length > 0 : input !== "sourceAudio" && req[input] !== void 0;
15881
+ const present2 = (input) => input === "references" ? compact(req.referenceImages).length + compact(req.referenceVideos).length + compact(req.referenceAudios).length > 0 : input !== "sourceAudio" && req[input] !== void 0;
15083
15882
  for (const input of c.requires ?? []) {
15084
- if (!present(input))
15883
+ if (!present2(input))
15085
15884
  throw new ModelKitError({
15086
15885
  code: "missing_input",
15087
15886
  message: `${model.id} requires ${input}`,
15088
15887
  model: model.id
15089
15888
  });
15090
15889
  }
15091
- if (c.requiresOneOf && !c.requiresOneOf.some(present)) {
15890
+ if (c.requiresOneOf && !c.requiresOneOf.some(present2)) {
15092
15891
  throw new ModelKitError({
15093
15892
  code: "missing_input",
15094
15893
  message: `${model.id} requires one of: ${c.requiresOneOf.join(", ")}`,
@@ -15136,8 +15935,8 @@ function resolveAudioOptions(model, request, onUnsupported = "error") {
15136
15935
  if (references.length > 0) merged.references = references;
15137
15936
  else delete merged.references;
15138
15937
  for (const input of c.requires ?? []) {
15139
- const present = input === "references" ? references.length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
15140
- if (!present)
15938
+ const present2 = input === "references" ? references.length > 0 : input === "sourceVideo" && merged.sourceVideo !== void 0;
15939
+ if (!present2)
15141
15940
  throw new ModelKitError({
15142
15941
  code: "missing_input",
15143
15942
  message: `${model.id} requires ${input}`,
@@ -15191,12 +15990,12 @@ function unsupported3(model, message) {
15191
15990
  model: model.id
15192
15991
  });
15193
15992
  }
15194
- function checkRequired(model, present) {
15993
+ function checkRequired(model, present2) {
15195
15994
  for (const input of model.constraints.requires ?? []) {
15196
- if (present[input] !== true) throw missing2(model, input);
15995
+ if (present2[input] !== true) throw missing2(model, input);
15197
15996
  }
15198
15997
  const oneOf = model.constraints.requiresOneOf;
15199
- if (oneOf !== void 0 && !oneOf.some((input) => present[input] === true)) {
15998
+ if (oneOf !== void 0 && !oneOf.some((input) => present2[input] === true)) {
15200
15999
  throw missing2(model, `one of ${oneOf.join(", ")}`);
15201
16000
  }
15202
16001
  }
@@ -15458,7 +16257,7 @@ function keysFromEnv(env, prefix = "") {
15458
16257
 
15459
16258
  // src/text.ts
15460
16259
  var import_ai4 = require("ai");
15461
- var import_zod28 = require("zod");
16260
+ var import_zod30 = require("zod");
15462
16261
  function mergeTextProviderOptions(catalog, caller) {
15463
16262
  const merged = {};
15464
16263
  const catalogOptions = catalog.providerOptions ?? {};
@@ -15497,8 +16296,8 @@ function passthroughTextModel(model) {
15497
16296
  pricingKind: "token"
15498
16297
  };
15499
16298
  }
15500
- var perplexityCostSchema = import_zod28.z.object({
15501
- perplexity: import_zod28.z.object({ cost: import_zod28.z.object({ totalCost: import_zod28.z.number().finite().nonnegative() }) })
16299
+ var perplexityCostSchema = import_zod30.z.object({
16300
+ perplexity: import_zod30.z.object({ cost: import_zod30.z.object({ totalCost: import_zod30.z.number().finite().nonnegative() }) })
15502
16301
  });
15503
16302
  function reportedCostUsd(metadata) {
15504
16303
  const parsed = perplexityCostSchema.safeParse(metadata);
@@ -15571,7 +16370,7 @@ function createTextSteps(initial, resolve, callerProviderOptions) {
15571
16370
 
15572
16371
  // src/client.ts
15573
16372
  var import_ai5 = require("ai");
15574
- var import_zod29 = require("zod");
16373
+ var import_zod31 = require("zod");
15575
16374
 
15576
16375
  // src/generated-image.ts
15577
16376
  function toGeneratedImage(image) {
@@ -15598,8 +16397,8 @@ function isAnthropicTransport(value) {
15598
16397
  return ANTHROPIC_TRANSPORTS.some((transport) => transport === value);
15599
16398
  }
15600
16399
  function preferredAnthropicTransport(model, routing) {
15601
- const row = model.providerOptions?.["modelkit"]?.["transport"];
15602
- if (isAnthropicTransport(row)) return row;
16400
+ const row2 = model.providerOptions?.["modelkit"]?.["transport"];
16401
+ if (isAnthropicTransport(row2)) return row2;
15603
16402
  return routing.anthropic ?? "direct";
15604
16403
  }
15605
16404
  function resolveAnthropicTransport(model, config, tier, warn) {
@@ -15626,6 +16425,85 @@ function textUsageProvider(model, transport) {
15626
16425
  return transport === "bedrock" ? BEDROCK_USAGE_PROVIDER : textProviderOf(model);
15627
16426
  }
15628
16427
 
16428
+ // src/provider-job.ts
16429
+ var VIDEO_TOOL_JOB = {
16430
+ type: "video-tool",
16431
+ noun: "a video tool",
16432
+ plural: "video tools",
16433
+ methods: (a) => ({
16434
+ submit: a.submitVideoTool?.bind(a),
16435
+ status: a.videoToolStatus?.bind(a),
16436
+ result: a.videoToolResult?.bind(a),
16437
+ cancel: a.cancelVideoTool?.bind(a)
16438
+ })
16439
+ };
16440
+ var MODEL3D_JOB = {
16441
+ type: "model3d",
16442
+ noun: "a 3D model",
16443
+ plural: "3D models",
16444
+ methods: (a) => ({
16445
+ submit: a.submitModel3d?.bind(a),
16446
+ status: a.model3dStatus?.bind(a),
16447
+ result: a.model3dResult?.bind(a),
16448
+ cancel: a.cancelModel3d?.bind(a)
16449
+ })
16450
+ };
16451
+ function providerJobMethods(kind, deps) {
16452
+ function target(modelId, call) {
16453
+ mediaRetryOptions(call);
16454
+ const model = deps.catalog.require(modelId);
16455
+ if (model.type !== kind.type)
16456
+ throw new ModelKitError({
16457
+ code: "unsupported_option",
16458
+ message: `${model.id} is not ${kind.noun}`,
16459
+ model: model.id
16460
+ });
16461
+ const { adapter, ctx } = deps.context(model, call);
16462
+ return { methods: kind.methods(adapter), adapter, ctx };
16463
+ }
16464
+ function missing3(adapter, model) {
16465
+ return new ModelKitError({
16466
+ code: "unsupported_option",
16467
+ message: `${adapter.id} has no ${kind.plural}`,
16468
+ model: model.id
16469
+ });
16470
+ }
16471
+ return {
16472
+ async submit(req, call = {}) {
16473
+ const { webhookUrl, ...rest } = call;
16474
+ const { methods, adapter, ctx } = target(req.model, rest);
16475
+ if (!methods.submit) throw missing3(adapter, ctx.model);
16476
+ const submittedAt = Date.now();
16477
+ const submission = await methods.submit(
16478
+ req,
16479
+ ctx,
16480
+ webhookUrl !== void 0 ? { webhookUrl } : {}
16481
+ );
16482
+ return { ...submission, submittedAt };
16483
+ },
16484
+ async status(sub, call = {}) {
16485
+ const { methods, adapter, ctx } = target(sub.model, call);
16486
+ if (!methods.status) throw missing3(adapter, ctx.model);
16487
+ return methods.status(sub, ctx);
16488
+ },
16489
+ async result(sub, call = {}) {
16490
+ const { webhook, ...rest } = call;
16491
+ const { methods, adapter, ctx } = target(sub.model, rest);
16492
+ if (!methods.result) throw missing3(adapter, ctx.model);
16493
+ const result = await methods.result(sub, ctx, webhook);
16494
+ const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
16495
+ const usage3 = sub.submittedAt === void 0 ? base : deps.timed(base, sub.submittedAt);
16496
+ await deps.emit(usage3);
16497
+ return { ...result, usage: usage3 };
16498
+ },
16499
+ async cancel(sub, call = {}) {
16500
+ const { methods, adapter, ctx } = target(sub.model, call);
16501
+ if (!methods.cancel) throw missing3(adapter, ctx.model);
16502
+ return methods.cancel(sub, ctx);
16503
+ }
16504
+ };
16505
+ }
16506
+
15629
16507
  // src/resolve-call.ts
15630
16508
  var MEDIA_METHODS = {
15631
16509
  text: [],
@@ -15641,7 +16519,10 @@ var MEDIA_METHODS = {
15641
16519
  lipsync: ["lipsync"],
15642
16520
  dubbing: ["dub"],
15643
16521
  transcription: ["transcribe"],
15644
- "video-tool": ["submitVideoTool"]
16522
+ "video-tool": ["submitVideoTool"],
16523
+ // 3D jobs run through submitModel3d, which checks the row type itself; their preflight
16524
+ // is model3dInputRefusal, not resolveOptions.
16525
+ model3d: []
15645
16526
  };
15646
16527
  var METHOD_NOUN = {
15647
16528
  generateImage: "an image model",
@@ -15838,10 +16719,10 @@ function textAbortOptions(sdk, context) {
15838
16719
  if (abortSignal) return { abortSignal };
15839
16720
  return {};
15840
16721
  }
15841
- var catalogId = import_zod29.z.string();
15842
- var exactSize = import_zod29.z.templateLiteral([import_zod29.z.number(), "x", import_zod29.z.number()]);
15843
- var sdkRatio = import_zod29.z.templateLiteral([import_zod29.z.number(), ":", import_zod29.z.number()]);
15844
- var sizeTier = import_zod29.z.enum(["512", "1K", "2K", "4K"]);
16722
+ var catalogId = import_zod31.z.string();
16723
+ var exactSize = import_zod31.z.templateLiteral([import_zod31.z.number(), "x", import_zod31.z.number()]);
16724
+ var sdkRatio = import_zod31.z.templateLiteral([import_zod31.z.number(), ":", import_zod31.z.number()]);
16725
+ var sizeTier = import_zod31.z.enum(["512", "1K", "2K", "4K"]);
15845
16726
  function isCatalogId(model) {
15846
16727
  return catalogId.safeParse(model).success;
15847
16728
  }
@@ -15951,19 +16832,14 @@ function createModelKit(config, adapters) {
15951
16832
  if (call.signal) ctx.signal = call.signal;
15952
16833
  return { adapter, ctx };
15953
16834
  }
15954
- function videoToolTarget(modelId, call) {
15955
- mediaRetryOptions(call);
15956
- const model = catalog.require(modelId);
15957
- assertMethod(model, "submitVideoTool");
15958
- return context(model, call, []);
15959
- }
15960
- function noVideoTools(adapter, model) {
15961
- return new ModelKitError({
15962
- code: "unsupported_option",
15963
- message: `${adapter.id} has no video tools`,
15964
- model: model.id
15965
- });
15966
- }
16835
+ const jobDeps = {
16836
+ catalog,
16837
+ context: (model, call) => context(model, call, []),
16838
+ timed,
16839
+ emit
16840
+ };
16841
+ const videoToolJobs = providerJobMethods(VIDEO_TOOL_JOB, jobDeps);
16842
+ const model3dJobs = providerJobMethods(MODEL3D_JOB, jobDeps);
15967
16843
  function timed(event, startedAt) {
15968
16844
  if (event.latencyMs !== void 0) return event;
15969
16845
  return { ...event, latencyMs: Math.max(0, Date.now() - startedAt) };
@@ -15979,8 +16855,8 @@ function createModelKit(config, adapters) {
15979
16855
  }
15980
16856
  }
15981
16857
  function withRowUnit(event) {
15982
- const row = catalog.get(event.model);
15983
- return row ? { ...event, unit: row.usage.unit } : event;
16858
+ const row2 = catalog.get(event.model);
16859
+ return row2 ? { ...event, unit: row2.usage.unit } : event;
15984
16860
  }
15985
16861
  function textTarget(model, call) {
15986
16862
  if (!isCatalogId(model)) {
@@ -16394,38 +17270,14 @@ function createModelKit(config, adapters) {
16394
17270
  usageProvider: provider
16395
17271
  };
16396
17272
  },
16397
- async submitVideoTool(req, call = {}) {
16398
- const { webhookUrl, ...rest } = call;
16399
- const { adapter, ctx } = videoToolTarget(req.model, rest);
16400
- if (!adapter.submitVideoTool) throw noVideoTools(adapter, ctx.model);
16401
- const submittedAt = Date.now();
16402
- const submission = await adapter.submitVideoTool(
16403
- req,
16404
- ctx,
16405
- webhookUrl !== void 0 ? { webhookUrl } : {}
16406
- );
16407
- return { ...submission, submittedAt };
16408
- },
16409
- async videoToolStatus(sub, call = {}) {
16410
- const { adapter, ctx } = videoToolTarget(sub.model, call);
16411
- if (!adapter.videoToolStatus) throw noVideoTools(adapter, ctx.model);
16412
- return adapter.videoToolStatus(sub, ctx);
16413
- },
16414
- async videoToolResult(sub, call = {}) {
16415
- const { webhook, ...rest } = call;
16416
- const { adapter, ctx } = videoToolTarget(sub.model, rest);
16417
- if (!adapter.videoToolResult) throw noVideoTools(adapter, ctx.model);
16418
- const result = await adapter.videoToolResult(sub, ctx, webhook);
16419
- const base = { ...result.usage, model: ctx.model.id, unit: ctx.model.usage.unit };
16420
- const usage3 = sub.submittedAt === void 0 ? base : timed(base, sub.submittedAt);
16421
- await emit(usage3);
16422
- return { ...result, usage: usage3 };
16423
- },
16424
- async cancelVideoTool(sub, call = {}) {
16425
- const { adapter, ctx } = videoToolTarget(sub.model, call);
16426
- if (!adapter.cancelVideoTool) throw noVideoTools(adapter, ctx.model);
16427
- return adapter.cancelVideoTool(sub, ctx);
16428
- },
17273
+ submitVideoTool: videoToolJobs.submit,
17274
+ videoToolStatus: videoToolJobs.status,
17275
+ videoToolResult: videoToolJobs.result,
17276
+ cancelVideoTool: videoToolJobs.cancel,
17277
+ submitModel3d: model3dJobs.submit,
17278
+ model3dStatus: model3dJobs.status,
17279
+ model3dResult: model3dJobs.result,
17280
+ cancelModel3d: model3dJobs.cancel,
16429
17281
  usageProvider(modelId, call = {}) {
16430
17282
  const entry = catalog.require(modelId);
16431
17283
  if (entry.type !== "text") return entry.adapter;
@@ -16573,6 +17425,8 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
16573
17425
  InputSpecSchema,
16574
17426
  JsonObjectSchema,
16575
17427
  JsonValueSchema,
17428
+ MODEL3D_IMAGE_SLOTS,
17429
+ MODEL3D_MODELS,
16576
17430
  MODELS,
16577
17431
  ModelKitError,
16578
17432
  SURFACES,
@@ -16615,6 +17469,14 @@ var describe = (modelId) => createDefaultModelKit().describe(modelId);
16615
17469
  liveState,
16616
17470
  mergeTextProviderOptions,
16617
17471
  missingTierKeys,
17472
+ model3dCall,
17473
+ model3dConstraints,
17474
+ model3dInputRefusal,
17475
+ model3dPricingSku,
17476
+ model3dResolution,
17477
+ model3dSeedFits,
17478
+ model3dSkus,
17479
+ model3dTexture,
16618
17480
  nearestAspectRatio,
16619
17481
  normalizeExposure,
16620
17482
  openaiImageAdapter,