threenative-asset-mcp 0.10.0 → 0.12.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.
Files changed (73) hide show
  1. package/README.md +38 -1
  2. package/dist/blendkit/client.d.ts +112 -0
  3. package/dist/blendkit/client.d.ts.map +1 -0
  4. package/dist/blendkit/client.js +346 -0
  5. package/dist/blendkit/client.js.map +1 -0
  6. package/dist/blendkit/provider.d.ts +234 -0
  7. package/dist/blendkit/provider.d.ts.map +1 -0
  8. package/dist/blendkit/provider.js +507 -0
  9. package/dist/blendkit/provider.js.map +1 -0
  10. package/dist/server.d.ts +2 -0
  11. package/dist/server.d.ts.map +1 -1
  12. package/dist/server.js +37 -1
  13. package/dist/server.js.map +1 -1
  14. package/dist/tools/blendkit.d.ts +143 -0
  15. package/dist/tools/blendkit.d.ts.map +1 -0
  16. package/dist/tools/blendkit.js +145 -0
  17. package/dist/tools/blendkit.js.map +1 -0
  18. package/dist/tools/source-directory.d.ts.map +1 -1
  19. package/dist/tools/source-directory.js +15 -0
  20. package/dist/tools/source-directory.js.map +1 -1
  21. package/dist/unreal/animation-data.d.ts +342 -0
  22. package/dist/unreal/animation-data.d.ts.map +1 -0
  23. package/dist/unreal/animation-data.js +375 -0
  24. package/dist/unreal/animation-data.js.map +1 -0
  25. package/dist/unreal/contact-sheet.d.ts +17 -0
  26. package/dist/unreal/contact-sheet.d.ts.map +1 -1
  27. package/dist/unreal/contact-sheet.js +32 -5
  28. package/dist/unreal/contact-sheet.js.map +1 -1
  29. package/dist/unreal/cooking.d.ts +69 -0
  30. package/dist/unreal/cooking.d.ts.map +1 -1
  31. package/dist/unreal/cooking.js +272 -4
  32. package/dist/unreal/cooking.js.map +1 -1
  33. package/dist/unreal/cue4parse-adapter.d.ts +1 -1
  34. package/dist/unreal/cue4parse-adapter.d.ts.map +1 -1
  35. package/dist/unreal/cue4parse-adapter.js +3094 -117
  36. package/dist/unreal/cue4parse-adapter.js.map +1 -1
  37. package/dist/unreal/effects-dump.d.ts +81 -0
  38. package/dist/unreal/effects-dump.d.ts.map +1 -0
  39. package/dist/unreal/effects-dump.js +113 -0
  40. package/dist/unreal/effects-dump.js.map +1 -0
  41. package/dist/unreal/effects-preview.d.ts +76 -0
  42. package/dist/unreal/effects-preview.d.ts.map +1 -0
  43. package/dist/unreal/effects-preview.js +386 -0
  44. package/dist/unreal/effects-preview.js.map +1 -0
  45. package/dist/unreal/effects-schema.d.ts +1797 -0
  46. package/dist/unreal/effects-schema.d.ts.map +1 -0
  47. package/dist/unreal/effects-schema.js +1670 -0
  48. package/dist/unreal/effects-schema.js.map +1 -0
  49. package/dist/unreal/game-path.d.ts +7 -0
  50. package/dist/unreal/game-path.d.ts.map +1 -0
  51. package/dist/unreal/game-path.js +12 -0
  52. package/dist/unreal/game-path.js.map +1 -0
  53. package/dist/unreal/gameplay-data.d.ts +350 -0
  54. package/dist/unreal/gameplay-data.d.ts.map +1 -0
  55. package/dist/unreal/gameplay-data.js +534 -0
  56. package/dist/unreal/gameplay-data.js.map +1 -0
  57. package/dist/unreal/importer.d.ts +137 -4
  58. package/dist/unreal/importer.d.ts.map +1 -1
  59. package/dist/unreal/importer.js +1016 -49
  60. package/dist/unreal/importer.js.map +1 -1
  61. package/dist/unreal/psa.d.ts +45 -1
  62. package/dist/unreal/psa.d.ts.map +1 -1
  63. package/dist/unreal/psa.js +95 -12
  64. package/dist/unreal/psa.js.map +1 -1
  65. package/dist/unreal/scenes.d.ts +12 -0
  66. package/dist/unreal/scenes.d.ts.map +1 -1
  67. package/dist/unreal/scenes.js +40 -2
  68. package/dist/unreal/scenes.js.map +1 -1
  69. package/dist/unreal/static-mesh-sections.d.ts +16 -0
  70. package/dist/unreal/static-mesh-sections.d.ts.map +1 -1
  71. package/dist/unreal/static-mesh-sections.js +108 -14
  72. package/dist/unreal/static-mesh-sections.js.map +1 -1
  73. package/package.json +1 -1
package/README.md CHANGED
@@ -145,10 +145,36 @@ Fab:
145
145
  flows.
146
146
  - `asset_import_unreal` — converts an already-downloaded Unreal directory to
147
147
  self-contained GLBs plus `import-report.json`; Unreal Engine is not required.
