Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions apps/koa/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "nodemon --exec NODE_OPTIONS=--inspect-brk NODE_ENV=development ts-node --files ./src/index.ts",
"dev": "cross-env NETWORK_DEBUG_MODE=true node --inspect --watch ./src/index.js",
"start": "cross-env NODE_ENV=production node --inspect ./src/index.js",
"dev": "cross-env NETWORK_DEBUG_MODE=true node --inspect --experimental-network-inspection --watch ./src/index.js",
"start": "cross-env NODE_ENV=production node ./src/index.js",
"build": "vite build"
},
"keywords": [],
Expand Down
13 changes: 12 additions & 1 deletion apps/koa/src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
const WebSocket = require('ws')

function ensureNode16() {
if (typeof global.ReadableStream === 'undefined') {
const { ReadableStream, WritableStream, TransformStream } = require('node:stream/web')
global.ReadableStream = ReadableStream
global.WritableStream = WritableStream
global.TransformStream = TransformStream
}
}

const run = () => {
let register
try {
ensureNode16()
register = require('node-network-devtools').register
} catch {
} catch (e) {
console.error(e)
setTimeout(run, 1000)
return
}
Expand Down
2 changes: 1 addition & 1 deletion packages/network-debugger/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "node-network-devtools",
"version": "1.0.28",
"version": "1.0.29",
"description": "Inspecting Node.js's Network with Chrome DevTools",
"homepage": "https://grinzero.github.io/node-network-devtools/",
"main": "./dist/index.js",
Expand Down
4 changes: 2 additions & 2 deletions packages/network-debugger/src/fork/module/health/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ export const healthPlugin = createPlugin('health', ({ devtool }) => {
process.exit(0)
}

let id = setTimeout(exitProcess, 5000)
let id = setTimeout(exitProcess, 10000)
useHandler('healthcheck', () => {
clearTimeout(id)
id = setTimeout(exitProcess, 5000)
id = setTimeout(exitProcess, 10000)
})
})
63 changes: 62 additions & 1 deletion packages/network-debugger/src/fork/module/network/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ import { BodyTransformer, RequestHeaderPipe } from '../../pipe'
import { createPlugin, useHandler } from '../common'
import zlib from 'node:zlib'
import { ResourceService } from '../../resource-service'
import type { Network, Runtime } from 'node:inspector'

const inspector = (async () => {
return await import('node:inspector')
})()

const frameId = '517.528'
const loaderId = '517.529'
Expand All @@ -12,6 +17,44 @@ export const toMimeType = (contentType: string) => {
return contentType.split(';')[0] || 'text/plain'
}

/**
* 将本项目中的 Initiator 结构转换为 node:inspector 的 Network.Initiator
* - 本地格式:{ type: string; stack: { callFrames: CDPCallFrame[] } }
* - 目标格式:Network.Initiator(可包含 url/lineNumber/columnNumber 等可选字段)
*/
export const toInspectorInitiator = (initiator?: RequestDetail['initiator']): Network.Initiator => {
if (!initiator) {
// 提供一个最小可用的 Initiator,避免类型不满足要求
return { type: 'other' }
}

const callFrames = initiator.stack?.callFrames ?? []

// 仅在所有必要字段存在时构造 StackTrace,以满足类型约束
const framesForInspector: Runtime.CallFrame[] = callFrames
.filter((f) => typeof f.scriptId === 'string' && !!f.scriptId)
.map((f) => ({
functionName: f.functionName || '',
scriptId: f.scriptId as string,
url: f.url || '',
lineNumber: typeof f.lineNumber === 'number' ? f.lineNumber : 0,
columnNumber: typeof f.columnNumber === 'number' ? f.columnNumber : 0
}))

const stack: Runtime.StackTrace | undefined =
framesForInspector.length > 0 ? { callFrames: framesForInspector } : undefined

const topFrame = callFrames[0]

return {
type: initiator.type,
...(stack ? { stack } : {}),
...(topFrame?.url ? { url: topFrame.url } : {}),
...(typeof topFrame?.lineNumber === 'number' ? { lineNumber: topFrame.lineNumber } : {}),
...(typeof topFrame?.columnNumber === 'number' ? { columnNumber: topFrame.columnNumber } : {})
}
}

export const networkPlugin = createPlugin('network', ({ devtool, core }) => {
const requests: Record<string, RequestDetail> = {}

Expand All @@ -22,6 +65,7 @@ export const networkPlugin = createPlugin('network', ({ devtool, core }) => {
requests[request.id] = request
}
const endRequest = (request: RequestDetail) => {
requests[request.id] = request
request.requestEndTime = request.requestEndTime || Date.now()
devtool.updateTimestamp()
const headers = new RequestHeaderPipe(request.responseHeaders)
Expand Down Expand Up @@ -145,9 +189,11 @@ export const networkPlugin = createPlugin('network', ({ devtool, core }) => {
requests[request.id] = request
})

useHandler<RequestDetail>('registerRequest', ({ data }) => {
useHandler<RequestDetail>('registerRequest', async ({ data }) => {
const request = new RequestDetail(data)

const inspect = await inspector.catch(() => null)

requests[request.id] = request
// replace callFrames' scriptId
if (request.initiator) {
Expand All @@ -166,6 +212,21 @@ export const networkPlugin = createPlugin('network', ({ devtool, core }) => {
const headerPipe = new RequestHeaderPipe(request.requestHeaders)
const contentType = headerPipe.getHeader('content-type')

if (inspect && inspect.Network) {
const newInitiator = toInspectorInitiator(request.initiator)
inspect.Network.requestWillBeSent({
requestId: request.id,
timestamp: devtool.timestamp,
wallTime: request.requestStartTime!,
request: {
url: request.url!,
method: request.method!,
headers: headerPipe.getData()
},
initiator: newInitiator!
})
}

return devtool.send({
method: 'Network.requestWillBeSent',
params: {
Expand Down