@thenavidm/midjourney-mcp-cli 1.0.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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +677 -0
  3. package/SKILL.md +184 -0
  4. package/dist/api/client.d.ts +72 -0
  5. package/dist/api/client.js +278 -0
  6. package/dist/api/client.js.map +1 -0
  7. package/dist/api/download.d.ts +41 -0
  8. package/dist/api/download.js +108 -0
  9. package/dist/api/download.js.map +1 -0
  10. package/dist/api/errors.d.ts +75 -0
  11. package/dist/api/errors.js +166 -0
  12. package/dist/api/errors.js.map +1 -0
  13. package/dist/api/jobs.d.ts +140 -0
  14. package/dist/api/jobs.js +296 -0
  15. package/dist/api/jobs.js.map +1 -0
  16. package/dist/api/moodboards.d.ts +88 -0
  17. package/dist/api/moodboards.js +189 -0
  18. package/dist/api/moodboards.js.map +1 -0
  19. package/dist/capture.d.ts +27 -0
  20. package/dist/capture.js +162 -0
  21. package/dist/capture.js.map +1 -0
  22. package/dist/cli.d.ts +92 -0
  23. package/dist/cli.js +633 -0
  24. package/dist/cli.js.map +1 -0
  25. package/dist/config.d.ts +37 -0
  26. package/dist/config.js +90 -0
  27. package/dist/config.js.map +1 -0
  28. package/dist/content/prompt.d.ts +69 -0
  29. package/dist/content/prompt.js +173 -0
  30. package/dist/content/prompt.js.map +1 -0
  31. package/dist/doctor.d.ts +19 -0
  32. package/dist/doctor.js +161 -0
  33. package/dist/doctor.js.map +1 -0
  34. package/dist/format/jobs.d.ts +71 -0
  35. package/dist/format/jobs.js +211 -0
  36. package/dist/format/jobs.js.map +1 -0
  37. package/dist/index.d.ts +13 -0
  38. package/dist/index.js +161 -0
  39. package/dist/index.js.map +1 -0
  40. package/dist/safety.d.ts +52 -0
  41. package/dist/safety.js +100 -0
  42. package/dist/safety.js.map +1 -0
  43. package/dist/server.d.ts +10 -0
  44. package/dist/server.js +57 -0
  45. package/dist/server.js.map +1 -0
  46. package/dist/tools/create.d.ts +96 -0
  47. package/dist/tools/create.js +375 -0
  48. package/dist/tools/create.js.map +1 -0
  49. package/dist/tools/download.d.ts +17 -0
  50. package/dist/tools/download.js +47 -0
  51. package/dist/tools/download.js.map +1 -0
  52. package/dist/tools/explore.d.ts +8 -0
  53. package/dist/tools/explore.js +57 -0
  54. package/dist/tools/explore.js.map +1 -0
  55. package/dist/tools/index.d.ts +3 -0
  56. package/dist/tools/index.js +16 -0
  57. package/dist/tools/index.js.map +1 -0
  58. package/dist/tools/jobs.d.ts +18 -0
  59. package/dist/tools/jobs.js +92 -0
  60. package/dist/tools/jobs.js.map +1 -0
  61. package/dist/tools/kit.d.ts +84 -0
  62. package/dist/tools/kit.js +104 -0
  63. package/dist/tools/kit.js.map +1 -0
  64. package/dist/tools/library.d.ts +22 -0
  65. package/dist/tools/library.js +185 -0
  66. package/dist/tools/library.js.map +1 -0
  67. package/dist/tools/profile.d.ts +2 -0
  68. package/dist/tools/profile.js +89 -0
  69. package/dist/tools/profile.js.map +1 -0
  70. package/dist/transport/cdp.d.ts +217 -0
  71. package/dist/transport/cdp.js +607 -0
  72. package/dist/transport/cdp.js.map +1 -0
  73. package/dist/transport/http.d.ts +18 -0
  74. package/dist/transport/http.js +48 -0
  75. package/dist/transport/http.js.map +1 -0
  76. package/package.json +72 -0