148
+ Cascade `ParticleSystem` and Niagara systems are exported as data-only
149
+ descriptors under `Effects/<system>-<hash>.<cascade|niagara>.json`, one per
150
+ canonical package and object path so two same-basename systems in different
151
+ folders stay distinct. No runtime plays them: each descriptor lists the
152
+ modules and inputs it does not carry, and a placed effect component points at
153
+ its descriptor through `import-report.json`. Effects with no exported
154
+ descriptor stay named in the report; the importer never reconstructs a
155
+ particle simulation.
148
156
  - `fab_import_asset` — downloads an owned listing through the user's existing
149
157
  FabCLI session, then runs the same Unreal importer. It never signs in, claims,
150
158
  or purchases an asset.
151
159
 
160
+ Blendkit (through the user's own official Blendkit-Client; see
161
+ [docs/blendkit-integration.md](docs/blendkit-integration.md)):
162
+
163
+ - `blendkit_status` — local-only health: whether the Client runs on loopback,
164
+ its version and `export_glb` recipe, whether live access is enabled, and the
165
+ setup steps still missing. It never contacts Blendkit.
166
+ - `blendkit_import_asset` — acquires one free Blendkit model through the Client,
167
+ converts it with the Client's bundled `export_glb` recipe under headless
168
+ Blender, inspects the GLB (meshes, triangles, PBR texture slots, size) and
169
+ writes a provenance file. It needs the item's license acknowledgement and
170
+ explicit project-use consent, and it refuses paid items and unknown licenses.
171
+ The output is private use only: the Blendkit Terms forbid open-format models
172
+ such as GLB in software and apply that to CC0-labelled items too. It never
173
+ goes into game builds, demos or starter kits, and `purpose: "redistribution"`
174
+ is always refused. Existing outputs are never overwritten. Live search and
175
+ import stay off until `BLENDKIT_PROVIDER_PERMISSION` is set. With it,
176
+ `asset_search` also searches Blendkit.
177
+
152
178
  Poly Haven:
153
179
 
154
180
  - `polyhaven_search_assets` — searches HDRIs, textures, and models by text,
@@ -383,6 +409,9 @@ it out of process. Modern UE5 packages rejected by UE Viewer use a pinned,
383
409
  out-of-process CUE4Parse adapter. Set `THREENATIVE_TOOLCHAIN_AUTOINSTALL=0` to
384
410
  require manually installed tools instead.
385
411
 
412
+ **Supported, verified and missing formats:** [`docs/unreal-format-support.md`](docs/unreal-format-support.md)
413
+ is the tracking ledger for every Unreal 4 and 5 class, with its status, evidence and gaps.
414
+
386
415
  ### Fab login for owned packs
387
416
 
388
417
  `fab_import_asset` and `fab_list_owned` read your Fab library through
@@ -430,8 +459,9 @@ sweep's `--no-graph-bake` uses this to produce a baseline).
430
459
  | --- | --- |
431
460
  | Cooked loose UE4 static meshes and textures | GLB geometry, LOD sections, embedded textures, and common PBR reconstruction |
432
461
  | Cooked loose UE4 skeletal meshes and standalone animation packages | Standard skinned GLB; joints, weights, inverse-bind matrices, and existing clips are preserved; ActorX PSA clips are attached by case-insensitive bone name when at least 80% of tracks match, without duplicating an existing clip name |
462
+ | UE5 `AnimSequence`, blend spaces, aim offsets, montages and composites | UE5.0–5.5 conventional clips and UE5.4+ FK Sequencer-model clips become glTF animations and attach by bone name; blend spaces, aim offsets, montages and composites become `Animation/<name>.json` with typed axes, mirror flags and resolved section starts, and `<clip>.clip.json` sidecars preserve notifies, curves and sync markers. Current release 0.12.0 / importer124 / converter `.584.10.2` fresh public/native proof retains 325 selected UE5.4 clips and 7 UE5.8 clips. Independent actual UE5.8.3 full-pose comparison passes 7 clips, 8 GLB-document comparisons and 72,233 keys (actual current maximum 0.000264° against 0.5°); scope is serialized raw bones, excluding only 2 independently declared mannequin virtuals and no face bones. Static poses remain intact; non-FK graphs remain reported. Current independent replay and all four local repository gates pass (PRD-596); selected clips do not prove whole-pack or generated-virtual-bone support. |
433
463
  | Uncooked UE4 `FMeshDescription` static meshes (object versions 517–522) | GLB geometry with centimetres converted to metres; verified on Fab Office Pack Vol.1 (47/47 meshes) |
434
- | Uncooked UE5 editor static meshes (source models only, no render data) | LOD0 of the `FMeshDescription` source model is decoded from the package trailer's Oodle payloads, with the cooked glTF writer's axes, scale, and material naming. Verified on Fab's Megascans Common Hazel and European Hornbeam UE5.1 artifacts: triangle counts match the UE4.27 decoder of the same scans exactly |
464
+ | Uncooked UE5 editor static meshes (source models only, no render data) | Requested payload-backed `FMeshDescription` source models are decoded from the package trailer's Oodle payloads as `Models/<name>_LOD<n>.glb`; `BuildScale3D` from `SourceModels[0].BuildSettings` is applied on the modern route. Source models Unreal generates at build time are reported as generated and are not faked. Verified on Fab's Megascans European Hornbeam UE5.1 artifact for LOD0/1/2 |
435
465
  | Uncooked UE4.0–4.20 static and skeletal meshes (object versions below 517) | Exported by UE Viewer from the editor source data, with materials, skins, and ActorX clips like cooked packages. Verified on Fab packs from UE4.10 to UE4.20: Modular Building Set (129 meshes), Animal Variety Pack (6 rigged animals, 146 clips), STF Landscape Pro 2.0 (61), Power Plant (65), and a UE4.19 fern pack (38) |
