@shop-os/modelkit 0.7.3 → 0.7.4

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/CHANGELOG.md CHANGED
@@ -9,6 +9,13 @@ header in the release PR.
9
9
 
10
10
  ## [Unreleased]
11
11
 
12
+ ## [0.7.4] - Unreleased
13
+
14
+ ENG-3321: one source of truth for each 3D family's options.
15
+
16
+ ### Changed
17
+ - The 3D family rules (`MODEL3D_FAMILY_RULES`, `model3dSpecIssues`) move from the catalog schema to `catalog/model3d-spec.ts`. Each family's texture and resolution options are now a map to the value the fal request sends (Hi3D `quality`/`master` to `2048quality`/`2048master`; Tripo `texture_quality`; Hunyuan `generate_type`; Meshy's text `mode`; Hi3D `enable_texture`). The catalog check allows only the map's keys and `model3dCall` sends its values, so an option cannot be offered without a value to send. An option missing from the map (only possible on an unvalidated `catalogOverride` row) now fails with `unsupported_option` instead of being sent as the family's default. Every request the current rows can make sends the same body as before.
18
+
12
19
  ## [0.7.3] - Unreleased
13
20
 
14
21
  ENG-3272 Luma code review follow-ups.
package/dist/catalog.cjs CHANGED
@@ -6633,6 +6633,161 @@ var MODEL3D_IMAGE_SLOTS = {
6633
6633
  ordered: ["image", "left", "back", "right"],
6634
6634
  unordered: ["image", "back", "left", "right", "top"]
6635
6635
  };