@@ -0,0 +1,607 @@
1
+ /**
2
+ * Chrome DevTools Protocol transport.
3
+ *
4
+ * This is the whole reason the server works, so it is worth saying plainly why
5
+ * it exists rather than a normal HTTP client.
6
+ *
7
+ * Midjourney publishes no API. The endpoints under `/api/` are the ones its own
8
+ * web app calls, and they sit behind a Cloudflare interstitial that answers a
9
+ * plain client with a 403 challenge page rather than JSON. The challenge is not
10
+ * defeated by a header: the `cf_clearance` cookie is bound to the IP, the
11
+ * User-Agent and the TLS fingerprint together, so a cookie lifted out of a
12
+ * browser and replayed from Node is a different client and gets stopped.
13
+ *
14
+ * Rather than impersonate a browser, we drive one. Requests are issued by
15
+ * `fetch()` running inside a real midjourney.com page in a real Chrome that is
16
+ * really logged in. Same origin, same cookies, same fingerprint, same IP,
17
+ * credentials attached by the browser itself. There is nothing to spoof
18
+ * because nothing is being faked, and the session stays valid for as long as
19
+ * the user stays logged in.
20
+ *
21
+ * Chrome 136 stopped honouring --remote-debugging-port on the default profile,
22
+ * so attaching to whatever Chrome the user already has open is not reliable.
23
+ * Instead we own a profile: a dedicated user-data-dir under ~/.midjourney-mcp
24
+ * that the user logs into once. That also keeps this well away from their real
25
+ * browsing session, which is the right default for something holding a login.
26
+ */
27
+ import { spawn } from "node:child_process";
28
+ import { existsSync } from "node:fs";
29
+ import { mkdir } from "node:fs/promises";
30
+ import { homedir, platform } from "node:os";
31
+ import { join } from "node:path";
32
+ import { BrowserError } from "../api/errors.js";
33
+ const CHROME_PATHS = {
34
+ darwin: [
35
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
36
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
37
+ "/Applications/Google Chrome Canary.app/Contents/MacOS/Google Chrome Canary",
38
+ ],
39
+ linux: [
40
+ "/usr/bin/google-chrome",
41
+ "/usr/bin/google-chrome-stable",
42
+ "/usr/bin/chromium",
43
+ "/usr/bin/chromium-browser",
44
+ ],
45
+ win32: [
46
+ "C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe",
47
+ "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe",
48
+ ],
49
+ };
50
+ export function findChrome(explicit) {
51
+ if (explicit) {
52
+ if (!existsSync(explicit)) {
53
+ throw new BrowserError(`MIDJOURNEY_CHROME_PATH points at ${explicit}, which does not exist.`);
54
+ }
55
+ return explicit;
56
+ }
57
+ for (const candidate of CHROME_PATHS[platform()] ?? []) {
58
+ if (existsSync(candidate))
59
+ return candidate;
60
+ }
61
+ throw new BrowserError("No Chrome or Chromium found. Install Google Chrome, or set MIDJOURNEY_CHROME_PATH to the binary.");
62
+ }
63
+ export function defaultProfileDir() {
64
+ return join(homedir(), ".midjourney-mcp", "chrome-profile");
65
+ }
66
+ /**
67
+ * A single WebSocket to one CDP target, multiplexing commands by id.
68
+ *
69
+ * One socket per command would be simpler and is what a lot of CDP glue does,
70
+ * but it costs a connection handshake on every API call and loses the events
71
+ * we need for navigation. Node 22 ships a global WebSocket, so this needs no
72
+ * dependency at all.
73
+ */
74
+ export class CdpSession {
75
+ socket;
76
+ nextId = 1;
77
+ pending = new Map();
78
+ listeners = new Map();
79
+ url;
80
+ timeoutMs;
81
+ closed = false;
82
+ constructor(webSocketDebuggerUrl, timeoutMs) {
83
+ this.url = webSocketDebuggerUrl;
84
+ this.timeoutMs = timeoutMs;
85
+ }
86
+ async connect() {
87
+ if (this.socket && this.socket.readyState === WebSocket.OPEN)
88
+ return;
89
+ await new Promise((resolve, reject) => {
90
+ const socket = new WebSocket(this.url);
91
+ const onError = () => reject(new BrowserError(`Could not open a DevTools connection to ${this.url}.`));
92
+ socket.addEventListener("open", () => {
93
+ socket.removeEventListener("error", onError);
94
+ this.socket = socket;
95
+ resolve();
96
+ });
97
+ socket.addEventListener("error", onError, { once: true });
98
+ socket.addEventListener("message", (event) => this.receive(String(event.data)));
99
+ socket.addEventListener("close", () => {
100
+ this.socket = undefined;
101
+ for (const [, entry] of this.pending) {
102
+ entry.reject(new BrowserError("The DevTools connection closed mid-command."));
103
+ }
104
+ this.pending.clear();
105
+ });
106
+ });
107
+ }
108
+ receive(raw) {
109
+ let message;
110
+ try {
111
+ message = JSON.parse(raw);
112
+ }
113
+ catch {
114
+ return;
115
+ }
116
+ if (typeof message.id === "number") {
117
+ const entry = this.pending.get(message.id);
118
+ if (!entry)
119
+ return;
120
+ this.pending.delete(message.id);
121
+ if (message.error) {
122
+ entry.reject(new BrowserError(`DevTools refused the command: ${message.error.message ?? "unknown error"}`));
123
+ }
124
+ else {
125
+ entry.resolve(message.result);
126
+ }
127
+ return;
128
+ }
129
+ if (message.method) {
130
+ for (const listener of this.listeners.get(message.method) ?? []) {
131
+ listener(message.params);
132
+ }
133
+ }
134
+ }
135
+ send(method, params = {}) {
136
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN) {
137
+ return Promise.reject(new BrowserError("The DevTools connection is not open."));
138
+ }
139
+ const id = this.nextId++;
140
+ return new Promise((resolve, reject) => {
141
+ const timer = setTimeout(() => {
142
+ this.pending.delete(id);
143
+ reject(new BrowserError(`DevTools command ${method} did not answer within ${this.timeoutMs}ms.`));
144
+ }, this.timeoutMs);
145
+ this.pending.set(id, {
146
+ resolve: (value) => {
147
+ clearTimeout(timer);
148
+ resolve(value);
149
+ },
150
+ reject: (error) => {
151
+ clearTimeout(timer);
152
+ reject(error);
153
+ },
154
+ });
155
+ this.socket?.send(JSON.stringify({ id, method, params }));
156
+ });
157
+ }
158
+ /**
159
+ * Answer a native `window.alert`, `confirm` or `prompt`.
160
+ *
161
+ * These are not DOM elements, they are browser modals, and while one is open
162
+ * the renderer stops servicing the DevTools protocol entirely. Every command
163
+ * then hangs until its timeout, including the ones trying to clear the modal,
164
+ * so the reply to this one only arrives after it has already worked. That is
165
+ * why it is sent without awaiting.
166
+ *
167
+ * Midjourney uses one for "Add from Link", so this is a normal path, not only
168
+ * an error path.
169
+ */
170
+ answerDialog(accept, promptText) {
171
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN)
172
+ return;
173
+ const id = this.nextId++;
174
+ this.socket.send(JSON.stringify({
175
+ id,
176
+ method: "Page.handleJavaScriptDialog",
177
+ params: { accept, ...(promptText === undefined ? {} : { promptText }) },
178
+ }));
179
+ }
180
+ /** Send a command without waiting for a reply, for use while the page is blocked. */
181
+ fire(method, params = {}) {
182
+ if (!this.socket || this.socket.readyState !== WebSocket.OPEN)
183
+ return;
184
+ this.socket.send(JSON.stringify({ id: this.nextId++, method, params }));
185
+ }
186
+ /** Subscribe to a CDP event for as long as this session lives. */
187
+ on(method, handler) {
188
+ const set = this.listeners.get(method) ?? new Set();
189
+ set.add(handler);
190
+ this.listeners.set(method, set);
191
+ return () => set.delete(handler);
192
+ }
193
+ /** Resolve on the next occurrence of a CDP event, or reject on timeout. */
194
+ once(method, timeoutMs = this.timeoutMs) {
195
+ return new Promise((resolve, reject) => {
196
+ const set = this.listeners.get(method) ?? new Set();
197
+ const timer = setTimeout(() => {
198
+ set.delete(handler);
199
+ reject(new BrowserError(`Timed out waiting for ${method}.`));
200
+ }, timeoutMs);
201
+ const handler = (params) => {
202
+ clearTimeout(timer);
203
+ set.delete(handler);
204
+ resolve(params);
205
+ };
206
+ set.add(handler);
207
+ this.listeners.set(method, set);
208
+ });
209
+ }
210
+ close() {
211
+ if (this.closed)
212
+ return;
213
+ this.closed = true;
214
+ try {
215
+ this.socket?.close();
216
+ }
217
+ catch {
218
+ // Closing a socket that is already gone is not a failure worth surfacing.
219
+ }
220
+ }
221
+ }
222
+ /**
223
+ * The browser this server drives.
224
+ *
225
+ * Everything above the transport talks to `apiFetch` and `fetchBinary` and does
226
+ * not know a browser is involved. That seam is deliberate: a second transport
227
+ * that impersonates Chrome's TLS fingerprint can implement the same two methods
228
+ * for people who need this on a headless box, without any tool changing.
229
+ */
230
+ export class CdpBrowser {
231
+ options;
232
+ session;
233
+ sessionTargetId;
234
+ launched = false;
235
+ /** Text to type into the next native prompt, when one is expected. */
236
+ pendingDialogText;
237
+ constructor(options) {
238
+ this.options = options;
239
+ }
240
+ /** True when something is already answering on the DevTools port. */
241
+ async isRunning() {
242
+ try {
243
+ const response = await fetch(`${this.options.cdpUrl}/json/version`, {
244
+ signal: AbortSignal.timeout(2000),
245
+ });
246
+ return response.ok;
247
+ }
248
+ catch {
249
+ return false;
250
+ }
251
+ }
252
+ async version() {
253
+ try {
254
+ const response = await fetch(`${this.options.cdpUrl}/json/version`, {
255
+ signal: AbortSignal.timeout(2000),
256
+ });
257
+ if (!response.ok)
258
+ return undefined;
259
+ return (await response.json());
260
+ }
261
+ catch {
262
+ return undefined;
263
+ }
264
+ }
265
+ /**
266
+ * Start Chrome on the dedicated profile and wait for DevTools to answer.
267
+ *
268
+ * Detached and with stdio ignored, so the browser outlives this process. A
269
+ * server that killed the browser on exit would log the user out every time an
270
+ * MCP client restarted, which is most of the value gone.
271
+ */
272
+ async launch() {
273
+ if (await this.isRunning())
274
+ return;
275
+ if (!this.options.autoLaunch) {
276
+ throw new BrowserError(`Nothing is listening on ${this.options.cdpUrl} and MIDJOURNEY_CHROME_LAUNCH=0. Start Chrome yourself, or allow auto-launch.`);
277
+ }
278
+ const binary = findChrome(this.options.chromePath);
279
+ await mkdir(this.options.profileDir, { recursive: true });
280
+ const port = new URL(this.options.cdpUrl).port || "9222";
281
+ const args = [
282
+ `--remote-debugging-port=${port}`,
283
+ `--user-data-dir=${this.options.profileDir}`,
284
+ "--no-first-run",
285
+ "--no-default-browser-check",
286
+ "--disable-features=Translate",
287
+ this.options.origin,
288
+ ];
289
+ if (this.options.headless)
290
+ args.unshift("--headless=new");
291
+ spawn(binary, args, { detached: true, stdio: "ignore" }).unref();
292
+ const deadline = Date.now() + 20_000;
293
+ while (Date.now() < deadline) {
294
+ if (await this.isRunning()) {
295
+ this.launched = true;
296
+ return;
297
+ }
298
+ await new Promise((resolve) => setTimeout(resolve, 250));
299
+ }
300
+ throw new BrowserError(`Chrome was started but DevTools never answered on ${this.options.cdpUrl}. Check that no other Chrome is already using that profile directory.`);
301
+ }
302
+ async targets() {
303
+ const response = await fetch(`${this.options.cdpUrl}/json/list`, {
304
+ signal: AbortSignal.timeout(5000),
305
+ });
306
+ if (!response.ok)
307
+ throw new BrowserError(`DevTools listing failed with HTTP ${response.status}.`);
308
+ return (await response.json());
309
+ }
310
+ originHost() {
311
+ return new URL(this.options.origin).host;
312
+ }
313
+ /** A page already on the target origin, or undefined. */
314
+ async findOriginTab() {
315
+ const host = this.originHost();
316
+ return (await this.targets()).find((target) => target.type === "page" &&
317
+ target.webSocketDebuggerUrl !== undefined &&
318
+ (() => {
319
+ try {
320
+ return new URL(target.url).host === host;
321
+ }
322
+ catch {
323
+ return false;
324
+ }
325
+ })());
326
+ }
327
+ /**
328
+ * Open a new tab. Chrome switched `/json/new` to PUT-only, and older builds
329
+ * only accept GET, so try the current spelling and fall back.
330
+ */
331
+ async openTab(url) {
332
+ const endpoint = `${this.options.cdpUrl}/json/new?${encodeURIComponent(url)}`;
333
+ for (const method of ["PUT", "GET"]) {
334
+ try {
335
+ const response = await fetch(endpoint, { method, signal: AbortSignal.timeout(10_000) });
336
+ if (response.ok)
337
+ return (await response.json());
338
+ }
339
+ catch {
340
+ // Try the other verb before giving up.
341
+ }
342
+ }
343
+ throw new BrowserError("Could not open a new browser tab through DevTools.");
344
+ }
345
+ async closeTab(targetId) {
346
+ try {
347
+ await fetch(`${this.options.cdpUrl}/json/close/${targetId}`, {
348
+ signal: AbortSignal.timeout(5000),
349
+ });
350
+ }
351
+ catch {
352
+ // A tab that failed to close is untidy, not broken.
353
+ }
354
+ }
355
+ /** A connected session against a page on the target origin, reused across calls. */
356
+ async originSession() {
357
+ if (this.session && this.sessionTargetId) {
358
+ const still = (await this.targets()).some((target) => target.id === this.sessionTargetId);
359
+ if (still)
360
+ return this.session;
361
+ this.session.close();
362
+ this.session = undefined;
363
+ this.sessionTargetId = undefined;
364
+ }
365
+ await this.launch();
366
+ let tab = await this.findOriginTab();
367
+ if (!tab) {
368
+ tab = await this.openTab(this.options.origin);
369
+ // A fresh tab has not run its scripts yet. The page does not need to be
370
+ // interactive for fetch() to work, only same-origin, but navigating takes
371
+ // a moment and evaluating against about:blank would be the wrong origin.
372
+ await new Promise((resolve) => setTimeout(resolve, 1500));
373
+ const settled = await this.findOriginTab();
374
+ if (settled)
375
+ tab = settled;
376
+ }
377
+ if (!tab.webSocketDebuggerUrl) {
378
+ throw new BrowserError("Found a Midjourney tab but DevTools gave no debugger URL for it. Another debugger may already be attached.");
379
+ }
380
+ const session = new CdpSession(tab.webSocketDebuggerUrl, this.options.timeoutMs);
381
+ await session.connect();
382
+ // Arm dialog handling before anything else runs.
383
+ //
384
+ // A native modal freezes the renderer, and every later command times out,
385
+ // including the ones that would clear it. Without this the server does not
386
+ // recover on its own: it stays broken until someone clicks the dialog by
387
+ // hand, which is not a thing a background process can rely on.
388
+ //
389
+ // Dismissed rather than accepted, because an unexpected dialog is a
390
+ // question nobody asked and "no" is the safe answer. A tool that means to
391
+ // answer one arms `pendingDialogText` first.
392
+ session.fire("Page.enable");
393
+ session.on("Page.javascriptDialogOpening", () => {
394
+ const answer = this.pendingDialogText;
395
+ this.pendingDialogText = undefined;
396
+ session.answerDialog(answer !== undefined, answer);
397
+ });
398
+ this.session = session;
399
+ this.sessionTargetId = tab.id;
400
+ return session;
401
+ }
402
+ /**
403
+ * Answer the next native prompt with this text instead of dismissing it.
404
+ *
405
+ * Consumed once. Midjourney's "Add from Link" is a `window.prompt`, so
406
+ * driving it means having the answer ready before the click that opens it.
407
+ */
408
+ expectDialog(text) {
409
+ this.pendingDialogText = text;
410
+ }
411
+ /** Evaluate an expression in the page and return its value. */
412
+ async evaluate(session, expression) {
413
+ const result = await session.send("Runtime.evaluate", {
414
+ expression,
415
+ awaitPromise: true,
416
+ returnByValue: true,
417
+ });
418
+ if (result.exceptionDetails) {
419
+ const detail = result.exceptionDetails.exception?.description ??
420
+ result.exceptionDetails.text ??
421
+ "unknown error";
422
+ throw new BrowserError(`The page threw while running the request: ${detail}`);
423
+ }
424
+ return result.result?.value;
425
+ }
426
+ /**
427
+ * Issue an API request from inside the page.
428
+ *
429
+ * `credentials: 'include'` is what makes this work: the browser attaches the
430
+ * session and Cloudflare clearance cookies itself, so nothing here ever
431
+ * handles a credential. The whole response is returned as text and parsed
432
+ * upstream, because an error page is HTML and swallowing that would lose the
433
+ * only clue about what went wrong.
434
+ */
435
+ async apiFetch(path, init = {}) {
436
+ const session = await this.originSession();
437
+ const request = {
438
+ path,
439
+ method: init.method ?? "GET",
440
+ body: init.body === undefined ? null : JSON.stringify(init.body),
441
+ headers: {
442
+ accept: "application/json",
443
+ "x-csrf-protection": "1",
444
+ ...(init.body === undefined ? {} : { "content-type": "application/json" }),
445
+ ...(init.headers ?? {}),
446
+ },
447
+ };
448
+ const expression = `(async (req) => {
449
+ try {
450
+ const response = await fetch(req.path, {
451
+ method: req.method,
452
+ headers: req.headers,
453
+ credentials: 'include',
454
+ body: req.body,
455
+ });
456
+ return { ok: response.ok, status: response.status, body: await response.text() };
457
+ } catch (error) {
458
+ return { ok: false, status: 0, body: '', networkError: String(error && error.message ? error.message : error) };
459
+ }
460
+ })(${JSON.stringify(request)})`;
461
+ return this.evaluate(session, expression);
462
+ }
463
+ /**
464
+ * Evaluate an expression in the Midjourney page and return its value.
465
+ *
466
+ * Used for the things the API does not answer. The signed-in user's own id is
467
+ * the case that matters: the endpoints want it as a parameter but none of
468
+ * them returns it, while the app has had it in memory since it booted.
469
+ */
470
+ async evaluateInPage(expression) {
471
+ const session = await this.originSession();
472
+ return this.evaluate(session, expression);
473
+ }
474
+ /**
475
+ * Make the open window show what just happened.
476
+ *
477
+ * Requests go out through `fetch()` behind the page, so the app never learns
478
+ * a job was submitted: its own grid only updates for work it started itself.
479
+ * The window then sits there looking stale until someone reloads it by hand,
480
+ * which makes a tool that is working look like a tool that is broken.
481
+ *
482
+ * A reload is blunt, and it is what the app does anyway on navigation. It is
483
+ * fire-and-forget: never awaited into a tool result, and a failure here is
484
+ * cosmetic, so it must not fail a generation that already succeeded.
485
+ */
486
+ async refreshView() {
487
+ if (!(await this.isRunning()))
488
+ return;
489
+ const session = await this.originSession();
490
+ await this.evaluate(session, "(() => { location.reload(); return 1; })()").catch(() => undefined);
491
+ }
492
+ /**
493
+ * Fetch a binary asset and return it base64 encoded.
494
+ *
495
+ * Done from inside the existing page, which means no window activity at all:
496
+ * no new tab, no navigation, no flash.
497
+ *
498
+ * The reference implementation for this API states that the CDN "disallows
499
+ * browser fetch() from www.midjourney.com via CORS" and falls back to
500
+ * screenshotting the rendered element. That is not true, at least not any
501
+ * more: cdn.midjourney.com answers with `access-control-allow-origin: *`, and
502
+ * a same-page fetch returns the exact bytes. Verified against a real asset,
503
+ * byte count matching the file on disk.
504
+ *
505
+ * So this reads the real image rather than a re-encoded picture of one, and
506
+ * it does it without touching the user's window. `openTab` remains for the
507
+ * navigation fallback below, for an asset on some host that does refuse.
508
+ */
509
+ async fetchBinary(url) {
510
+ const inPage = await this.fetchBinaryInPage(url).catch(() => undefined);
511
+ if (inPage)
512
+ return inPage;
513
+ return this.fetchBinaryByNavigation(url);
514
+ }
515
+ async fetchBinaryInPage(url) {
516
+ const session = await this.originSession();
517
+ // FileReader rather than a manual loop over the bytes: a 2 MB image is two
518
+ // million iterations of string concatenation otherwise, which is slow
519
+ // enough to trip the command timeout.
520
+ const expression = `(async () => {
521
+ try {
522
+ const response = await fetch(${JSON.stringify(url)}, { credentials: 'omit' });
523
+ if (!response.ok) return { error: 'HTTP ' + response.status };
524
+ const blob = await response.blob();
525
+ const base64 = await new Promise((resolve, reject) => {
526
+ const reader = new FileReader();
527
+ reader.onerror = () => reject(new Error('read failed'));
528
+ reader.onload = () => resolve(String(reader.result).split(',')[1] || '');
529
+ reader.readAsDataURL(blob);
530
+ });
531
+ return { base64, mimeType: blob.type || '', bytes: blob.size };
532
+ } catch (error) {
533
+ return { error: String(error && error.message ? error.message : error) };
534
+ }
535
+ })()`;
536
+ const result = await this.evaluate(session, expression);
537
+ if (!result || result.error || !result.base64)
538
+ return undefined;
539
+ return { base64: result.base64, mimeType: result.mimeType || mimeFromUrl(url) };
540
+ }
541
+ /**
542
+ * The fallback: navigate a throwaway tab and read the bytes back.
543
+ *
544
+ * Only reached when a host refuses a cross-origin read. It does open and
545
+ * close a tab, which is visible, so it is deliberately second.
546
+ */
547
+ async fetchBinaryByNavigation(url) {
548
+ await this.launch();
549
+ const tab = await this.openTab(url);
550
+ if (!tab.webSocketDebuggerUrl) {
551
+ await this.closeTab(tab.id);
552
+ throw new BrowserError("Could not attach to the tab opened for the download.");
553
+ }
554
+ const session = new CdpSession(tab.webSocketDebuggerUrl, this.options.timeoutMs);
555
+ try {
556
+ await session.connect();
557
+ await session.send("Page.enable");
558
+ const loaded = session.once("Page.loadEventFired", this.options.timeoutMs).catch(() => undefined);
559
+ await session.send("Page.navigate", { url });
560
+ await loaded;
561
+ const tree = await session.send("Page.getResourceTree");
562
+ const frameId = tree.frameTree.frame.id;
563
+ const content = await session.send("Page.getResourceContent", { frameId, url });
564
+ if (!content.base64Encoded) {
565
+ return {
566
+ base64: Buffer.from(content.content, "utf8").toString("base64"),
567
+ mimeType: "application/octet-stream",
568
+ };
569
+ }
570
+ return { base64: content.content, mimeType: mimeFromUrl(url) };
571
+ }
572
+ finally {
573
+ session.close();
574
+ await this.closeTab(tab.id);
575
+ }
576
+ }
577
+ close() {
578
+ this.session?.close();
579
+ this.session = undefined;
580
+ this.sessionTargetId = undefined;
581
+ }
582
+ get didLaunch() {
583
+ return this.launched;
584
+ }
585
+ }
586
+ export function mimeFromUrl(url) {
587
+ const path = url.split("?")[0] ?? "";
588
+ const extension = path.slice(path.lastIndexOf(".") + 1).toLowerCase();
589
+ switch (extension) {
590
+ case "png":
591
+ return "image/png";
592
+ case "jpg":
593
+ case "jpeg":
594
+ return "image/jpeg";
595
+ case "webp":
596
+ return "image/webp";
597
+ case "gif":
598
+ return "image/gif";
599
+ case "mp4":
600
+ return "video/mp4";
601
+ case "webm":
602
+ return "video/webm";
603
+ default:
604
+ return "application/octet-stream";
605
+ }
606
+ }
607
+ //# sourceMappingURL=cdp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cdp.js","sourceRoot":"","sources":["../../src/transport/cdp.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Streamable HTTP transport, for running this somewhere always on.
3
+ *
4
+ * Stdio is what an MCP client launches locally. This is for the other case: one
5
+ * machine that holds the browser session, reached by clients elsewhere. Bearer
6
+ * auth is mandatory when the listener is not on loopback, because this server
7
+ * acts as a signed-in Midjourney account and can spend money.
8
+ */
9
+ import type { BuiltServer } from "../server.js";
10
+ export type HttpOptions = {
11
+ port: number;
12
+ host: string;
13
+ token?: string;
14
+ };
15
+ export declare function httpOptionsFromEnv(argv?: string[]): HttpOptions;
16
+ export declare function startHttpServer(built: BuiltServer, options: HttpOptions): Promise<{
17
+ close: () => Promise<void>;
18
+ }>;