436
466
  | Standalone `Texture2D` packages | Collision-free source-relative PNGs under `textures/`; duplicate Unreal basenames are exported independently instead of overwriting one another |
437
467
  | `Texture2D` with an `RGBA16F` source | Raw little-endian half-float RGBA binaries and a versioned JSON manifest under `data-textures/`, promoted together under the package's qualified path. Values are stored, not decoded: no PivotPainter, classifier, source UV, graph or WPO semantics, and no material binding. The PNG exporters cannot encode the format, so the importer asks the converter for this route after a legacy PNG export fails; a UE 4.x pack needs its `engine` (`UE_4.19`), since the default detector reads every UE4 package as the latest UE4. Loaded in the browser with `threenative-asset-mcp/data-texture` (see Three.js usage) |
@@ -439,6 +469,7 @@ sweep's `--no-graph-bake` uses this to produce a baseline).
439
469
  | `Texture2DArray`, `TextureCubeArray`, and `VolumeTexture` | Collision-free RGBA8 slice data plus JSON dimensions under `textures3d/`; use `DataArrayTexture` for arrays and `Data3DTexture` for volumes. Cube-array faces remain ordered in groups of six for custom shaders. Floating-point/HDR stacks are rejected rather than reduced to RGBA8 |
440
470
  | Standalone `Material` and `MaterialInstanceConstant` packages | One directly loadable `Materials/UnrealMaterialLibrary.glb`; each source-relative swatch name is collision-free, follows parent instances, embeds resolved texture inputs, and applies common base-color/emissive vectors plus roughness/metallic/opacity scalars |
441
471
  | Standalone `SoundWave` packages | Collision-free WAV/Ogg/MP3/FLAC files under `audio/`; modern UE5 editor source WAVs and cooked formats exposed by CUE4Parse feed the same report path, verified through Three.js `AudioLoader` |
472
+ | Skeletal and static mesh sockets, static-mesh simple collision, `PhysicsAsset`, and `SoundCue` graphs | Socket nodes (`socket:<name>`) under the joint their bone names (or the mesh node for a static socket); simple collision on the mesh node's `extras.unrealCollision` and in `Collision/<package>.json`; physics bodies, constraints (limits, motions and drives) and collision-disabled pairs in metre-scale `Physics/<asset>.json`, referenced from the skinned mesh node; and each SoundCue graph in `Audio/<cue>.cue.json` with every `WavePlayer` leaf rewritten to the exported audio file or reported as a missing wave. A UE4 package that holds one of these classes routes to the CUE4Parse adapter, which UE Viewer cannot decode; an ordinary UE4 mesh whose only gameplay signal is a `BodySetup` or a cross-package PhysicsAsset/Skeleton reference joins the adapter run for its metadata while keeping its verified UE Viewer geometry route |
442
473
  | Runtime `Font` and inline `FontFace` packages | Validated TTF/OTF faces under collision-free `fonts/` paths; direct SFNT and legacy multi-block zlib `FontBulkData` are supported without Unreal Engine, with family/style/weight metadata for the browser `FontFace` API |
443
474
  | Offline `Font` packages | Pre-baked glyph pages and serialized `FontCharacter` rectangles become collision-safe atlas PNGs plus BMFont-compatible JSON under `bitmap-fonts/`; Unicode remaps, baseline metrics, kerning, page indices, and distance-field metadata are retained for Three.js bitmap/SDF text |
444
475
  | Paper2D `PaperSprite` and `PaperFlipbook` packages | Each sprite becomes a self-contained, unlit GLB with exact baked triangles and a cropped atlas region; flipbooks become JSON manifests preserving FPS and per-frame run lengths. Verified in Three.js on a real UE5.2 Paper2D project without Unreal Engine |
