Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
314375d
feat: debug via cli
Mkassabov Aug 19, 2025
3ac1506
feat: working
Mkassabov Aug 19, 2025
0b6d895
fix: support inspect & inspect-brk flags to control debugging
Mkassabov Aug 19, 2025
7a275bb
???
Mkassabov Aug 19, 2025
2f9e65a
feat: support the vscode debugger
Mkassabov Aug 19, 2025
93aab6e
better formatted server list
Mkassabov Aug 19, 2025
63cc10b
feat: inspect and inspect wait
Mkassabov Aug 19, 2025
84bf8fa
Update server.ts
Mkassabov Aug 19, 2025
2b07a7b
chore: debugging guide
Mkassabov Aug 19, 2025
2bff91d
fix build
Mkassabov Aug 19, 2025
7bc51ed
astro doesn't like comments I guess?
Mkassabov Aug 19, 2025
40dd151
chore(core): handle multiple CDP client's individual message streams
Mkassabov Aug 26, 2025
6d211b8
issue with registration request
Mkassabov Aug 27, 2025
fa054ba
almost working
Mkassabov Aug 28, 2025
255edd1
work?
Mkassabov Aug 28, 2025
261108a
okay finally actually working holy christ
Mkassabov Aug 28, 2025
c97bce4
clean up logs
Mkassabov Aug 28, 2025
920d7ed
client domain tracking
Mkassabov Aug 28, 2025
600eac0
ALMOST
Mkassabov Aug 28, 2025
6c72681
special case handling
Mkassabov Aug 28, 2025
bc30889
Merge branch 'main' into mkassabov/dev-cdp-tooling-2
Mkassabov Aug 28, 2025
f96f383
Merge branch 'mkassabov/dev-cdp-tooling-2' into dev-cdp-tooling-2-clo…
Mkassabov Aug 28, 2025
7dc6df4
Update cdp-proxy.ts
Mkassabov Aug 28, 2025
a379281
Merge branch 'main' into dev-cdp-tooling-2-cloudflare
Mkassabov Nov 4, 2025
f151134
Update bun.lock
Mkassabov Nov 4, 2025
414cc83
Update scope.ts
Mkassabov Nov 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -261,4 +261,4 @@ This guide shows how to create and manage [PlanetScale](https://planetscale.com/
</TabItem>
</Tabs>

</Steps>
</Steps>
107 changes: 89 additions & 18 deletions alchemy/bin/services/cdp-manager/cdp-proxy.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,64 @@
import type { WebSocket as WsWebSocket } from "ws";
import { CDPServer } from "./server.ts";
import { WebSocket } from "ws";
import {
CDPServer,
type ClientCDPMessage,
type ServerCDPMessage,
} from "./server.ts";

export class CDPProxy extends CDPServer {
private inspectorUrl: string;
private inspectorWs?: WebSocket;
private onStartMessageQueue: Array<string>;
private onStartMessageQueue: Array<ClientCDPMessage>;
private enabledDomains: Set<string> = new Set();
private debuggerId?: string;

constructor(
inspectorUrl: string,
options: ConstructorParameters<typeof CDPServer>[0] & {
connect?: boolean;
hotDomains?: Array<string>;
},
) {
super(options);
this.inspectorUrl = inspectorUrl;
this.onStartMessageQueue = [];
for (const domain of options.hotDomains ?? []) {
this.onStartMessageQueue.push({
id: ++this.internalMessageId,
method: `${domain}.enable`,
params: {},
});
}
if (options.connect ?? true) {
this.start();
}
}

public async start(): Promise<void> {
this.inspectorWs = new WebSocket(this.inspectorUrl);
if (this.inspectorWs != null) {
this.inspectorWs.close();
}
this.inspectorWs = new WebSocket(this.inspectorUrl, {
headers: {
Origin: "http://localhost",
},
});

this.inspectorWs.onmessage = async (event) => {
const json = JSON.parse(event.data.toString()) as ServerCDPMessage;
if (json.id != null && json?.result?.debuggerId != null) {
this.debuggerId = json?.result?.debuggerId;
}
await this.handleInspectorMessage(
JSON.parse(event.data.toString()) as ServerCDPMessage,
);
};

this.inspectorWs.addEventListener("open", async () => {
this.inspectorWs.onopen = async () => {
await new Promise((resolve) => setTimeout(resolve, 1000));
for (const message of this.onStartMessageQueue) {
this.internalHandleClientMessage(message);
this.handleClientMessage(undefined, message);
}
});

this.inspectorWs.onmessage = async (event) => {
await this.handleInspectorMessage(event.data.toString());
};

this.inspectorWs.onclose = () => {
Expand All @@ -43,7 +70,10 @@ export class CDPProxy extends CDPServer {
};
}

async handleClientMessage(_ws: WsWebSocket, data: string): Promise<void> {
async handleClientMessage(
clientId: string | undefined,
data: ClientCDPMessage,
): Promise<void> {
if (
this.inspectorWs == null ||
this.inspectorWs.readyState !== WebSocket.OPEN
Expand All @@ -54,16 +84,57 @@ export class CDPProxy extends CDPServer {
this.onStartMessageQueue.push(data);
return;
} else {
this.internalHandleClientMessage(data);
this.internalHandleClientMessage(clientId, data);
}
}

private async internalHandleClientMessage(data: string): Promise<void> {
const message = JSON.parse(data);
const messageDomain = message.method?.split(".")?.[0];
if (messageDomain != null && !this.domains.has(messageDomain)) {
return;
private async internalHandleClientMessage(
clientId: string | undefined,
data: ClientCDPMessage,
): Promise<void> {
const messageDomain = data.method?.split(".")?.[0];

if (data.method?.endsWith(".enable") && messageDomain) {
if (this.enabledDomains.has(messageDomain)) {
if (clientId != null) {
const client = this.getClientById(clientId);
if (client != null) {
//* handle some special cases where enabling isn't properly reported
switch (data.method) {
case "Runtime.enable": {
client.send(
JSON.stringify({
id: data.id,
result: {},
}),
);
break;
}
case "Debugger.enable": {
if (this.debuggerId != null) {
client.send(
JSON.stringify({
id: data.id,
result: {
debuggerId: this.debuggerId,
},
}),
);
break;
}
}
}
}
}
return;
}
this.enabledDomains.add(messageDomain);

if (data.id != null) {
data.id = ++this.internalMessageId;
}
}
this.inspectorWs!.send(data);

this.inspectorWs!.send(JSON.stringify(data));
}
}
Loading
Loading