threenative-asset-mcp 0.4.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 (150) hide show
  1. package/README.md +441 -0
  2. package/dist/ambientcg/client.d.ts +61 -0
  3. package/dist/ambientcg/client.d.ts.map +1 -0
  4. package/dist/ambientcg/client.js +234 -0
  5. package/dist/ambientcg/client.js.map +1 -0
  6. package/dist/audio/catalog.d.ts +36 -0
  7. package/dist/audio/catalog.d.ts.map +1 -0
  8. package/dist/audio/catalog.js +169 -0
  9. package/dist/audio/catalog.js.map +1 -0
  10. package/dist/audio/client.d.ts +46 -0
  11. package/dist/audio/client.d.ts.map +1 -0
  12. package/dist/audio/client.js +196 -0
  13. package/dist/audio/client.js.map +1 -0
  14. package/dist/bundle/client.d.ts +89 -0
  15. package/dist/bundle/client.d.ts.map +1 -0
  16. package/dist/bundle/client.js +324 -0
  17. package/dist/bundle/client.js.map +1 -0
  18. package/dist/config.d.ts +20 -0
  19. package/dist/config.d.ts.map +1 -0
  20. package/dist/config.js +130 -0
  21. package/dist/config.js.map +1 -0
  22. package/dist/download/direct-asset-downloader.d.ts +41 -0
  23. package/dist/download/direct-asset-downloader.d.ts.map +1 -0
  24. package/dist/download/direct-asset-downloader.js +232 -0
  25. package/dist/download/direct-asset-downloader.js.map +1 -0
  26. package/dist/fab/api-download.d.ts +30 -0
  27. package/dist/fab/api-download.d.ts.map +1 -0
  28. package/dist/fab/api-download.js +200 -0
  29. package/dist/fab/api-download.js.map +1 -0
  30. package/dist/fab/browser-transport.d.ts +79 -0
  31. package/dist/fab/browser-transport.d.ts.map +1 -0
  32. package/dist/fab/browser-transport.js +492 -0
  33. package/dist/fab/browser-transport.js.map +1 -0
  34. package/dist/fab/cache.d.ts +22 -0
  35. package/dist/fab/cache.d.ts.map +1 -0
  36. package/dist/fab/cache.js +55 -0
  37. package/dist/fab/cache.js.map +1 -0
  38. package/dist/fab/client.d.ts +61 -0
  39. package/dist/fab/client.d.ts.map +1 -0
  40. package/dist/fab/client.js +868 -0
  41. package/dist/fab/client.js.map +1 -0
  42. package/dist/fab/direct-transport.d.ts +68 -0
  43. package/dist/fab/direct-transport.d.ts.map +1 -0
  44. package/dist/fab/direct-transport.js +184 -0
  45. package/dist/fab/direct-transport.js.map +1 -0
  46. package/dist/fab/download-store.d.ts +21 -0
  47. package/dist/fab/download-store.d.ts.map +1 -0
  48. package/dist/fab/download-store.js +93 -0
  49. package/dist/fab/download-store.js.map +1 -0
  50. package/dist/fab/errors.d.ts +20 -0
  51. package/dist/fab/errors.d.ts.map +1 -0
  52. package/dist/fab/errors.js +65 -0
  53. package/dist/fab/errors.js.map +1 -0
  54. package/dist/fab/impersonate-fetch.d.ts +48 -0
  55. package/dist/fab/impersonate-fetch.d.ts.map +1 -0
  56. package/dist/fab/impersonate-fetch.js +228 -0
  57. package/dist/fab/impersonate-fetch.js.map +1 -0
  58. package/dist/fab/normalize.d.ts +3 -0
  59. package/dist/fab/normalize.d.ts.map +1 -0
  60. package/dist/fab/normalize.js +285 -0
  61. package/dist/fab/normalize.js.map +1 -0
  62. package/dist/fab/schemas.d.ts +10 -0
  63. package/dist/fab/schemas.d.ts.map +1 -0
  64. package/dist/fab/schemas.js +105 -0
  65. package/dist/fab/schemas.js.map +1 -0
  66. package/dist/index.d.ts +3 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +58 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/itch/catalog.d.ts +13 -0
  71. package/dist/itch/catalog.d.ts.map +1 -0
  72. package/dist/itch/catalog.js +50 -0
  73. package/dist/itch/catalog.js.map +1 -0
  74. package/dist/itch/client.d.ts +46 -0
  75. package/dist/itch/client.d.ts.map +1 -0
  76. package/dist/itch/client.js +175 -0
  77. package/dist/itch/client.js.map +1 -0
  78. package/dist/polyhaven/client.d.ts +55 -0
  79. package/dist/polyhaven/client.d.ts.map +1 -0
  80. package/dist/polyhaven/client.js +210 -0
  81. package/dist/polyhaven/client.js.map +1 -0
  82. package/dist/server.d.ts +25 -0
  83. package/dist/server.d.ts.map +1 -0
  84. package/dist/server.js +448 -0
  85. package/dist/server.js.map +1 -0
  86. package/dist/sketchfab/client.d.ts +70 -0
  87. package/dist/sketchfab/client.d.ts.map +1 -0
  88. package/dist/sketchfab/client.js +255 -0
  89. package/dist/sketchfab/client.js.map +1 -0
  90. package/dist/smithsonian/client.d.ts +32 -0
  91. package/dist/smithsonian/client.d.ts.map +1 -0
  92. package/dist/smithsonian/client.js +142 -0
  93. package/dist/smithsonian/client.js.map +1 -0
  94. package/dist/tools/ambientcg.d.ts +296 -0
  95. package/dist/tools/ambientcg.d.ts.map +1 -0
  96. package/dist/tools/ambientcg.js +183 -0
  97. package/dist/tools/ambientcg.js.map +1 -0
  98. package/dist/tools/audio.d.ts +211 -0
  99. package/dist/tools/audio.d.ts.map +1 -0
  100. package/dist/tools/audio.js +156 -0
  101. package/dist/tools/audio.js.map +1 -0
  102. package/dist/tools/bundle.d.ts +237 -0
  103. package/dist/tools/bundle.d.ts.map +1 -0
  104. package/dist/tools/bundle.js +206 -0
  105. package/dist/tools/bundle.js.map +1 -0
  106. package/dist/tools/direct-download.d.ts +53 -0
  107. package/dist/tools/direct-download.d.ts.map +1 -0
  108. package/dist/tools/direct-download.js +68 -0
  109. package/dist/tools/direct-download.js.map +1 -0
  110. package/dist/tools/download-free-asset.d.ts +66 -0
  111. package/dist/tools/download-free-asset.d.ts.map +1 -0
  112. package/dist/tools/download-free-asset.js +60 -0
  113. package/dist/tools/download-free-asset.js.map +1 -0
  114. package/dist/tools/get-asset.d.ts +161 -0
  115. package/dist/tools/get-asset.d.ts.map +1 -0
  116. package/dist/tools/get-asset.js +131 -0
  117. package/dist/tools/get-asset.js.map +1 -0
  118. package/dist/tools/itch.d.ts +120 -0
  119. package/dist/tools/itch.d.ts.map +1 -0
  120. package/dist/tools/itch.js +120 -0
  121. package/dist/tools/itch.js.map +1 -0
  122. package/dist/tools/list-filters.d.ts +127 -0
  123. package/dist/tools/list-filters.d.ts.map +1 -0
  124. package/dist/tools/list-filters.js +68 -0
  125. package/dist/tools/list-filters.js.map +1 -0
  126. package/dist/tools/list-limited-time-free.d.ts +57 -0
  127. package/dist/tools/list-limited-time-free.d.ts.map +1 -0
  128. package/dist/tools/list-limited-time-free.js +47 -0
  129. package/dist/tools/list-limited-time-free.js.map +1 -0
  130. package/dist/tools/polyhaven.d.ts +266 -0
  131. package/dist/tools/polyhaven.d.ts.map +1 -0
  132. package/dist/tools/polyhaven.js +233 -0
  133. package/dist/tools/polyhaven.js.map +1 -0
  134. package/dist/tools/search-assets.d.ts +176 -0
  135. package/dist/tools/search-assets.d.ts.map +1 -0
  136. package/dist/tools/search-assets.js +172 -0
  137. package/dist/tools/search-assets.js.map +1 -0
  138. package/dist/tools/sketchfab.d.ts +325 -0
  139. package/dist/tools/sketchfab.d.ts.map +1 -0
  140. package/dist/tools/sketchfab.js +203 -0
  141. package/dist/tools/sketchfab.js.map +1 -0
  142. package/dist/tools/smithsonian.d.ts +189 -0
  143. package/dist/tools/smithsonian.d.ts.map +1 -0
  144. package/dist/tools/smithsonian.js +189 -0
  145. package/dist/tools/smithsonian.js.map +1 -0
  146. package/dist/tools/source-directory.d.ts +226 -0
  147. package/dist/tools/source-directory.d.ts.map +1 -0
  148. package/dist/tools/source-directory.js +583 -0
  149. package/dist/tools/source-directory.js.map +1 -0
  150. package/package.json +69 -0
