@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.
- package/LICENSE +21 -0
- package/README.md +677 -0
- package/SKILL.md +184 -0
- package/dist/api/client.d.ts +72 -0
- package/dist/api/client.js +278 -0
- package/dist/api/client.js.map +1 -0
- package/dist/api/download.d.ts +41 -0
- package/dist/api/download.js +108 -0
- package/dist/api/download.js.map +1 -0
- package/dist/api/errors.d.ts +75 -0
- package/dist/api/errors.js +166 -0
- package/dist/api/errors.js.map +1 -0
- package/dist/api/jobs.d.ts +140 -0
- package/dist/api/jobs.js +296 -0
- package/dist/api/jobs.js.map +1 -0
- package/dist/api/moodboards.d.ts +88 -0
- package/dist/api/moodboards.js +189 -0
- package/dist/api/moodboards.js.map +1 -0
- package/dist/capture.d.ts +27 -0
- package/dist/capture.js +162 -0
- package/dist/capture.js.map +1 -0
- package/dist/cli.d.ts +92 -0
- package/dist/cli.js +633 -0
- package/dist/cli.js.map +1 -0
- package/dist/config.d.ts +37 -0
- package/dist/config.js +90 -0
- package/dist/config.js.map +1 -0
- package/dist/content/prompt.d.ts +69 -0
- package/dist/content/prompt.js +173 -0
- package/dist/content/prompt.js.map +1 -0
- package/dist/doctor.d.ts +19 -0
- package/dist/doctor.js +161 -0
- package/dist/doctor.js.map +1 -0
- package/dist/format/jobs.d.ts +71 -0
- package/dist/format/jobs.js +211 -0
- package/dist/format/jobs.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +161 -0
- package/dist/index.js.map +1 -0
- package/dist/safety.d.ts +52 -0
- package/dist/safety.js +100 -0
- package/dist/safety.js.map +1 -0
- package/dist/server.d.ts +10 -0
- package/dist/server.js +57 -0
- package/dist/server.js.map +1 -0
- package/dist/tools/create.d.ts +96 -0
- package/dist/tools/create.js +375 -0
- package/dist/tools/create.js.map +1 -0
- package/dist/tools/download.d.ts +17 -0
- package/dist/tools/download.js +47 -0
- package/dist/tools/download.js.map +1 -0
- package/dist/tools/explore.d.ts +8 -0
- package/dist/tools/explore.js +57 -0
- package/dist/tools/explore.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.js +16 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/jobs.d.ts +18 -0
- package/dist/tools/jobs.js +92 -0
- package/dist/tools/jobs.js.map +1 -0
- package/dist/tools/kit.d.ts +84 -0
- package/dist/tools/kit.js +104 -0
- package/dist/tools/kit.js.map +1 -0
- package/dist/tools/library.d.ts +22 -0
- package/dist/tools/library.js +185 -0
- package/dist/tools/library.js.map +1 -0
- package/dist/tools/profile.d.ts +2 -0
- package/dist/tools/profile.js +89 -0
- package/dist/tools/profile.js.map +1 -0
- package/dist/transport/cdp.d.ts +217 -0
- package/dist/transport/cdp.js +607 -0
- package/dist/transport/cdp.js.map +1 -0
- package/dist/transport/http.d.ts +18 -0
- package/dist/transport/http.js +48 -0
- package/dist/transport/http.js.map +1 -0
- 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
|
+
}>;
|