6636
+ var MODEL3D_FAMILY_RULES = {
6637
+ trellis: {
6638
+ textPath: false,
6639
+ views: ["none"],
6640
+ multiImage: false,
6641
+ texture: null,
6642
+ pbr: false,
6643
+ seed: true,
6644
+ textureRef: false,
6645
+ resolutions: "integer"
6646
+ },
6647
+ hunyuan: {
6648
+ textPath: true,
6649
+ views: ["none", "named"],
6650
+ multiImage: false,
6651
+ // generate_type
6652
+ texture: { none: "Geometry", standard: "Normal" },
6653
+ pbr: true,
6654
+ seed: false,
6655
+ textureRef: false,
6656
+ resolutions: null
6657
+ },
6658
+ tripo: {
6659
+ textPath: true,
6660
+ views: ["none", "ordered"],
6661
+ multiImage: true,
6662
+ // texture_quality; null sends an untextured model.
6663
+ texture: { none: null, standard: "standard", detailed: "detailed" },
6664
+ pbr: true,
6665
+ seed: true,
6666
+ textureRef: false,
6667
+ resolutions: null
6668
+ },
6669
+ rodin: {
6670
+ textPath: true,
6671
+ views: ["none", "unordered"],
6672
+ multiImage: false,
6673
+ texture: null,
6674
+ pbr: false,
6675
+ seed: true,
6676
+ textureRef: false,
6677
+ resolutions: null
6678
+ },
6679
+ meshy: {
6680
+ textPath: true,
6681
+ views: ["none", "unordered"],
6682
+ multiImage: true,
6683
+ // The text endpoint's mode; the image endpoints take should_texture.
6684
+ texture: { none: "preview", standard: "full" },
6685
+ pbr: true,
6686
+ seed: true,
6687
+ textureRef: true,
6688
+ resolutions: null
6689
+ },
6690
+ hi3d: {
6691
+ textPath: false,
6692
+ views: ["none", "named"],
6693
+ multiImage: true,
6694
+ // enable_texture
6695
+ texture: { none: false, standard: true },
6696
+ pbr: true,
6697
+ seed: false,
6698
+ textureRef: false,
6699
+ resolutions: { quality: "2048quality", master: "2048master" }
6700
+ },
6701
+ sam: {
6702
+ textPath: false,
6703
+ views: ["none"],
6704
+ multiImage: false,
6705
+ texture: null,
6706
+ pbr: false,
6707
+ seed: true,
6708
+ textureRef: false,
6709
+ resolutions: null
6710
+ }
6711
+ };
6712
+ function model3dSpecIssues(spec) {
6713
+ const issues = [];
6714
+ const add = (path, message) => issues.push({ path, message });
6715
+ const rules = MODEL3D_FAMILY_RULES[spec.family];
6716
+ const promptOnly = spec.text && !spec.imageRequired;
6717
+ if (spec.endpoints.image === void 0)
6718
+ add(["endpoints", "image"], "every row needs an image endpoint");
6719
+ if (promptOnly && !rules.textPath) {
6720
+ add(
6721
+ ["imageRequired"],
6722
+ `${spec.family} has no text-to-3D endpoint; a text row needs an image`
6723
+ );
6724
+ }
6725
+ if (promptOnly && spec.endpoints.text === void 0) {
6726
+ add(["endpoints", "text"], "a text row needs a text endpoint");
6727
+ }
6728
+ if (!rules.views.includes(spec.views)) {
6729
+ add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
6730
+ }
6731
+ if (spec.views === "none" && spec.maxImages !== 1) {
6732
+ add(["maxImages"], "a row without views takes 1 image");
6733
+ }
6734
+ if (spec.views === "unordered" && spec.maxImages < 2) {
6735
+ add(["maxImages"], "a row with views takes at least 2 images");
6736
+ }
6737
+ const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
6738
+ if (spec.views !== "none" && spec.maxImages > slots) {
6739
+ add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
6740
+ }
6741
+ if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
6742
+ add(
6743
+ ["maxImages"],
6744
+ `a row with ${spec.views} views takes ${slots} images (front and three sides)`
6745
+ );
6746
+ }
6747
+ if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
6748
+ add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
6749
+ }
6750
+ if (rules.texture === null) {
6751
+ if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
6752
+ } else {
6753
+ const allowed = rules.texture;
6754
+ if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
6755
+ if (new Set(spec.texture).size !== spec.texture.length)
6756
+ add(["texture"], "texture options repeat");
6757
+ for (const t of spec.texture) {
6758
+ if (!Object.hasOwn(allowed, t))
6759
+ add(["texture"], `${spec.family} has no "${t}" texture`);
6760
+ }
6761
+ }
6762
+ if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
6763
+ if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
6764
+ add(["pbr"], "PBR needs a textured option");
6765
+ }
6766
+ if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
6767
+ if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
6768
+ if (spec.textureRef && !rules.textureRef)
6769
+ add(["textureRef"], `${spec.family} takes no texture reference`);
6770
+ const res = spec.resolutions;
6771
+ if (rules.resolutions === null) {
6772
+ if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
6773
+ } else if (res === void 0) {
6774
+ add(["resolutions"], `${spec.family} needs its resolution options`);
6775
+ } else {
6776
+ if (!res.options.includes(res.default)) {
6777
+ add(["resolutions", "default"], "default must be an option");
6778
+ }
6779
+ if (new Set(res.options).size !== res.options.length) {
6780
+ add(["resolutions", "options"], "resolution options repeat");
6781
+ }
6782
+ const allowed = rules.resolutions;
6783
+ for (const option of res.options) {
6784
+ const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : Object.hasOwn(allowed, option);
6785
+ if (!ok)
6786
+ add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
6787
+ }
6788
+ }
6789
+ return issues;
6790
+ }
6636
6791
  function model3dInputRefusal(spec, wired) {
6637
6792
  const top = spec.views === "unordered" && wired.top === true;
6638
6793
  const anyView = spec.views !== "none" && (wired.back || wired.left || wired.right || top);
@@ -7214,156 +7369,6 @@ var LanguageOptionSchema = import_zod3.z.looseObject({
7214
7369
  code: import_zod3.z.string().min(1),
7215
7370
  name: import_zod3.z.string().min(1)
7216
7371
  });
7217
- var MODEL3D_FAMILY_RULES = {
7218
- trellis: {
7219
- textPath: false,
7220
- views: ["none"],
7221
- multiImage: false,
7222
- texture: null,
7223
- pbr: false,
7224
- seed: true,
7225
- textureRef: false,
7226
- resolutions: "integer"
7227
- },
7228
- hunyuan: {
7229
- textPath: true,
7230
- views: ["none", "named"],
7231
- multiImage: false,
7232
- texture: ["none", "standard"],
7233
- pbr: true,
7234
- seed: false,
7235
- textureRef: false,
7236
- resolutions: null
7237
- },
7238
- tripo: {
7239
- textPath: true,
7240
- views: ["none", "ordered"],
7241
- multiImage: true,
7242
- texture: ["none", "standard", "detailed"],
7243
- pbr: true,
7244
- seed: true,
7245
- textureRef: false,
7246
- resolutions: null
7247
- },
7248
- rodin: {
7249
- textPath: true,
7250
- views: ["none", "unordered"],
7251
- multiImage: false,
7252
- texture: null,
7253
- pbr: false,
7254
- seed: true,
7255
- textureRef: false,
7256
- resolutions: null
7257
- },
7258
- meshy: {
7259
- textPath: true,
7260
- views: ["none", "unordered"],
7261
- multiImage: true,
7262
- texture: ["none", "standard"],
7263
- pbr: true,
7264
- seed: true,
7265
- textureRef: true,
7266
- resolutions: null
7267
- },
7268
- hi3d: {
7269
- textPath: false,
7270
- views: ["none", "named"],
7271
- multiImage: true,
7272
- texture: ["none", "standard"],
7273
- pbr: true,
7274
- seed: false,
7275
- textureRef: false,
7276
- resolutions: ["quality", "master"]
7277
- },
7278
- sam: {
7279
- textPath: false,
7280
- views: ["none"],
7281
- multiImage: false,
7282
- texture: null,
7283
- pbr: false,
7284
- seed: true,
7285
- textureRef: false,
7286
- resolutions: null
7287
- }
7288
- };
7289
- function model3dSpecIssues(spec) {
7290
- const issues = [];
7291
- const add = (path, message) => issues.push({ path, message });
7292
- const rules = MODEL3D_FAMILY_RULES[spec.family];
7293
- const promptOnly = spec.text && !spec.imageRequired;
7294
- if (spec.endpoints.image === void 0)
7295
- add(["endpoints", "image"], "every row needs an image endpoint");
7296
- if (promptOnly && !rules.textPath) {
7297
- add(
7298
- ["imageRequired"],
7299
- `${spec.family} has no text-to-3D endpoint; a text row needs an image`
7300
- );
7301
- }
7302
- if (promptOnly && spec.endpoints.text === void 0) {
7303
- add(["endpoints", "text"], "a text row needs a text endpoint");
7304
- }
7305
- if (!rules.views.includes(spec.views)) {
7306
- add(["views"], `${spec.family} takes views ${rules.views.join(" or ")}`);
7307
- }
7308
- if (spec.views === "none" && spec.maxImages !== 1) {
7309
- add(["maxImages"], "a row without views takes 1 image");
7310
- }
7311
- if (spec.views === "unordered" && spec.maxImages < 2) {
7312
- add(["maxImages"], "a row with views takes at least 2 images");
7313
- }
7314
- const slots = MODEL3D_IMAGE_SLOTS[spec.views].length;
7315
- if (spec.views !== "none" && spec.maxImages > slots) {
7316
- add(["maxImages"], `a row with ${spec.views} views sends at most ${slots} images`);
7317
- }
7318
- if ((spec.views === "named" || spec.views === "ordered") && spec.maxImages < slots) {
7319
- add(
7320
- ["maxImages"],
7321
- `a row with ${spec.views} views takes ${slots} images (front and three sides)`
7322
- );
7323
- }
7324
- if (spec.views !== "none" && rules.multiImage && spec.endpoints.multiImage === void 0) {
7325
- add(["endpoints", "multiImage"], `${spec.family} sends views to a multi-image endpoint`);
7326
- }
7327
- if (rules.texture === null) {
7328
- if (spec.texture.length > 0) add(["texture"], `${spec.family} has no texture switch`);
7329
- } else {
7330
- const allowed = rules.texture;
7331
- if (spec.texture.length === 0) add(["texture"], `${spec.family} needs its texture options`);
7332
- if (new Set(spec.texture).size !== spec.texture.length)
7333
- add(["texture"], "texture options repeat");
7334
- for (const t of spec.texture) {
7335
- if (!allowed.includes(t)) add(["texture"], `${spec.family} has no "${t}" texture`);
7336
- }
7337
- }
7338
- if (spec.pbr && !rules.pbr) add(["pbr"], `${spec.family} has no PBR switch`);
7339
- if (spec.pbr && !spec.texture.some((t) => t !== "none")) {
7340
- add(["pbr"], "PBR needs a textured option");
7341
- }
7342
- if (spec.seed && !rules.seed) add(["seed"], `${spec.family} takes no seed`);
7343
- if (spec.seedMax !== void 0 && !spec.seed) add(["seedMax"], "seedMax needs seed");
7344
- if (spec.textureRef && !rules.textureRef)
7345
- add(["textureRef"], `${spec.family} takes no texture reference`);
7346
- const res = spec.resolutions;
7347
- if (rules.resolutions === null) {
7348
- if (res !== void 0) add(["resolutions"], `${spec.family} has no resolution option`);
7349
- } else if (res === void 0) {
7350
- add(["resolutions"], `${spec.family} needs its resolution options`);
7351
- } else {
7352
- if (!res.options.includes(res.default)) {
7353
- add(["resolutions", "default"], "default must be an option");
7354
- }
7355
- if (new Set(res.options).size !== res.options.length) {
7356
- add(["resolutions", "options"], "resolution options repeat");
7357
- }
7358
- const allowed = rules.resolutions;
7359
- for (const option of res.options) {
7360
- const ok = allowed === "integer" ? /^[1-9][0-9]*$/.test(option) : allowed.includes(option);
7361
- if (!ok)
7362
- add(["resolutions", "options"], `${spec.family} has no "${option}" resolution`);
7363
- }
7364
- }
7365
- return issues;
7366
- }
7367
7372
  var VideoToolConstraintsSchema = import_zod3.z.looseObject({
7368
7373
  kind: import_zod3.z.enum(["upscale", "interpolate", "hdr", "bg-remove", "subtitles"]),
7369
7374
  upscaleFactor: RangeSchema.optional(),