@@ -448,9 +479,11 @@ sweep's `--no-graph-bake` uses this to produce a baseline).
448
479
  | Modern UE5 loose static meshes, skeletal meshes, `Texture2D`, Material, and `.umap` packages rejected by UE Viewer | CUE4Parse converts directly to the same output/report pipeline; verified with UE5.5 cooked static geometry, UE5 editor skeletal geometry, Oodle-compressed UE5.3 editor texture source art, and a UE5.2 Paper2D map. Editor source art is restored to display colour: `TSF_BGRA8` sources are stored with red and blue swapped, and sRGB-sampled `TSF_RGBA16` sources are linear, so both are corrected (checked against UE Viewer's export of the same textures from the UE4.27 artifact). Cooked packages using unversioned properties require one matching `.usmap` file beside the imported tree |
449
480
  | Separate roughness/metalness, solid palette maps, glass, and mirrors | Packed glTF PBR maps or explicit material fallbacks; extra graph inputs remain named sidecars |
450
481
  | UE4 `.umap` placement, direct lights, and serialized Blueprint component templates (object versions 517–522) | Directly loadable scene GLB plus a transform/source manifest; repeated actors instance shared meshes; inherited mesh/light defaults are merged into placed instances; directional, point, and spot lights use `KHR_lights_punctual` |
482
+ | UE5 World Partition `.umap` external actors | The selected level export loads `__ExternalActors__` packages with the same provider mount and complete map path into the scene; external actor/object packages belonging to maps outside the import remain reported as skipped. Real-pack verification is tracked by PRD-598 |
451
483
  | Standalone modern UE5 Blueprint prefabs | Serialized static/skeletal mesh and light component defaults become directly loadable scene GLBs; referenced meshes, transforms, skins, and bone hierarchies are retained, while bytecode is explicitly reported and never executed |
452
484
  | UE4 ISM/HISM and painted static-mesh foliage placement | Bulk-serialized instance matrices become `EXT_mesh_gpu_instancing`, which Three.js `GLTFLoader` loads as GPU-instanced meshes |
453
485
  | UE4 editor `LandscapeComponent` heightfields | Package-relative compressed BGRA8 heightmaps become indexed terrain meshes with decoded normals, component transforms, and original material names |
486
+ | UE5 level `Landscape` and `LandscapeStreamingProxy` heightfields | CUE4Parse follows every proxy component, restores trailer-backed BGRA8 source pixels, and emits indexed terrain meshes with decoded heights, normals, proxy-root transforms, and material identity |
454
487
  | ActorX per-frame bone scale, dynamic Blueprint bytecode/construction scripts, Paper Terrain/spline deformation, and Nanite-only data without a fallback mesh | Detected or reported honestly; scene-level omissions are listed in `scenes[].omittedActors`, and Blueprint bytecode is never executed by the importer |
455
488
  | Arbitrary Unreal shader graphs | Recoverable PBR inputs become standard glTF materials. Reports mark materials as degraded when shader connections are unavailable, even if every section has a texture; section `limitations` explain omitted layering, graph UV transforms, subsurface lighting, normal strength, and deformation |
456
489
  | Encrypted Pak/IoStore | Unsupported without user-supplied keys and archive extraction; never reported as a complete conversion |
@@ -714,6 +747,10 @@ new `--out`, or add `--no-sheets`. Profiles and binaries derive from licensed pa
714
747
  | `ASSET_PROVIDER_TIMEOUT_MS` | `8000` | Provider deadline; range 1–30000 milliseconds. |
715
748
  | `ASSET_SEARCH_TIMEOUT_MS` | `10000` | Aggregate search/metadata deadline including queue time; range 1–60000. |
716
749
  | `ASSET_PLAN_TTL_MS` | `300000` | Acquisition-plan TTL; range 1–900000; at most 100 bounded plans. |
750
+ | `BLENDKIT_CLIENT_URL` | `http://127.0.0.1:62485` | Loopback address of the user's official Blendkit-Client; other hosts fail. |
751
+ | `BLENDKIT_PROVIDER_PERMISSION` | unset | Citation of documented Blendkit permission for this use. Unset keeps live Blendkit search and import off. |
752
+ | `BLENDKIT_API_KEY` | unset | **Your own** key from the official Blendkit sign-in; sent only to the loopback Client, never logged or returned. |
753
+ | `BLENDKIT_BLENDER_PATH` | Client-stored Blender | Absolute path to the Blender that runs the `export_glb` recipe. |
717
754
  | `THREENATIVE_TOOLCHAIN_AUTOINSTALL` | `1` | Set to `0` to disable first-use external-tool installs. |
718
755
  | `THREENATIVE_TOOLCHAIN_DIR` | OS cache under `threenative-asset-mcp/toolchain` | UE Viewer, FabCLI, and uncooked-converter cache. |
719
756
  | `THREENATIVE_UMODEL_PATH` | auto-detected/provisioned | Absolute path to a UE Viewer executable override. |
@@ -0,0 +1,112 @@
1
+ /**
2
+ * HTTP client for the official Blendkit-Client (https://github.com/BlenderKit/bk_client), a
3
+ * GPL-2.0-or-later Go service the user installs and runs. This module only speaks its documented
4
+ * local HTTP API (client/docs/API.md, v1.13.6); it bundles and copies none of its code.
5
+ *
6
+ * Asynchronous work (search, download, tool runs) returns a task_id; the result arrives through
7
+ * POST /report, which also hands each finished or failed task out exactly once.
8
+ */
9
+ export type BlendkitErrorCode = "BLENDKIT_INVALID_INPUT" | "BLENDKIT_UNSAFE_URL" | "BLENDKIT_CLIENT_UNAVAILABLE" | "BLENDKIT_INVALID_RESPONSE" | "BLENDKIT_TASK_FAILED" | "BLENDKIT_TIMEOUT" | "BLENDKIT_CANCELLED" | "BLENDKIT_PERMISSION_REQUIRED" | "BLENDKIT_NOT_FOUND" | "BLENDKIT_PAID_DENIED" | "BLENDKIT_AUTH_REQUIRED" | "BLENDKIT_LICENSE_DENIED" | "BLENDKIT_CONSENT_REQUIRED" | "BLENDKIT_UNSUPPORTED" | "BLENDKIT_CONVERSION_FAILED" | "BLENDKIT_OUTPUT_EXISTS" | "BLENDKIT_PUBLISH_FAILED" | "BLENDKIT_PARTIAL_OUTPUT" | "BLENDKIT_CLIENT_ERROR" | "BLENDKIT_STAGING_RETAINED";
10
+ export declare class BlendkitError extends Error {
11
+ readonly code: BlendkitErrorCode;
12
+ constructor(code: BlendkitErrorCode, message: string);
13
+ }
14
+ export declare const DEFAULT_CLIENT_URL = "http://127.0.0.1:62485";
15
+ /** The Client is a local service: only plain-HTTP loopback origins are accepted. */
16
+ export declare function loopbackOrigin(raw: string): string;
17
+ /**
18
+ * Task text comes from the Client and the provider: bounded, single-line, with any configured
19
+ * credential (plain text, not only inside a URL) and every URL, signed or not, removed.
20
+ */
21
+ export declare function safeTaskText(value: unknown, secrets?: Iterable<string>): string;
22
+ /**
23
+ * True only for an OBSERVED terminal task state (the Client's /report said the task failed or was
24
+ * cancelled). A transport error such as HTTP 500 or an unreachable Client proves nothing about
25
+ * whether a Go download or a Blender export is still writing.
26
+ */
27
+ export declare function taskEnded(error: unknown): boolean;
28
+ /** A task failed or was aborted and the Client did not confirm that it stopped writing. */
29
+ export declare class UnconfirmedStopError extends Error {
30
+ readonly reason: unknown;
31
+ constructor(reason: unknown);
32
+ }
33
+ export type BlendkitTask = {
34
+ taskId: string;
35
+ taskType: string;
36
+ status: string;
37
+ progress: number;
38
+ message: string;
39
+ result: unknown;
40
+ };
41
+ export type TaskProgress = {
42
+ progress: number;
43
+ message: string;
44
+ };
45
+ export type BlendkitClientOptions = {
46
+ baseUrl?: string;
47
+ fetch?: typeof fetch;
48
+ requestTimeoutMs?: number;
49
+ maxResponseBytes?: number;
50
+ pollIntervalMs?: number;
51
+ /** How long to wait for the Client to report a cancelled download as over. */
52
+ cancelConfirmMs?: number;
53
+ appId?: number;
54
+ addonVersion?: string;
55
+ };
56
+ export declare class BlendkitClient {
57
+ readonly origin: string;
58
+ private readonly fetcher;
59
+ private readonly requestTimeoutMs;
60
+ private readonly maxResponseBytes;
61
+ private readonly pollIntervalMs;
62
+ private readonly cancelConfirmMs;
63
+ readonly appId: number;
64
+ private readonly addonVersion;
65
+ /** Stable scene identity for this client session, forwarded by the Client as scene_uuid. */
66
+ private readonly sceneId;
67
+ /** Terminal tasks /report handed over before their waiter asked; each is delivered once. */
68
+ private readonly done;
69
+ private readonly latest;
70
+ /** Tasks someone is waiting for: their parked results are never evicted. */
71
+ private readonly active;
72
+ /** Start requests in flight: their task id is unknown, so nothing may be evicted meanwhile. */
73
+ private pendingStarts;
74
+ /** API keys seen in requests, redacted from any task text the Client echoes back. */
75
+ private readonly secrets;
76
+ private polling;
77
+ constructor(options?: BlendkitClientOptions);
78
+ private identity;
79
+ private request;
80
+ /** Local-only health: neither endpoint subscribes this process or contacts the provider. */
81
+ status(signal: AbortSignal): Promise<{
82
+ clientVersion: string;
83
+ tools: string[];
84
+ }>;
85
+ /**
86
+ * A start request for work that writes files (download, recipe) can fail after the Client
87
+ * accepted it: the connection may drop or the answer may be malformed, and then there is no task
88
+ * id to cancel or watch. That is not proof that nothing runs, so it never counts as "not started".
89
+ */
90
+ private startWriter;
91
+ private startTask;
92
+ /**
93
+ * One /report request at a time, shared by every waiter, so it runs on its own deadline rather
94
+ * than one caller's signal. Terminal tasks are parked until their waiter takes them.
95
+ */
96
+ private poll;
97
+ private waitTask;
98
+ /** Starts a provider search whose URL the caller built and validated; returns the raw result. */
99
+ search(urlquery: string, pageSize: number, apiKey: string, signal: AbortSignal): Promise<unknown>;
100
+ /** Downloads one asset into downloadDir; a failure that is not an observed task end cancels the Client task. */
101
+ download(assetData: {
102
+ id: string;
103
+ name: string;
104
+ assetType: string;
105
+ files: unknown[];
106
+ }, downloadDir: string, resolution: string, apiKey: string, signal: AbortSignal, onProgress?: (progress: TaskProgress) => void): Promise<string[]>;
107
+ /** True only when the cancelled task was observed in a terminal state within the deadline. */
108
+ private cancelDownload;
109
+ /** Runs one bundled recipe under the user's headless Blender. The Client cannot cancel a run. */
110
+ runTool(scriptId: string, blendPath: string, outputPath: string, params: Record<string, unknown>, blenderExePath: string, signal: AbortSignal): Promise<string>;
111
+ }
112
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/blendkit/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,346 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { setTimeout as delay } from "node:timers/promises";
3
+ export class BlendkitError extends Error {
4
+ code;
5
+ constructor(code, message) {
6
+ super(message);
7
+ this.code = code;
8
+ this.name = "BlendkitError";
9
+ }
10
+ }
11
+ export const DEFAULT_CLIENT_URL = "http://127.0.0.1:62485";
12
+ const LOOPBACK_HOSTS = new Set(["127.0.0.1", "localhost", "[::1]"]);
13
+ /** The Client is a local service: only plain-HTTP loopback origins are accepted. */
14
+ export function loopbackOrigin(raw) {
15
+ let url;
16
+ try {
17
+ url = new URL(raw);
18
+ }
19
+ catch {
20
+ throw new BlendkitError("BLENDKIT_UNSAFE_URL", "The Blendkit-Client URL is not a valid URL.");
21
+ }
22
+ if (url.protocol !== "http:" ||
23
+ !LOOPBACK_HOSTS.has(url.hostname) ||
24
+ url.username ||
25
+ url.password ||
26
+ (url.pathname !== "/" && url.pathname !== "") ||
27
+ url.search ||
28
+ url.hash)
29
+ throw new BlendkitError("BLENDKIT_UNSAFE_URL", "The Blendkit-Client URL must be a loopback http origin such as http://127.0.0.1:62485.");
30
+ return url.origin;
31
+ }
32
+ /**
33
+ * Task text comes from the Client and the provider: bounded, single-line, with any configured
34
+ * credential (plain text, not only inside a URL) and every URL, signed or not, removed.
35
+ */
36
+ export function safeTaskText(value, secrets = []) {
37
+ if (typeof value !== "string")
38
+ return "";
39
+ // URLs go first: a short secret such as ":" would otherwise split "https://" and leave a
40
+ // signed link's token behind. Then one pass over the secrets, longest first.
41
+ const withoutUrls = value.replace(/[a-z][a-z0-9+.-]*:\/\/\S+/giu, "<url>");
42
+ const known = [...secrets].filter(Boolean).sort((a, b) => b.length - a.length);
43
+ const text = known.length
44
+ ? withoutUrls.replace(new RegExp(known.map((secret) => secret.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")).join("|"), "gu"), "<redacted>")
45
+ : withoutUrls;
46
+ return text
47
+ .replace(/[\p{Cc}\p{Cf}]+/gu, " ")
48
+ .trim()
49
+ .slice(0, 300);
50
+ }
51
+ /**
52
+ * True only for an OBSERVED terminal task state (the Client's /report said the task failed or was
53
+ * cancelled). A transport error such as HTTP 500 or an unreachable Client proves nothing about
54
+ * whether a Go download or a Blender export is still writing.
55
+ */
56
+ export function taskEnded(error) {
57
+ return (error instanceof BlendkitError &&
58
+ (error.code === "BLENDKIT_TASK_FAILED" || error.code === "BLENDKIT_CANCELLED"));
59
+ }
60
+ /** A task failed or was aborted and the Client did not confirm that it stopped writing. */
61
+ export class UnconfirmedStopError extends Error {
62
+ reason;
63
+ constructor(reason) {
64
+ super(reason instanceof Error ? reason.message : "The Client task was interrupted.");
65
+ this.reason = reason;
66
+ this.name = "UnconfirmedStopError";
67
+ }
68
+ }
69
+ const TERMINAL = new Set(["finished", "error", "cancelled"]);
70
+ export class BlendkitClient {
71
+ origin;
72
+ fetcher;
73
+ requestTimeoutMs;
74
+ maxResponseBytes;
75
+ pollIntervalMs;
76
+ cancelConfirmMs;
77
+ appId;
78
+ addonVersion;
79
+ /** Stable scene identity for this client session, forwarded by the Client as scene_uuid. */
80
+ sceneId = randomUUID();
81
+ /** Terminal tasks /report handed over before their waiter asked; each is delivered once. */
82
+ done = new Map();
83
+ latest = new Map();
84
+ /** Tasks someone is waiting for: their parked results are never evicted. */
85
+ active = new Set();
86
+ /** Start requests in flight: their task id is unknown, so nothing may be evicted meanwhile. */
87
+ pendingStarts = 0;
88
+ /** API keys seen in requests, redacted from any task text the Client echoes back. */
89
+ secrets = new Set();
90
+ polling;
91
+ constructor(options = {}) {
92
+ this.origin = loopbackOrigin(options.baseUrl ?? DEFAULT_CLIENT_URL);
93
+ this.fetcher = options.fetch ?? fetch;
94
+ this.requestTimeoutMs = options.requestTimeoutMs ?? 10_000;
95
+ this.maxResponseBytes = options.maxResponseBytes ?? 8 * 1024 * 1024;
96
+ this.pollIntervalMs = options.pollIntervalMs ?? 500;
97
+ this.cancelConfirmMs = options.cancelConfirmMs ?? 5000;
98
+ this.appId = options.appId ?? process.pid;
99
+ this.addonVersion = options.addonVersion ?? "0.0.0";
100
+ }
101
+ identity() {
102
+ return {
103
+ app_id: this.appId,
104
+ addon_version: this.addonVersion,
105
+ platform_version: `${process.platform}-${process.arch}`,
106
+ };
107
+ }
108
+ async request(path, body, signal, expectJson = true) {
109
+ const requestSignal = AbortSignal.any([signal, AbortSignal.timeout(this.requestTimeoutMs)]);
110
+ let response;
111
+ try {
112
+ response = await this.fetcher(new URL(path, this.origin), {
113
+ method: body === undefined ? "GET" : "POST",
114
+ redirect: "error",
115
+ signal: requestSignal,
116
+ ...(body === undefined
117
+ ? {}
118
+ : { headers: { "content-type": "application/json" }, body: JSON.stringify(body) }),
119
+ });
120
+ }
121
+ catch {
122
+ signal.throwIfAborted();
123
+ throw new BlendkitError("BLENDKIT_CLIENT_UNAVAILABLE", `No Blendkit-Client answered at ${this.origin}. Start the official client (see blendkit_status).`);
124
+ }
125
+ const declared = Number(response.headers.get("content-length") ?? 0);
126
+ if (declared > this.maxResponseBytes) {
127
+ await response.body?.cancel();
128
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Blendkit-Client response is too large.");
129
+ }
130
+ const chunks = [];
131
+ let size = 0;
132
+ for await (const chunk of response.body ?? []) {
133
+ size += chunk.byteLength;
134
+ if (size > this.maxResponseBytes)
135
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Blendkit-Client response is too large.");
136
+ chunks.push(chunk);
137
+ }
138
+ if (!response.ok)
139
+ throw new BlendkitError(response.status === 404 ? "BLENDKIT_UNSUPPORTED" : "BLENDKIT_CLIENT_ERROR", `Blendkit-Client ${path} answered HTTP ${response.status}.`);
140
+ if (!expectJson)
141
+ return undefined;
142
+ try {
143
+ return JSON.parse(Buffer.concat(chunks).toString("utf8"));
144
+ }
145
+ catch {
146
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", `Blendkit-Client ${path} returned no JSON.`);
147
+ }
148
+ }
149
+ /** Local-only health: neither endpoint subscribes this process or contacts the provider. */
150
+ async status(signal) {
151
+ const addons = (await this.request("/addons/list", undefined, signal));
152
+ const listed = (await this.request("/tools/list", undefined, signal));
153
+ const clientVersion = String(addons?.clientVersion ?? "");
154
+ if (!/^\d+\.\d+\.\d+$/u.test(clientVersion) || !Array.isArray(listed?.tools))
155
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Unexpected Blendkit-Client status shape.");
156
+ const tools = listed.tools
157
+ .map((tool) => tool?.id)
158
+ .filter((id) => typeof id === "string" && /^[a-z0-9_]{1,64}$/u.test(id));
159
+ return { clientVersion, tools };
160
+ }
161
+ /**
162
+ * A start request for work that writes files (download, recipe) can fail after the Client
163
+ * accepted it: the connection may drop or the answer may be malformed, and then there is no task
164
+ * id to cancel or watch. That is not proof that nothing runs, so it never counts as "not started".
165
+ */
166
+ startWriter(path, body, signal) {
167
+ return this.startTask(path, body, signal).catch((error) => {
168
+ throw new UnconfirmedStopError(error);
169
+ });
170
+ }
171
+ async startTask(path, body, signal) {
172
+ this.pendingStarts += 1;
173
+ try {
174
+ const started = (await this.request(path, body, signal));
175
+ const taskId = started?.task_id;
176
+ if (typeof taskId !== "string" || !/^[a-f0-9-]{36}$/u.test(taskId))
177
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Blendkit-Client returned no task id.");
178
+ this.active.add(taskId);
179
+ return taskId;
180
+ }
181
+ finally {
182
+ this.pendingStarts -= 1;
183
+ }
184
+ }
185
+ /**
186
+ * One /report request at a time, shared by every waiter, so it runs on its own deadline rather
187
+ * than one caller's signal. Terminal tasks are parked until their waiter takes them.
188
+ */
189
+ poll() {
190
+ this.polling ??= (async () => {
191
+ try {
192
+ const tasks = await this.request("/report", {
193
+ ...this.identity(),
194
+ api_key: "",
195
+ software: "ThreeNative Asset MCP",
196
+ software_version: this.addonVersion,
197
+ }, AbortSignal.timeout(this.requestTimeoutMs));
198
+ if (!Array.isArray(tasks))
199
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Blendkit-Client /report is not a list.");
200
+ for (const raw of tasks) {
201
+ // Only these fields are read: a task's `data` echoes its request, API key included.
202
+ const item = raw;
203
+ if (typeof item?.task_id !== "string" || typeof item.status !== "string")
204
+ continue;
205
+ const task = {
206
+ taskId: item.task_id,
207
+ taskType: safeTaskText(item.task_type, this.secrets).slice(0, 64),
208
+ status: item.status,
209
+ progress: Math.max(0, Math.min(100, Number(item.progress) || 0)),
210
+ message: safeTaskText(item.message, this.secrets),
211
+ result: item.result,
212
+ };
213
+ this.latest.set(task.taskId, { progress: task.progress, message: task.message });
214
+ if (TERMINAL.has(task.status))
215
+ this.done.set(task.taskId, task);
216
+ }
217
+ // ponytail: parked results of abandoned waiters are dropped oldest-first past 256.
218
+ for (const map of this.pendingStarts ? [] : [this.done, this.latest])
219
+ for (const id of map.keys()) {
220
+ if (map.size <= 256)
221
+ break;
222
+ if (!this.active.has(id))
223
+ map.delete(id);
224
+ }
225
+ }
226
+ finally {
227
+ this.polling = undefined;
228
+ }
229
+ })();
230
+ return this.polling;
231
+ }
232
+ async waitTask(taskId, signal, onProgress) {
233
+ try {
234
+ for (;;) {
235
+ // Before the parked result: a caller that has aborted never accepts a completion.
236
+ signal.throwIfAborted();
237
+ const finished = this.done.get(taskId);
238
+ if (finished) {
239
+ this.done.delete(taskId);
240
+ if (finished.status === "finished")
241
+ return finished;
242
+ throw new BlendkitError(finished.status === "cancelled" ? "BLENDKIT_CANCELLED" : "BLENDKIT_TASK_FAILED", `Blendkit-Client ${finished.taskType || "task"} ${finished.status}: ${finished.message || "no reason given"}`);
243
+ }
244
+ await this.poll();
245
+ const latest = this.latest.get(taskId);
246
+ if (latest && onProgress)
247
+ onProgress(latest);
248
+ // timers/promises rejects with a generic AbortError; surface the caller's own reason.
249
+ if (!this.done.has(taskId))
250
+ await delay(this.pollIntervalMs, undefined, { signal }).catch(() => signal.throwIfAborted());
251
+ }
252
+ }
253
+ finally {
254
+ // A parked completion stays (bounded by eviction): an aborted caller still needs to learn,
255
+ // through cancelDownload, whether the task really ended.
256
+ this.active.delete(taskId);
257
+ this.latest.delete(taskId);
258
+ }
259
+ }
260
+ /** Starts a provider search whose URL the caller built and validated; returns the raw result. */
261
+ async search(urlquery, pageSize, apiKey, signal) {
262
+ if (apiKey)
263
+ this.secrets.add(apiKey);
264
+ const taskId = await this.startTask("/assets/search", {
265
+ ...this.identity(),
266
+ api_key: apiKey,
267
+ PREFS: { api_key: apiKey },
268
+ urlquery,
269
+ page_size: pageSize,
270
+ asset_type: "",
271
+ tempdir: "",
272
+ get_next: false,
273
+ }, signal);
274
+ return (await this.waitTask(taskId, signal)).result;
275
+ }
276
+ /** Downloads one asset into downloadDir; a failure that is not an observed task end cancels the Client task. */
277
+ async download(assetData, downloadDir, resolution, apiKey, signal, onProgress) {
278
+ signal.throwIfAborted();
279
+ if (apiKey)
280
+ this.secrets.add(apiKey);
281
+ // The start request runs to completion so an abort always knows which task to cancel.
282
+ const taskId = await this.startWriter("/assets/download", {
283
+ ...this.identity(),
284
+ download_dirs: [downloadDir],
285
+ resolution,
286
+ asset_data: { ...assetData, available_resolutions: [] },
287
+ PREFS: {
288
+ api_key: apiKey,
289
+ scene_id: this.sceneId,
290
+ app_id: this.appId,
291
+ unpack_files: false,
292
+ create_asset_library: false,
293
+ resolution,
294
+ },
295
+ }, AbortSignal.timeout(this.requestTimeoutMs));
296
+ let task;
297
+ try {
298
+ task = await this.waitTask(taskId, signal, onProgress);
299
+ }
300
+ catch (error) {
301
+ if (taskEnded(error))
302
+ throw error;
303
+ // Anything else (abort, timeout, /report failing): ask the official Client to stop the
304
+ // download, then only trust that it did once /report says the task is over.
305
+ throw (await this.cancelDownload(taskId)) ? error : new UnconfirmedStopError(error);
306
+ }
307
+ const paths = task.result?.file_paths;
308
+ if (!Array.isArray(paths) || !paths.every((path) => typeof path === "string"))
309
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Download task returned no file paths.");
310
+ return paths;
311
+ }
312
+ /** True only when the cancelled task was observed in a terminal state within the deadline. */
313
+ async cancelDownload(taskId) {
314
+ try {
315
+ await this.request("/assets/cancel_download", { task_id: taskId, app_id: this.appId }, AbortSignal.timeout(this.requestTimeoutMs), false);
316
+ this.active.add(taskId);
317
+ await this.waitTask(taskId, AbortSignal.timeout(this.cancelConfirmMs));
318
+ return true;
319
+ }
320
+ catch (error) {
321
+ return taskEnded(error);
322
+ }
323
+ }
324
+ /** Runs one bundled recipe under the user's headless Blender. The Client cannot cancel a run. */
325
+ async runTool(scriptId, blendPath, outputPath, params, blenderExePath, signal) {
326
+ signal.throwIfAborted();
327
+ const taskId = await this.startWriter("/tools/run", {
328
+ ...this.identity(),
329
+ script_id: scriptId,
330
+ blender_exe_path: blenderExePath,
331
+ blend_path: blendPath,
332
+ output_path: outputPath,
333
+ params: { ...params, output_path: outputPath },
334
+ software: "ThreeNative Asset MCP",
335
+ }, signal);
336
+ // The Client cannot cancel a recipe: anything but an observed end leaves Blender possibly writing.
337
+ const task = await this.waitTask(taskId, signal).catch((error) => {
338
+ throw taskEnded(error) ? error : new UnconfirmedStopError(error);
339
+ });
340
+ const path = task.result?.file_path;
341
+ if (path !== outputPath)
342
+ throw new BlendkitError("BLENDKIT_INVALID_RESPONSE", "Tool run reported an unexpected output.");
343
+ return path;
344
+ }
345
+ }
346
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/blendkit/client.ts"],"names":[],"mappings":"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"}