@@ -0,0 +1,492 @@
1
+ import { join, resolve } from "node:path";
2
+ import { chromium } from "playwright";
3
+ import { assertAllowedFabApiUrl, FabClientError, } from "./direct-transport.js";
4
+ import { storeDownload } from "./download-store.js";
5
+ const FAB_ORIGIN = "https://www.fab.com";
6
+ function playwrightContext(config) {
7
+ return async () => (await chromium.launchPersistentContext(config.browserProfileDir, {
8
+ headless: config.browserHeadless,
9
+ acceptDownloads: true,
10
+ serviceWorkers: "block",
11
+ // Keep MCP calls within common client deadlines even when a headed
12
+ // browser cannot start in the host environment.
13
+ timeout: Math.min(config.browserTimeoutMs, 10_000),
14
+ viewport: { width: 1280, height: 900 },
15
+ }));
16
+ }
17
+ export class BrowserFabTransport {
18
+ name = "browser";
19
+ timeoutMs;
20
+ manualChallengeTimeoutMs;
21
+ headless;
22
+ downloadDir;
23
+ maxDownloadBytes;
24
+ sleep;
25
+ launchContext;
26
+ contextPromise;
27
+ queue = Promise.resolve();
28
+ closed = false;
29
+ constructor(options) {
30
+ this.timeoutMs = options.timeoutMs;
31
+ this.manualChallengeTimeoutMs =
32
+ options.manualChallengeTimeoutMs ?? 10_000;
33
+ this.headless = options.headless;
34
+ this.downloadDir = resolve(options.downloadDir ?? join(options.profileDir, "downloads"));
35
+ this.maxDownloadBytes = options.maxDownloadBytes ?? 2_147_483_648;
36
+ this.sleep =
37
+ options.sleep ??
38
+ ((milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds)));
39
+ this.launchContext =
40
+ options.launchContext ??
41
+ playwrightContext({
42
+ browserTimeoutMs: options.timeoutMs,
43
+ browserHeadless: options.headless,
44
+ browserProfileDir: options.profileDir,
45
+ });
46
+ }
47
+ static fromConfig(config) {
48
+ return new BrowserFabTransport({
49
+ timeoutMs: config.browserTimeoutMs,
50
+ manualChallengeTimeoutMs: config.browserManualTimeoutMs,
51
+ headless: config.browserHeadless,
52
+ profileDir: config.browserProfileDir,
53
+ downloadDir: config.downloadDir,
54
+ maxDownloadBytes: config.maxDownloadBytes,
55
+ });
56
+ }
57
+ async search(url) {
58
+ return this.request(url);
59
+ }
60
+ async getListing(id, currency) {
61
+ const url = new URL(`/i/listings/${encodeURIComponent(id)}`, FAB_ORIGIN);
62
+ url.searchParams.set("currency", currency);
63
+ return this.request(url);
64
+ }
65
+ async prepare() {
66
+ if (this.headless)
67
+ return;
68
+ await this.serialized(async () => {
69
+ await this.page(false);
70
+ });
71
+ }
72
+ async downloadFreeAsset(request) {
73
+ return this.serialized(async () => {
74
+ const page = await this.page(false);
75
+ const listingUrl = `${FAB_ORIGIN}/listings/${request.listingId}`;
76
+ try {
77
+ await page.goto(listingUrl, {
78
+ waitUntil: "domcontentloaded",
79
+ timeout: this.timeoutMs,
80
+ });
81
+ }
82
+ catch {
83
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not load the listing download page.", true);
84
+ }
85
+ this.assertListingPage(page, request.listingId);
86
+ await this.ensureListingIsUsable(page);
87
+ if (!page.getByRole || !page.waitForEvent) {
88
+ throw new FabClientError("FAB_INTERNAL", "The configured Fab browser cannot perform file downloads.");
89
+ }
90
+ const openDownload = page.getByRole("button", {
91
+ name: "Download",
92
+ exact: true,
93
+ });
94
+ if ((await openDownload.count()) !== 1) {
95
+ const buyNow = page.getByRole("button", {
96
+ name: "Buy now",
97
+ exact: true,
98
+ });
99
+ if ((await buyNow.count()) > 0) {
100
+ throw new FabClientError("FAB_ACQUISITION_REQUIRED", "This listing requires an acquisition or checkout flow before downloading. The MCP did not start it.");
101
+ }
102
+ const addToLibrary = page.getByRole("button", {
103
+ name: "Add to My Library",
104
+ exact: true,
105
+ });
106
+ if ((await addToLibrary.count()) > 0) {
107
+ throw new FabClientError("FAB_LIBRARY_REQUIRED", "This format must be added to an authenticated Fab library and may require Epic Games Launcher or an editor integration.");
108
+ }
109
+ throw new FabClientError("FAB_FORMAT_UNAVAILABLE", "Fab does not expose a direct public download for this listing.");
110
+ }
111
+ await openDownload.click({ timeout: this.timeoutMs });
112
+ const formatButton = page.getByRole("button", {
113
+ name: `Download ${downloadFormatLabel(request.format)} asset`,
114
+ exact: true,
115
+ });
116
+ try {
117
+ await formatButton.waitFor({
118
+ state: "visible",
119
+ timeout: this.timeoutMs,
120
+ });
121
+ }
122
+ catch {
123
+ const dialogState = await this.downloadDialogState(page);
124
+ if (dialogState.eulaVisible) {
125
+ throw new FabClientError("FAB_EULA_REQUIRED", "Fab requires visible EULA acknowledgement in the dedicated browser before this file can be downloaded.");
126
+ }
127
+ throw new FabClientError("FAB_FORMAT_UNAVAILABLE", `Fab does not expose the requested ${request.format.toUpperCase()} file for this listing.`);
128
+ }
129
+ if ((await formatButton.count()) !== 1) {
130
+ throw new FabClientError("FAB_UPSTREAM_CHANGED", "Fab exposed an ambiguous download control.");
131
+ }
132
+ let download;
133
+ try {
134
+ const pending = page.waitForEvent("download", {
135
+ timeout: this.timeoutMs,
136
+ });
137
+ await formatButton.click({ timeout: this.timeoutMs });
138
+ download = await pending;
139
+ }
140
+ catch {
141
+ throw new FabClientError("FAB_DOWNLOAD_FAILED", "Fab did not start the requested file download.", true);
142
+ }
143
+ const failure = await download.failure().catch(() => null);
144
+ if (failure) {
145
+ throw new FabClientError("FAB_DOWNLOAD_FAILED", "Fab could not complete the requested file download.", true);
146
+ }
147
+ return this.persistDownload(download, request);
148
+ });
149
+ }
150
+ async getLimitedTimeFreeIds(limit) {
151
+ return this.serialized(async () => {
152
+ const page = await this.context().then((context) => context.pages()[0] ?? context.newPage());
153
+ try {
154
+ await page.goto(`${FAB_ORIGIN}/limited-time-free`, {
155
+ waitUntil: "domcontentloaded",
156
+ timeout: this.timeoutMs,
157
+ });
158
+ }
159
+ catch {
160
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not load limited-time-free promotions.", true);
161
+ }
162
+ try {
163
+ const finalUrl = new URL(page.url());
164
+ if (finalUrl.origin !== FAB_ORIGIN ||
165
+ finalUrl.pathname !== "/limited-time-free") {
166
+ throw new Error("unexpected promotion origin");
167
+ }
168
+ }
169
+ catch {
170
+ throw new FabClientError("FAB_ACCESS_DENIED", "Fab redirected the promotions page outside the approved public route.");
171
+ }
172
+ let ids;
173
+ try {
174
+ ids = await page.evaluate(({ expectedOrigin, maximum }) => {
175
+ const pattern = /^\/listings\/([0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12})(?:\/)?$/i;
176
+ const values = [];
177
+ for (const anchor of Array.from(document.querySelectorAll('a[href*="/listings/"]'))) {
178
+ let url;
179
+ try {
180
+ url = new URL(anchor.href, expectedOrigin);
181
+ }
182
+ catch {
183
+ continue;
184
+ }
185
+ if (url.origin !== expectedOrigin)
186
+ continue;
187
+ const match = pattern.exec(url.pathname);
188
+ if (!match?.[1] || values.includes(match[1].toLowerCase())) {
189
+ continue;
190
+ }
191
+ values.push(match[1].toLowerCase());
192
+ if (values.length >= maximum)
193
+ break;
194
+ }
195
+ return values;
196
+ }, { expectedOrigin: FAB_ORIGIN, maximum: limit });
197
+ }
198
+ catch {
199
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not read curated promotion IDs.", true);
200
+ }
201
+ if (ids.length === 0) {
202
+ throw new FabClientError("FAB_BROWSER_ATTENTION_REQUIRED", "Fab did not expose curated promotion IDs in the dedicated browser. Start the MCP once with FAB_BROWSER_HEADLESS=0 to check for manual verification.");
203
+ }
204
+ return ids;
205
+ });
206
+ }
207
+ request(url) {
208
+ assertAllowedFabApiUrl(url);
209
+ return this.serialized(() => this.requestInBrowser(url));
210
+ }
211
+ serialized(operation) {
212
+ const result = this.queue.then(operation, operation);
213
+ this.queue = result.then(() => undefined, () => undefined);
214
+ return result;
215
+ }
216
+ async context() {
217
+ if (this.closed) {
218
+ throw new FabClientError("FAB_INTERNAL", "The Fab browser transport is closed.");
219
+ }
220
+ this.contextPromise ??= this.launchContext().catch(() => {
221
+ this.contextPromise = undefined;
222
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not be started.", true);
223
+ });
224
+ return this.contextPromise;
225
+ }
226
+ async page(waitForVerification = true) {
227
+ const context = await this.context();
228
+ const page = context.pages()[0] ?? (await context.newPage());
229
+ let atFabOrigin = false;
230
+ try {
231
+ atFabOrigin = new URL(page.url()).origin === FAB_ORIGIN;
232
+ }
233
+ catch {
234
+ // about:blank and malformed page URLs are navigated to Fab below.
235
+ }
236
+ if (!atFabOrigin) {
237
+ try {
238
+ await page.goto(`${FAB_ORIGIN}/`, {
239
+ waitUntil: "domcontentloaded",
240
+ timeout: this.timeoutMs,
241
+ });
242
+ }
243
+ catch {
244
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not load Fab.", true);
245
+ }
246
+ }
247
+ try {
248
+ if (new URL(page.url()).origin !== FAB_ORIGIN) {
249
+ throw new Error("unexpected browser origin");
250
+ }
251
+ }
252
+ catch {
253
+ throw new FabClientError("FAB_ACCESS_DENIED", "The dedicated browser did not remain on Fab.");
254
+ }
255
+ if (!this.headless && waitForVerification) {
256
+ await this.waitForManualVerification(page);
257
+ }
258
+ return page;
259
+ }
260
+ async waitForManualVerification(page) {
261
+ const deadline = Date.now() + this.manualChallengeTimeoutMs;
262
+ while (true) {
263
+ let state;
264
+ try {
265
+ state = await page.evaluate(({ expectedOrigin }) => ({
266
+ origin: globalThis.location.origin,
267
+ challengeVisible: globalThis.location.origin === expectedOrigin &&
268
+ (document.title.toLowerCase().includes("just a moment") ||
269
+ document.querySelector("#challenge-running, #challenge-stage, .cf-challenge") !== null),
270
+ }), { expectedOrigin: FAB_ORIGIN });
271
+ }
272
+ catch {
273
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not inspect the verification page.", true);
274
+ }
275
+ if (state.origin !== FAB_ORIGIN) {
276
+ throw new FabClientError("FAB_ACCESS_DENIED", "The dedicated browser left Fab during manual verification.");
277
+ }
278
+ if (!state.challengeVisible)
279
+ return;
280
+ if (Date.now() >= deadline) {
281
+ throw new FabClientError("FAB_BROWSER_ATTENTION_REQUIRED", "Fab still requires manual verification in the dedicated MCP browser profile.");
282
+ }
283
+ await this.sleep(1_000);
284
+ }
285
+ }
286
+ assertListingPage(page, listingId) {
287
+ try {
288
+ const finalUrl = new URL(page.url());
289
+ if (finalUrl.origin !== FAB_ORIGIN ||
290
+ finalUrl.pathname !== `/listings/${listingId}`) {
291
+ throw new Error("unexpected listing route");
292
+ }
293
+ }
294
+ catch {
295
+ throw new FabClientError("FAB_ACCESS_DENIED", "Fab redirected the dedicated browser outside the requested listing.");
296
+ }
297
+ }
298
+ async ensureListingIsUsable(page) {
299
+ let state;
300
+ try {
301
+ state = await page.evaluate(({ expectedOrigin }) => ({
302
+ origin: globalThis.location.origin,
303
+ challengeVisible: globalThis.location.origin === expectedOrigin &&
304
+ (document.title.toLowerCase().includes("just a moment") ||
305
+ document.querySelector("#challenge-running, #challenge-stage, .cf-challenge") !== null),
306
+ }), { expectedOrigin: FAB_ORIGIN });
307
+ }
308
+ catch {
309
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated browser could not inspect the Fab listing.", true);
310
+ }
311
+ if (state.origin !== FAB_ORIGIN) {
312
+ throw new FabClientError("FAB_ACCESS_DENIED", "The dedicated browser left Fab while opening the listing.");
313
+ }
314
+ if (state.challengeVisible) {
315
+ if (!this.headless)
316
+ await this.waitForManualVerification(page);
317
+ else {
318
+ throw new FabClientError("FAB_BROWSER_ATTENTION_REQUIRED", "Fab requires manual verification in the dedicated MCP browser profile. Start the MCP once with FAB_BROWSER_HEADLESS=0 to complete it.");
319
+ }
320
+ }
321
+ }
322
+ async downloadDialogState(page) {
323
+ try {
324
+ return await page.evaluate(() => {
325
+ const dialog = document.querySelector('[role="dialog"]');
326
+ const text = dialog?.textContent?.toLowerCase().slice(0, 4_000) ?? "";
327
+ return {
328
+ eulaVisible: text.includes("eula") ||
329
+ text.includes("end user license agreement") ||
330
+ text.includes("read and agree"),
331
+ };
332
+ }, undefined);
333
+ }
334
+ catch {
335
+ return { eulaVisible: false };
336
+ }
337
+ }
338
+ async persistDownload(download, request) {
339
+ return storeDownload({
340
+ downloadDir: this.downloadDir,
341
+ listingId: request.listingId,
342
+ format: request.format,
343
+ fileName: download.suggestedFilename(),
344
+ maxBytes: this.maxDownloadBytes,
345
+ materialize: (temporaryPath) => download.saveAs(temporaryPath),
346
+ });
347
+ }
348
+ async requestInBrowser(url) {
349
+ const page = await this.page();
350
+ let result;
351
+ try {
352
+ result = await page.evaluate(async ({ requestUrl, expectedOrigin, timeoutMs }) => {
353
+ if (globalThis.location.origin !== expectedOrigin) {
354
+ return {
355
+ status: 0,
356
+ ok: false,
357
+ contentType: "",
358
+ cfMitigated: null,
359
+ responseOrigin: globalThis.location.origin,
360
+ };
361
+ }
362
+ const controller = new AbortController();
363
+ const timeout = globalThis.setTimeout(() => controller.abort(), timeoutMs);
364
+ try {
365
+ let response;
366
+ try {
367
+ response = await fetch(requestUrl, {
368
+ headers: { accept: "application/json" },
369
+ credentials: "same-origin",
370
+ redirect: "error",
371
+ signal: controller.signal,
372
+ });
373
+ }
374
+ catch (error) {
375
+ if (error instanceof DOMException && error.name === "AbortError") {
376
+ return {
377
+ status: 0,
378
+ ok: false,
379
+ contentType: "",
380
+ cfMitigated: null,
381
+ responseOrigin: null,
382
+ timedOut: true,
383
+ };
384
+ }
385
+ throw error;
386
+ }
387
+ const contentType = response.headers.get("content-type") ?? "";
388
+ const cfMitigated = response.headers.get("cf-mitigated");
389
+ let responseOrigin = null;
390
+ try {
391
+ responseOrigin = new URL(response.url).origin;
392
+ }
393
+ catch {
394
+ // The caller classifies a missing response origin safely.
395
+ }
396
+ if (!contentType.toLowerCase().includes("application/json")) {
397
+ return {
398
+ status: response.status,
399
+ ok: response.ok,
400
+ contentType,
401
+ cfMitigated,
402
+ responseOrigin,
403
+ };
404
+ }
405
+ try {
406
+ return {
407
+ status: response.status,
408
+ ok: response.ok,
409
+ contentType,
410
+ cfMitigated,
411
+ responseOrigin,
412
+ payload: await response.json(),
413
+ };
414
+ }
415
+ catch {
416
+ return {
417
+ status: response.status,
418
+ ok: response.ok,
419
+ contentType,
420
+ cfMitigated,
421
+ responseOrigin,
422
+ invalidJson: true,
423
+ };
424
+ }
425
+ }
426
+ finally {
427
+ globalThis.clearTimeout(timeout);
428
+ }
429
+ }, {
430
+ requestUrl: url.toString(),
431
+ expectedOrigin: FAB_ORIGIN,
432
+ timeoutMs: this.timeoutMs,
433
+ });
434
+ }
435
+ catch {
436
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "The dedicated Fab browser could not complete the request.", true);
437
+ }
438
+ if (result.timedOut) {
439
+ throw new FabClientError("FAB_TIMEOUT", "Fab did not respond before the browser request timeout.", true);
440
+ }
441
+ const isHtml = result.contentType.toLowerCase().includes("text/html");
442
+ if (result.cfMitigated?.toLowerCase() === "challenge" ||
443
+ isHtml ||
444
+ (result.status === 403 && !result.payload)) {
445
+ throw new FabClientError("FAB_BROWSER_ATTENTION_REQUIRED", "Fab requires manual verification in the dedicated MCP browser profile. Start the MCP once with FAB_BROWSER_HEADLESS=0 to complete it.");
446
+ }
447
+ if (result.responseOrigin !== FAB_ORIGIN) {
448
+ throw new FabClientError("FAB_ACCESS_DENIED", "Fab redirected the anonymous browser request outside Fab.");
449
+ }
450
+ if (result.status === 404) {
451
+ throw new FabClientError("FAB_NOT_FOUND", "The Fab resource was not found.");
452
+ }
453
+ if (result.status === 429) {
454
+ throw new FabClientError("FAB_RATE_LIMITED", "Fab rate-limited the request.", true);
455
+ }
456
+ if (result.status === 401 || result.status === 403) {
457
+ throw new FabClientError("FAB_ACCESS_DENIED", "Fab denied this anonymous public request.");
458
+ }
459
+ if (!result.ok) {
460
+ throw new FabClientError("FAB_UPSTREAM_UNAVAILABLE", "Fab returned an unavailable response.", result.status >= 500);
461
+ }
462
+ if (!result.contentType.toLowerCase().includes("application/json")) {
463
+ throw new FabClientError("FAB_UPSTREAM_CHANGED", "Fab returned an unexpected response format.");
464
+ }
465
+ if (result.invalidJson || result.payload === undefined) {
466
+ throw new FabClientError("FAB_UPSTREAM_CHANGED", "Fab returned invalid JSON.");
467
+ }
468
+ return result.payload;
469
+ }
470
+ async close() {
471
+ if (this.closed)
472
+ return;
473
+ this.closed = true;
474
+ await this.queue;
475
+ const context = await this.contextPromise?.catch(() => undefined);
476
+ this.contextPromise = undefined;
477
+ await context?.close().catch(() => undefined);
478
+ }
479
+ }
480
+ const DOWNLOAD_FORMAT_LABELS = {
481
+ blender: "Blender",
482
+ fbx: "FBX",
483
+ glb: "GLB",
484
+ gltf: "GLTF",
485
+ maya: "Maya",
486
+ obj: "OBJ",
487
+ unity: "Unity",
488
+ };
489
+ function downloadFormatLabel(format) {
490
+ return DOWNLOAD_FORMAT_LABELS[format];
491
+ }
492
+ //# sourceMappingURL=browser-transport.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser-transport.js","sourceRoot":"","sources":["../../src/fab/browser-transport.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ export interface TtlLruCacheOptions {
2
+ maxEntries?: number;
3
+ now?: () => number;
4
+ }
5
+ /**
6
+ * Process-local TTL/LRU cache. Map insertion order is used as the LRU list,
7
+ * so reads move an entry to the newest position and eviction remains O(1).
8
+ */
9
+ export declare class TtlLruCache<Value> {
10
+ private readonly entries;
11
+ private readonly maxEntries;
12
+ private readonly now;
13
+ constructor(options?: TtlLruCacheOptions);
14
+ get size(): number;
15
+ /** Returns an entry even after TTL expiry, without changing LRU order. */
16
+ peek(key: string): Value | undefined;
17
+ get(key: string): Value | undefined;
18
+ set(key: string, value: Value, ttlMs: number): void;
19
+ delete(key: string): boolean;
20
+ clear(): void;
21
+ }
22
+ //# sourceMappingURL=cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/fab/cache.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,qBAAa,WAAW,CAAC,KAAK;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwC;IAChE,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IAEnC,YAAY,OAAO,GAAE,kBAAuB,EAM3C;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAEnC;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,GAAG,SAAS,CAUlC;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAYlD;IAED,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE3B;IAED,KAAK,IAAI,IAAI,CAEZ;CACF"}
@@ -0,0 +1,55 @@
1
+ const MAX_CACHE_ENTRIES = 500;
2
+ /**
3
+ * Process-local TTL/LRU cache. Map insertion order is used as the LRU list,
4
+ * so reads move an entry to the newest position and eviction remains O(1).
5
+ */
6
+ export class TtlLruCache {
7
+ entries = new Map();
8
+ maxEntries;
9
+ now;
10
+ constructor(options = {}) {
11
+ this.maxEntries = Math.min(MAX_CACHE_ENTRIES, Math.max(1, Math.trunc(options.maxEntries ?? MAX_CACHE_ENTRIES)));
12
+ this.now = options.now ?? Date.now;
13
+ }
14
+ get size() {
15
+ return this.entries.size;
16
+ }
17
+ /** Returns an entry even after TTL expiry, without changing LRU order. */
18
+ peek(key) {
19
+ return this.entries.get(key)?.value;
20
+ }
21
+ get(key) {
22
+ const entry = this.entries.get(key);
23
+ if (!entry)
24
+ return undefined;
25
+ if (entry.expiresAt <= this.now()) {
26
+ this.entries.delete(key);
27
+ return undefined;
28
+ }
29
+ this.entries.delete(key);
30
+ this.entries.set(key, entry);
31
+ return entry.value;
32
+ }
33
+ set(key, value, ttlMs) {
34
+ if (!Number.isFinite(ttlMs) || ttlMs <= 0)
35
+ return;
36
+ this.entries.delete(key);
37
+ this.entries.set(key, {
38
+ value,
39
+ expiresAt: this.now() + ttlMs,
40
+ });
41
+ while (this.entries.size > this.maxEntries) {
42
+ const oldest = this.entries.keys().next().value;
43
+ if (oldest === undefined)
44
+ break;
45
+ this.entries.delete(oldest);
46
+ }
47
+ }
48
+ delete(key) {
49
+ return this.entries.delete(key);
50
+ }
51
+ clear() {
52
+ this.entries.clear();
53
+ }
54
+ }
55
+ //# sourceMappingURL=cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/fab/cache.ts"],"names":[],"mappings":"AAAA,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAY9B;;;GAGG;AACH,MAAM,OAAO,WAAW;IACL,OAAO,GAAG,IAAI,GAAG,EAA6B,CAAC;IAC/C,UAAU,CAAS;IACnB,GAAG,CAAe;IAEnC,YAAY,OAAO,GAAuB,EAAE;QAC1C,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,CACxB,iBAAiB,EACjB,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,iBAAiB,CAAC,CAAC,CACjE,CAAC;QACF,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;IACrC,CAAC;IAED,IAAI,IAAI;QACN,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED,0EAA0E;IAC1E,IAAI,CAAC,GAAW;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC;IACtC,CAAC;IAED,GAAG,CAAC,GAAW;QACb,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,CAAC,KAAK;YAAE,OAAO,SAAS,CAAC;QAC7B,IAAI,KAAK,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;YAClC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7B,OAAO,KAAK,CAAC,KAAK,CAAC;IACrB,CAAC;IAED,GAAG,CAAC,GAAW,EAAE,KAAY,EAAE,KAAa;QAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC;YAAE,OAAO;QAClD,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;YACpB,KAAK;YACL,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;SAC9B,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC;YAC3C,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAA2B,CAAC;YACtE,IAAI,MAAM,KAAK,SAAS;gBAAE,MAAM;YAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAClC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;CACF"}