shippie
Version:
an extensible code review agent
1 lines ⢠145 kB
Source Map (JSON)
{"version":3,"file":"server.mjs","names":["#init","#body","#init","#eventInitDict"],"sources":["../node_modules/@hono/node-server/dist/constants-BXAKTxRC.cjs","../node_modules/hono/dist/cjs/helper/websocket/index.js","../node_modules/@hono/node-server/dist/index.cjs","../src/channels/github.ts","../src/agents/mention.ts","../src/common/formatting/summary.ts","../src/github/reporter.ts","../src/review/config.ts","../src/review/instructions.ts","../src/tools/suggest-change.ts","../src/agents/reviewer.ts","../src/common/telemetry.ts","../src/mcp/connect.ts","../src/review/prompt/fileInfo.ts","../src/review/context.ts","../src/review/diff.ts","../src/review/constants.ts","../src/review/utils/filterFiles.ts","../src/workflows/review.ts","../.flue-vite/_entry_server.ts"],"sourcesContent":["\n//#region src/utils/response/constants.ts\nconst X_ALREADY_SENT = \"x-hono-already-sent\";\n\n//#endregion\nObject.defineProperty(exports, 'X_ALREADY_SENT', {\n enumerable: true,\n get: function () {\n return X_ALREADY_SENT;\n }\n});","var __defProp = Object.defineProperty;\nvar __getOwnPropDesc = Object.getOwnPropertyDescriptor;\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __hasOwnProp = Object.prototype.hasOwnProperty;\nvar __export = (target, all) => {\n for (var name in all)\n __defProp(target, name, { get: all[name], enumerable: true });\n};\nvar __copyProps = (to, from, except, desc) => {\n if (from && typeof from === \"object\" || typeof from === \"function\") {\n for (let key of __getOwnPropNames(from))\n if (!__hasOwnProp.call(to, key) && key !== except)\n __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });\n }\n return to;\n};\nvar __toCommonJS = (mod) => __copyProps(__defProp({}, \"__esModule\", { value: true }), mod);\nvar websocket_exports = {};\n__export(websocket_exports, {\n WSContext: () => WSContext,\n createWSMessageEvent: () => createWSMessageEvent,\n defineWebSocketHelper: () => defineWebSocketHelper\n});\nmodule.exports = __toCommonJS(websocket_exports);\nclass WSContext {\n #init;\n constructor(init) {\n this.#init = init;\n this.raw = init.raw;\n this.url = init.url ? new URL(init.url) : null;\n this.protocol = init.protocol ?? null;\n }\n send(source, options) {\n this.#init.send(source, options ?? {});\n }\n raw;\n binaryType = \"arraybuffer\";\n get readyState() {\n return this.#init.readyState;\n }\n url;\n protocol;\n close(code, reason) {\n this.#init.close(code, reason);\n }\n}\nconst createWSMessageEvent = (source) => {\n return new MessageEvent(\"message\", {\n data: source\n });\n};\nconst defineWebSocketHelper = (handler) => {\n return ((...args) => {\n if (typeof args[0] === \"function\") {\n const [createEvents, options] = args;\n return async function upgradeWebSocket(c, next) {\n const events = await createEvents(c);\n const result = await handler(c, events, options);\n if (result) {\n return result;\n }\n await next();\n };\n } else {\n const [c, events, options] = args;\n return (async () => {\n const upgraded = await handler(c, events, options);\n if (!upgraded) {\n throw new Error(\"Failed to upgrade WebSocket\");\n }\n return upgraded;\n })();\n }\n });\n};\n// Annotate the CommonJS export names for ESM import in node:\n0 && (module.exports = {\n WSContext,\n createWSMessageEvent,\n defineWebSocketHelper\n});\n","Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\nconst require_constants = require('./constants-BXAKTxRC.cjs');\nlet node_http = require(\"node:http\");\nlet node_http2 = require(\"node:http2\");\nlet node_stream = require(\"node:stream\");\nlet hono_ws = require(\"hono/ws\");\n\n//#region src/error.ts\nvar RequestError = class extends Error {\n\tconstructor(message, options) {\n\t\tsuper(message, options);\n\t\tthis.name = \"RequestError\";\n\t}\n};\n\n//#endregion\n//#region src/url.ts\nconst reValidRequestUrl = /^\\/[!#$&-;=?-\\[\\]_a-z~]*$/;\nconst reDotSegment = /\\/\\.\\.?(?:[/?#]|$)/;\nconst reValidHost = /^[a-z0-9._-]+(?::(?:[1-5]\\d{3,4}|[6-9]\\d{3}))?$/;\nconst buildUrl = (scheme, host, incomingUrl) => {\n\tconst url = `${scheme}://${host}${incomingUrl}`;\n\tif (!reValidHost.test(host)) {\n\t\tconst urlObj = new URL(url);\n\t\tif (urlObj.hostname.length !== host.length && urlObj.hostname !== (host.includes(\":\") ? host.replace(/:\\d+$/, \"\") : host).toLowerCase()) throw new RequestError(\"Invalid host header\");\n\t\treturn urlObj.href;\n\t} else if (incomingUrl.length === 0) return url + \"/\";\n\telse {\n\t\tif (incomingUrl.charCodeAt(0) !== 47) throw new RequestError(\"Invalid URL\");\n\t\tif (!reValidRequestUrl.test(incomingUrl) || reDotSegment.test(incomingUrl)) return new URL(url).href;\n\t\treturn url;\n\t}\n};\n\n//#endregion\n//#region src/request.ts\nconst toRequestError = (e) => {\n\tif (e instanceof RequestError) return e;\n\treturn new RequestError(e.message, { cause: e });\n};\nconst GlobalRequest = global.Request;\nvar Request$1 = class extends GlobalRequest {\n\tconstructor(input, options) {\n\t\tif (typeof input === \"object\" && getRequestCache in input) {\n\t\t\tconst hasReplacementBody = options !== void 0 && \"body\" in options && options.body != null;\n\t\t\tif (input[bodyConsumedDirectlyKey] && !hasReplacementBody) throw new TypeError(\"Cannot construct a Request with a Request object that has already been used.\");\n\t\t\tinput = input[getRequestCache]();\n\t\t}\n\t\tif (typeof (options?.body)?.getReader !== \"undefined\") options.duplex ??= \"half\";\n\t\tsuper(input, options);\n\t}\n};\nconst newHeadersFromIncoming = (incoming) => {\n\tconst headerRecord = [];\n\tconst rawHeaders = incoming.rawHeaders;\n\tfor (let i = 0, len = rawHeaders.length; i < len; i += 2) {\n\t\tconst key = rawHeaders[i];\n\t\tif (key.charCodeAt(0) !== 58) headerRecord.push([key, rawHeaders[i + 1]]);\n\t}\n\treturn new Headers(headerRecord);\n};\nconst wrapBodyStream = Symbol(\"wrapBodyStream\");\nconst newRequestFromIncoming = (method, url, headers, incoming, abortController) => {\n\tconst init = {\n\t\tmethod,\n\t\theaders,\n\t\tsignal: abortController.signal\n\t};\n\tif (method === \"TRACE\") {\n\t\tinit.method = \"GET\";\n\t\tconst req = new Request$1(url, init);\n\t\tObject.defineProperty(req, \"method\", { get() {\n\t\t\treturn \"TRACE\";\n\t\t} });\n\t\treturn req;\n\t}\n\tif (!(method === \"GET\" || method === \"HEAD\")) if (\"rawBody\" in incoming && incoming.rawBody instanceof Buffer) init.body = new ReadableStream({ start(controller) {\n\t\tcontroller.enqueue(incoming.rawBody);\n\t\tcontroller.close();\n\t} });\n\telse if (incoming[wrapBodyStream]) {\n\t\tlet reader;\n\t\tinit.body = new ReadableStream({ async pull(controller) {\n\t\t\ttry {\n\t\t\t\treader ||= node_stream.Readable.toWeb(incoming).getReader();\n\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\tif (done) controller.close();\n\t\t\t\telse controller.enqueue(value);\n\t\t\t} catch (error) {\n\t\t\t\tcontroller.error(error);\n\t\t\t}\n\t\t} });\n\t} else init.body = node_stream.Readable.toWeb(incoming);\n\treturn new Request$1(url, init);\n};\nconst getRequestCache = Symbol(\"getRequestCache\");\nconst requestCache = Symbol(\"requestCache\");\nconst incomingKey = Symbol(\"incomingKey\");\nconst urlKey = Symbol(\"urlKey\");\nconst methodKey = Symbol(\"methodKey\");\nconst headersKey = Symbol(\"headersKey\");\nconst abortControllerKey = Symbol(\"abortControllerKey\");\nconst getAbortController = Symbol(\"getAbortController\");\nconst abortRequest = Symbol(\"abortRequest\");\nconst bodyBufferKey = Symbol(\"bodyBuffer\");\nconst bodyReadPromiseKey = Symbol(\"bodyReadPromise\");\nconst bodyConsumedDirectlyKey = Symbol(\"bodyConsumedDirectly\");\nconst bodyLockReaderKey = Symbol(\"bodyLockReader\");\nconst abortReasonKey = Symbol(\"abortReason\");\nconst newBodyUnusableError = () => {\n\treturn /* @__PURE__ */ new TypeError(\"Body is unusable\");\n};\nconst rejectBodyUnusable = () => {\n\treturn Promise.reject(newBodyUnusableError());\n};\nconst textDecoder = new TextDecoder();\nconst consumeBodyDirectOnce = (request) => {\n\tif (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();\n\trequest[bodyConsumedDirectlyKey] = true;\n};\nconst toArrayBuffer = (buf) => {\n\treturn buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);\n};\nconst contentType = (request) => {\n\treturn (request[headersKey] ||= newHeadersFromIncoming(request[incomingKey])).get(\"content-type\") || \"\";\n};\nconst methodTokenRegExp = /^[!#$%&'*+\\-.^_`|~0-9A-Za-z]+$/;\nconst normalizeIncomingMethod = (method) => {\n\tif (typeof method !== \"string\" || method.length === 0) return \"GET\";\n\tswitch (method) {\n\t\tcase \"DELETE\":\n\t\tcase \"GET\":\n\t\tcase \"HEAD\":\n\t\tcase \"OPTIONS\":\n\t\tcase \"POST\":\n\t\tcase \"PUT\": return method;\n\t}\n\tconst upper = method.toUpperCase();\n\tswitch (upper) {\n\t\tcase \"DELETE\":\n\t\tcase \"GET\":\n\t\tcase \"HEAD\":\n\t\tcase \"OPTIONS\":\n\t\tcase \"POST\":\n\t\tcase \"PUT\": return upper;\n\t\tdefault: return method;\n\t}\n};\nconst validateDirectReadMethod = (method) => {\n\tif (!methodTokenRegExp.test(method)) return /* @__PURE__ */ new TypeError(`'${method}' is not a valid HTTP method.`);\n\tconst normalized = method.toUpperCase();\n\tif (normalized === \"CONNECT\" || normalized === \"TRACK\" || normalized === \"TRACE\" && method !== \"TRACE\") return /* @__PURE__ */ new TypeError(`'${method}' HTTP method is unsupported.`);\n};\nconst readBodyWithFastPath = (request, method, fromBuffer) => {\n\tif (request[bodyConsumedDirectlyKey]) return rejectBodyUnusable();\n\tconst methodName = request.method;\n\tif (methodName === \"GET\" || methodName === \"HEAD\") return request[getRequestCache]()[method]();\n\tconst methodValidationError = validateDirectReadMethod(methodName);\n\tif (methodValidationError) return Promise.reject(methodValidationError);\n\tif (request[requestCache]) {\n\t\tif (methodName !== \"TRACE\") return request[requestCache][method]();\n\t}\n\tconst alreadyUsedError = consumeBodyDirectOnce(request);\n\tif (alreadyUsedError) return alreadyUsedError;\n\tconst raw = readRawBodyIfAvailable(request);\n\tif (raw) {\n\t\tconst result = Promise.resolve(fromBuffer(raw, request));\n\t\trequest[bodyBufferKey] = void 0;\n\t\treturn result;\n\t}\n\treturn readBodyDirect(request).then((buf) => {\n\t\tconst result = fromBuffer(buf, request);\n\t\trequest[bodyBufferKey] = void 0;\n\t\treturn result;\n\t});\n};\nconst readRawBodyIfAvailable = (request) => {\n\tconst incoming = request[incomingKey];\n\tif (\"rawBody\" in incoming && incoming.rawBody instanceof Buffer) return incoming.rawBody;\n};\nconst readBodyDirect = (request) => {\n\tif (request[bodyBufferKey]) return Promise.resolve(request[bodyBufferKey]);\n\tif (request[bodyReadPromiseKey]) return request[bodyReadPromiseKey];\n\tconst incoming = request[incomingKey];\n\tif (node_stream.Readable.isDisturbed(incoming)) return rejectBodyUnusable();\n\tconst promise = new Promise((resolve, reject) => {\n\t\tconst chunks = [];\n\t\tlet settled = false;\n\t\tconst finish = (callback) => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tcallback();\n\t\t};\n\t\tconst onData = (chunk) => {\n\t\t\tchunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));\n\t\t};\n\t\tconst onEnd = () => {\n\t\t\tfinish(() => {\n\t\t\t\tconst buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks);\n\t\t\t\trequest[bodyBufferKey] = buffer;\n\t\t\t\tresolve(buffer);\n\t\t\t});\n\t\t};\n\t\tconst onError = (error) => {\n\t\t\tfinish(() => {\n\t\t\t\treject(error);\n\t\t\t});\n\t\t};\n\t\tconst onClose = () => {\n\t\t\tif (incoming.readableEnded) {\n\t\t\t\tonEnd();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfinish(() => {\n\t\t\t\tif (incoming.errored) {\n\t\t\t\t\treject(incoming.errored);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst reason = request[abortReasonKey];\n\t\t\t\tif (reason !== void 0) {\n\t\t\t\t\treject(reason instanceof Error ? reason : new Error(String(reason)));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treject(/* @__PURE__ */ new Error(\"Client connection prematurely closed.\"));\n\t\t\t});\n\t\t};\n\t\tconst cleanup = () => {\n\t\t\tincoming.off(\"data\", onData);\n\t\t\tincoming.off(\"end\", onEnd);\n\t\t\tincoming.off(\"error\", onError);\n\t\t\tincoming.off(\"close\", onClose);\n\t\t\trequest[bodyReadPromiseKey] = void 0;\n\t\t};\n\t\tincoming.on(\"data\", onData);\n\t\tincoming.on(\"end\", onEnd);\n\t\tincoming.on(\"error\", onError);\n\t\tincoming.on(\"close\", onClose);\n\t\tqueueMicrotask(() => {\n\t\t\tif (settled) return;\n\t\t\tif (incoming.readableEnded) onEnd();\n\t\t\telse if (incoming.errored) onError(incoming.errored);\n\t\t\telse if (incoming.destroyed) onClose();\n\t\t});\n\t});\n\trequest[bodyReadPromiseKey] = promise;\n\treturn promise;\n};\nconst requestPrototype = {\n\tget method() {\n\t\treturn this[methodKey];\n\t},\n\tget url() {\n\t\treturn this[urlKey];\n\t},\n\tget headers() {\n\t\treturn this[headersKey] ||= newHeadersFromIncoming(this[incomingKey]);\n\t},\n\t[abortRequest](reason) {\n\t\tif (this[abortReasonKey] === void 0) this[abortReasonKey] = reason;\n\t\tconst abortController = this[abortControllerKey];\n\t\tif (abortController && !abortController.signal.aborted) abortController.abort(reason);\n\t},\n\t[getAbortController]() {\n\t\tthis[abortControllerKey] ||= new AbortController();\n\t\tif (this[abortReasonKey] !== void 0 && !this[abortControllerKey].signal.aborted) this[abortControllerKey].abort(this[abortReasonKey]);\n\t\treturn this[abortControllerKey];\n\t},\n\t[getRequestCache]() {\n\t\tconst abortController = this[getAbortController]();\n\t\tif (this[requestCache]) return this[requestCache];\n\t\tconst method = this.method;\n\t\tif (this[bodyConsumedDirectlyKey] && !(method === \"GET\" || method === \"HEAD\")) {\n\t\t\tthis[bodyBufferKey] = void 0;\n\t\t\tconst init = {\n\t\t\t\tmethod: method === \"TRACE\" ? \"GET\" : method,\n\t\t\t\theaders: this.headers,\n\t\t\t\tsignal: abortController.signal\n\t\t\t};\n\t\t\tif (method !== \"TRACE\") {\n\t\t\t\tinit.body = new ReadableStream({ start(c) {\n\t\t\t\t\tc.close();\n\t\t\t\t} });\n\t\t\t\tinit.duplex = \"half\";\n\t\t\t}\n\t\t\tconst req = new Request$1(this[urlKey], init);\n\t\t\tif (method === \"TRACE\") Object.defineProperty(req, \"method\", { get() {\n\t\t\t\treturn \"TRACE\";\n\t\t\t} });\n\t\t\treturn this[requestCache] = req;\n\t\t}\n\t\treturn this[requestCache] = newRequestFromIncoming(this.method, this[urlKey], this.headers, this[incomingKey], abortController);\n\t},\n\tget body() {\n\t\tif (!this[bodyConsumedDirectlyKey]) return this[getRequestCache]().body;\n\t\tconst request = this[getRequestCache]();\n\t\tif (!this[bodyLockReaderKey] && request.body) this[bodyLockReaderKey] = request.body.getReader();\n\t\treturn request.body;\n\t},\n\tget bodyUsed() {\n\t\tif (this[bodyConsumedDirectlyKey]) return true;\n\t\tif (this[requestCache]) return this[requestCache].bodyUsed;\n\t\treturn false;\n\t}\n};\nObject.defineProperty(requestPrototype, \"signal\", { get() {\n\treturn this[getAbortController]().signal;\n} });\n[\n\t\"cache\",\n\t\"credentials\",\n\t\"destination\",\n\t\"integrity\",\n\t\"mode\",\n\t\"redirect\",\n\t\"referrer\",\n\t\"referrerPolicy\",\n\t\"keepalive\"\n].forEach((k) => {\n\tObject.defineProperty(requestPrototype, k, { get() {\n\t\treturn this[getRequestCache]()[k];\n\t} });\n});\n[\"clone\", \"formData\"].forEach((k) => {\n\tObject.defineProperty(requestPrototype, k, { value: function() {\n\t\tif (this[bodyConsumedDirectlyKey]) {\n\t\t\tif (k === \"clone\") throw newBodyUnusableError();\n\t\t\treturn rejectBodyUnusable();\n\t\t}\n\t\treturn this[getRequestCache]()[k]();\n\t} });\n});\nObject.defineProperty(requestPrototype, \"text\", { value: function() {\n\treturn readBodyWithFastPath(this, \"text\", (buf) => textDecoder.decode(buf));\n} });\nObject.defineProperty(requestPrototype, \"arrayBuffer\", { value: function() {\n\treturn readBodyWithFastPath(this, \"arrayBuffer\", (buf) => toArrayBuffer(buf));\n} });\nObject.defineProperty(requestPrototype, \"blob\", { value: function() {\n\treturn readBodyWithFastPath(this, \"blob\", (buf, request) => {\n\t\tconst type = contentType(request);\n\t\tconst init = type ? { headers: { \"content-type\": type } } : void 0;\n\t\treturn new Response(buf, init).blob();\n\t});\n} });\nObject.defineProperty(requestPrototype, \"json\", { value: function() {\n\tif (this[bodyConsumedDirectlyKey]) return rejectBodyUnusable();\n\treturn this.text().then(JSON.parse);\n} });\nObject.defineProperty(requestPrototype, Symbol.for(\"nodejs.util.inspect.custom\"), { value: function(depth, options, inspectFn) {\n\treturn `Request (lightweight) ${inspectFn({\n\t\tmethod: this.method,\n\t\turl: this.url,\n\t\theaders: this.headers,\n\t\tnativeRequest: this[requestCache]\n\t}, {\n\t\t...options,\n\t\tdepth: depth == null ? null : depth - 1\n\t})}`;\n} });\nObject.setPrototypeOf(requestPrototype, Request$1.prototype);\nconst newRequest = (incoming, defaultHostname) => {\n\tconst req = Object.create(requestPrototype);\n\treq[incomingKey] = incoming;\n\treq[methodKey] = normalizeIncomingMethod(incoming.method);\n\tconst incomingUrl = incoming.url || \"\";\n\tif (incomingUrl[0] !== \"/\" && (incomingUrl.startsWith(\"http://\") || incomingUrl.startsWith(\"https://\"))) {\n\t\tif (incoming instanceof node_http2.Http2ServerRequest) throw new RequestError(\"Absolute URL for :path is not allowed in HTTP/2\");\n\t\ttry {\n\t\t\treq[urlKey] = new URL(incomingUrl).href;\n\t\t} catch (e) {\n\t\t\tthrow new RequestError(\"Invalid absolute URL\", { cause: e });\n\t\t}\n\t\treturn req;\n\t}\n\tconst host = (incoming instanceof node_http2.Http2ServerRequest ? incoming.authority : incoming.headers.host) || defaultHostname;\n\tif (!host) throw new RequestError(\"Missing host header\");\n\tlet scheme;\n\tif (incoming instanceof node_http2.Http2ServerRequest) {\n\t\tscheme = incoming.scheme;\n\t\tif (!(scheme === \"http\" || scheme === \"https\")) throw new RequestError(\"Unsupported scheme\");\n\t} else scheme = incoming.socket && incoming.socket.encrypted ? \"https\" : \"http\";\n\ttry {\n\t\treq[urlKey] = buildUrl(scheme, host, incomingUrl);\n\t} catch (e) {\n\t\tif (e instanceof RequestError) throw e;\n\t\telse throw new RequestError(\"Invalid URL\", { cause: e });\n\t}\n\treturn req;\n};\n\n//#endregion\n//#region src/response.ts\nconst defaultContentType = \"text/plain; charset=UTF-8\";\nconst responseCache = Symbol(\"responseCache\");\nconst getResponseCache = Symbol(\"getResponseCache\");\nconst cacheKey = Symbol(\"cache\");\nconst GlobalResponse = global.Response;\nvar Response$1 = class Response$1 {\n\t#body;\n\t#init;\n\t[getResponseCache]() {\n\t\tconst cache = this[cacheKey];\n\t\tconst liveHeaders = cache && cache[2] instanceof Headers ? cache[2] : void 0;\n\t\tdelete this[cacheKey];\n\t\treturn this[responseCache] ||= new GlobalResponse(this.#body, liveHeaders ? {\n\t\t\tstatus: this.#init?.status,\n\t\t\tstatusText: this.#init?.statusText,\n\t\t\theaders: liveHeaders\n\t\t} : this.#init);\n\t}\n\tconstructor(body, init) {\n\t\tlet headers;\n\t\tthis.#body = body;\n\t\tif (init instanceof Response$1) {\n\t\t\tconst cachedGlobalResponse = init[responseCache];\n\t\t\tif (cachedGlobalResponse) {\n\t\t\t\tthis.#init = cachedGlobalResponse;\n\t\t\t\tthis[getResponseCache]();\n\t\t\t\treturn;\n\t\t\t} else {\n\t\t\t\tthis.#init = init.#init;\n\t\t\t\theaders = new Headers(init.headers);\n\t\t\t}\n\t\t} else this.#init = init;\n\t\tif (body == null || typeof body === \"string\" || typeof body?.getReader !== \"undefined\" || body instanceof Blob || body instanceof Uint8Array) this[cacheKey] = [\n\t\t\tinit?.status || 200,\n\t\t\tbody ?? null,\n\t\t\theaders || init?.headers\n\t\t];\n\t}\n\tget headers() {\n\t\tconst cache = this[cacheKey];\n\t\tif (cache) {\n\t\t\tif (!(cache[2] instanceof Headers)) cache[2] = new Headers(cache[2] || (cache[1] === null ? void 0 : { \"content-type\": defaultContentType }));\n\t\t\treturn cache[2];\n\t\t}\n\t\treturn this[getResponseCache]().headers;\n\t}\n\tget status() {\n\t\treturn this[cacheKey]?.[0] ?? this[getResponseCache]().status;\n\t}\n\tget ok() {\n\t\tconst status = this.status;\n\t\treturn status >= 200 && status < 300;\n\t}\n};\n[\n\t\"body\",\n\t\"bodyUsed\",\n\t\"redirected\",\n\t\"statusText\",\n\t\"trailers\",\n\t\"type\",\n\t\"url\"\n].forEach((k) => {\n\tObject.defineProperty(Response$1.prototype, k, { get() {\n\t\treturn this[getResponseCache]()[k];\n\t} });\n});\n[\n\t\"arrayBuffer\",\n\t\"blob\",\n\t\"clone\",\n\t\"formData\",\n\t\"json\",\n\t\"text\"\n].forEach((k) => {\n\tObject.defineProperty(Response$1.prototype, k, { value: function() {\n\t\treturn this[getResponseCache]()[k]();\n\t} });\n});\nObject.defineProperty(Response$1.prototype, Symbol.for(\"nodejs.util.inspect.custom\"), { value: function(depth, options, inspectFn) {\n\treturn `Response (lightweight) ${inspectFn({\n\t\tstatus: this.status,\n\t\theaders: this.headers,\n\t\tok: this.ok,\n\t\tnativeResponse: this[responseCache]\n\t}, {\n\t\t...options,\n\t\tdepth: depth == null ? null : depth - 1\n\t})}`;\n} });\nObject.setPrototypeOf(Response$1, GlobalResponse);\nObject.setPrototypeOf(Response$1.prototype, GlobalResponse.prototype);\nconst validRedirectUrl = /^https?:\\/\\/[!#-;=?-[\\]_a-z~A-Z]+$/;\nconst parseRedirectUrl = (url) => {\n\tif (url instanceof URL) return url.href;\n\tif (validRedirectUrl.test(url)) return url;\n\treturn new URL(url).href;\n};\nconst validRedirectStatuses = new Set([\n\t301,\n\t302,\n\t303,\n\t307,\n\t308\n]);\nObject.defineProperty(Response$1, \"redirect\", {\n\tvalue: function redirect(url, status = 302) {\n\t\tif (!validRedirectStatuses.has(status)) throw new RangeError(\"Invalid status code\");\n\t\treturn new Response$1(null, {\n\t\t\tstatus,\n\t\t\theaders: { location: parseRedirectUrl(url) }\n\t\t});\n\t},\n\twritable: true,\n\tconfigurable: true\n});\nObject.defineProperty(Response$1, \"json\", {\n\tvalue: function json(data, init) {\n\t\tconst body = JSON.stringify(data);\n\t\tif (body === void 0) throw new TypeError(\"The data is not JSON serializable\");\n\t\tconst initHeaders = init?.headers;\n\t\tlet headers;\n\t\tif (initHeaders) {\n\t\t\theaders = new Headers(initHeaders);\n\t\t\tif (!headers.has(\"content-type\")) headers.set(\"content-type\", \"application/json\");\n\t\t} else headers = { \"content-type\": \"application/json\" };\n\t\treturn new Response$1(body, {\n\t\t\tstatus: init?.status ?? 200,\n\t\t\tstatusText: init?.statusText,\n\t\t\theaders\n\t\t});\n\t},\n\twritable: true,\n\tconfigurable: true\n});\n\n//#endregion\n//#region src/utils.ts\nasync function readWithoutBlocking(readPromise) {\n\treturn Promise.race([readPromise, Promise.resolve().then(() => Promise.resolve(void 0))]);\n}\nfunction writeFromReadableStreamDefaultReader(reader, writable, currentReadPromise) {\n\tconst cancel = (error) => {\n\t\treader.cancel(error).catch(() => {});\n\t};\n\twritable.on(\"close\", cancel);\n\twritable.on(\"error\", cancel);\n\t(currentReadPromise ?? reader.read()).then(flow, handleStreamError);\n\treturn reader.closed.finally(() => {\n\t\twritable.off(\"close\", cancel);\n\t\twritable.off(\"error\", cancel);\n\t});\n\tfunction handleStreamError(error) {\n\t\tif (error) writable.destroy(error);\n\t}\n\tfunction onDrain() {\n\t\treader.read().then(flow, handleStreamError);\n\t}\n\tfunction flow({ done, value }) {\n\t\ttry {\n\t\t\tif (done) writable.end();\n\t\t\telse if (!writable.write(value)) writable.once(\"drain\", onDrain);\n\t\t\telse return reader.read().then(flow, handleStreamError);\n\t\t} catch (e) {\n\t\t\thandleStreamError(e);\n\t\t}\n\t}\n}\nfunction writeFromReadableStream(stream, writable) {\n\tif (stream.locked) throw new TypeError(\"ReadableStream is locked.\");\n\telse if (writable.destroyed) return;\n\treturn writeFromReadableStreamDefaultReader(stream.getReader(), writable);\n}\nconst buildOutgoingHttpHeaders = (headers, defaultContentType) => {\n\tconst res = {};\n\tif (!(headers instanceof Headers)) headers = new Headers(headers ?? void 0);\n\tif (headers.has(\"set-cookie\")) {\n\t\tconst cookies = [];\n\t\tfor (const [k, v] of headers) if (k === \"set-cookie\") cookies.push(v);\n\t\telse res[k] = v;\n\t\tif (cookies.length > 0) res[\"set-cookie\"] = cookies;\n\t} else for (const [k, v] of headers) res[k] = v;\n\tif (defaultContentType) res[\"content-type\"] ??= defaultContentType;\n\treturn res;\n};\n\n//#endregion\n//#region src/listener.ts\nconst outgoingEnded = Symbol(\"outgoingEnded\");\nconst incomingDraining = Symbol(\"incomingDraining\");\nconst DRAIN_TIMEOUT_MS = 500;\nconst MAX_DRAIN_BYTES = 64 * 1024 * 1024;\nconst drainIncoming = (incoming) => {\n\tconst incomingWithDrainState = incoming;\n\tif (incoming.destroyed || incomingWithDrainState[incomingDraining]) return;\n\tincomingWithDrainState[incomingDraining] = true;\n\tif (incoming instanceof node_http2.Http2ServerRequest) {\n\t\ttry {\n\t\t\tincoming.stream?.close?.(node_http2.constants.NGHTTP2_NO_ERROR);\n\t\t} catch {}\n\t\treturn;\n\t}\n\tlet bytesRead = 0;\n\tconst cleanup = () => {\n\t\tclearTimeout(timer);\n\t\tincoming.off(\"data\", onData);\n\t\tincoming.off(\"end\", cleanup);\n\t\tincoming.off(\"error\", cleanup);\n\t};\n\tconst forceClose = () => {\n\t\tcleanup();\n\t\tconst socket = incoming.socket;\n\t\tif (socket && !socket.destroyed) socket.destroySoon();\n\t};\n\tconst timer = setTimeout(forceClose, DRAIN_TIMEOUT_MS);\n\ttimer.unref?.();\n\tconst onData = (chunk) => {\n\t\tbytesRead += chunk.length;\n\t\tif (bytesRead > MAX_DRAIN_BYTES) forceClose();\n\t};\n\tincoming.on(\"data\", onData);\n\tincoming.on(\"end\", cleanup);\n\tincoming.on(\"error\", cleanup);\n\tincoming.resume();\n};\nconst makeCloseHandler = (req, incoming, outgoing, needsBodyCleanup) => () => {\n\tif (incoming.errored) req[abortRequest](incoming.errored.toString());\n\telse if (!outgoing.writableFinished) req[abortRequest](\"Client connection prematurely closed.\");\n\tif (needsBodyCleanup && !incoming.readableEnded) setTimeout(() => {\n\t\tif (!incoming.readableEnded) setTimeout(() => {\n\t\t\tdrainIncoming(incoming);\n\t\t});\n\t});\n};\nconst isImmediateCacheableResponse = (res) => {\n\tif (!(cacheKey in res)) return false;\n\tconst body = res[cacheKey][1];\n\treturn body === null || typeof body === \"string\" || body instanceof Uint8Array;\n};\nconst handleRequestError = () => new Response(null, { status: 400 });\nconst handleFetchError = (e) => new Response(null, { status: e instanceof Error && (e.name === \"TimeoutError\" || e.constructor.name === \"TimeoutError\") ? 504 : 500 });\nconst handleResponseError = (e, outgoing) => {\n\tconst err = e instanceof Error ? e : new Error(\"unknown error\", { cause: e });\n\tif (err.code === \"ERR_STREAM_PREMATURE_CLOSE\") console.info(\"The user aborted a request.\");\n\telse {\n\t\tconsole.error(e);\n\t\tif (!outgoing.headersSent) outgoing.writeHead(500, { \"Content-Type\": \"text/plain\" });\n\t\toutgoing.end(`Error: ${err.message}`);\n\t\toutgoing.destroy(err);\n\t}\n};\nconst flushHeaders = (outgoing) => {\n\tif (\"flushHeaders\" in outgoing && outgoing.writable) outgoing.flushHeaders();\n};\nconst responseViaCache = async (res, outgoing) => {\n\tlet [status, body, header] = res[cacheKey];\n\tif (!header) {\n\t\tif (body === null) {\n\t\t\toutgoing.writeHead(status);\n\t\t\toutgoing.end();\n\t\t} else if (typeof body === \"string\") {\n\t\t\toutgoing.writeHead(status, {\n\t\t\t\t\"Content-Type\": defaultContentType,\n\t\t\t\t\"Content-Length\": Buffer.byteLength(body)\n\t\t\t});\n\t\t\toutgoing.end(body);\n\t\t} else if (body instanceof Uint8Array) {\n\t\t\toutgoing.writeHead(status, {\n\t\t\t\t\"Content-Type\": defaultContentType,\n\t\t\t\t\"Content-Length\": body.byteLength\n\t\t\t});\n\t\t\toutgoing.end(body);\n\t\t} else if (body instanceof Blob) {\n\t\t\toutgoing.writeHead(status, {\n\t\t\t\t\"Content-Type\": defaultContentType,\n\t\t\t\t\"Content-Length\": body.size\n\t\t\t});\n\t\t\toutgoing.end(new Uint8Array(await body.arrayBuffer()));\n\t\t} else {\n\t\t\toutgoing.writeHead(status, { \"Content-Type\": defaultContentType });\n\t\t\tflushHeaders(outgoing);\n\t\t\tawait writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));\n\t\t}\n\t\toutgoing[outgoingEnded]?.();\n\t\treturn;\n\t}\n\tlet hasContentLength = false;\n\tif (header instanceof Headers) {\n\t\thasContentLength = header.has(\"content-length\");\n\t\theader = buildOutgoingHttpHeaders(header, body === null ? void 0 : defaultContentType);\n\t} else if (Array.isArray(header)) {\n\t\tconst headerObj = new Headers(header);\n\t\thasContentLength = headerObj.has(\"content-length\");\n\t\theader = buildOutgoingHttpHeaders(headerObj, body === null ? void 0 : defaultContentType);\n\t} else for (const key in header) if (key.length === 14 && key.toLowerCase() === \"content-length\") {\n\t\thasContentLength = true;\n\t\tbreak;\n\t}\n\tif (!hasContentLength) {\n\t\tif (typeof body === \"string\") header[\"Content-Length\"] = Buffer.byteLength(body);\n\t\telse if (body instanceof Uint8Array) header[\"Content-Length\"] = body.byteLength;\n\t\telse if (body instanceof Blob) header[\"Content-Length\"] = body.size;\n\t}\n\toutgoing.writeHead(status, header);\n\tif (body == null) outgoing.end();\n\telse if (typeof body === \"string\" || body instanceof Uint8Array) outgoing.end(body);\n\telse if (body instanceof Blob) outgoing.end(new Uint8Array(await body.arrayBuffer()));\n\telse {\n\t\tflushHeaders(outgoing);\n\t\tawait writeFromReadableStream(body, outgoing)?.catch((e) => handleResponseError(e, outgoing));\n\t}\n\toutgoing[outgoingEnded]?.();\n};\nconst isPromise = (res) => typeof res.then === \"function\";\nconst responseViaResponseObject = async (res, outgoing, options = {}) => {\n\tif (isPromise(res)) if (options.errorHandler) try {\n\t\tres = await res;\n\t} catch (err) {\n\t\tconst errRes = await options.errorHandler(err);\n\t\tif (!errRes) return;\n\t\tres = errRes;\n\t}\n\telse res = await res.catch(handleFetchError);\n\tif (cacheKey in res) return responseViaCache(res, outgoing);\n\tconst resHeaderRecord = buildOutgoingHttpHeaders(res.headers, res.body === null ? void 0 : defaultContentType);\n\tif (res.body) {\n\t\tconst reader = res.body.getReader();\n\t\tconst values = [];\n\t\tlet done = false;\n\t\tlet currentReadPromise = void 0;\n\t\tif (resHeaderRecord[\"transfer-encoding\"] !== \"chunked\") {\n\t\t\tlet maxReadCount = 2;\n\t\t\tfor (let i = 0; i < maxReadCount; i++) {\n\t\t\t\tcurrentReadPromise ||= reader.read();\n\t\t\t\tconst chunk = await readWithoutBlocking(currentReadPromise).catch((e) => {\n\t\t\t\t\tconsole.error(e);\n\t\t\t\t\tdone = true;\n\t\t\t\t});\n\t\t\t\tif (!chunk) {\n\t\t\t\t\tif (i === 1) {\n\t\t\t\t\t\tawait new Promise((resolve) => setTimeout(resolve));\n\t\t\t\t\t\tmaxReadCount = 3;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcurrentReadPromise = void 0;\n\t\t\t\tif (chunk.value) values.push(chunk.value);\n\t\t\t\tif (chunk.done) {\n\t\t\t\t\tdone = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (done && !(\"content-length\" in resHeaderRecord)) resHeaderRecord[\"content-length\"] = values.reduce((acc, value) => acc + value.length, 0);\n\t\t}\n\t\toutgoing.writeHead(res.status, resHeaderRecord);\n\t\tvalues.forEach((value) => {\n\t\t\toutgoing.write(value);\n\t\t});\n\t\tif (done) outgoing.end();\n\t\telse {\n\t\t\tif (values.length === 0) flushHeaders(outgoing);\n\t\t\tawait writeFromReadableStreamDefaultReader(reader, outgoing, currentReadPromise);\n\t\t}\n\t} else if (resHeaderRecord[require_constants.X_ALREADY_SENT]) {} else {\n\t\toutgoing.writeHead(res.status, resHeaderRecord);\n\t\toutgoing.end();\n\t}\n\toutgoing[outgoingEnded]?.();\n};\nconst getRequestListener = (fetchCallback, options = {}) => {\n\tconst autoCleanupIncoming = options.autoCleanupIncoming ?? true;\n\tif (options.overrideGlobalObjects !== false && global.Request !== Request$1) {\n\t\tObject.defineProperty(global, \"Request\", { value: Request$1 });\n\t\tObject.defineProperty(global, \"Response\", { value: Response$1 });\n\t}\n\treturn async (incoming, outgoing) => {\n\t\tlet res, req;\n\t\tlet needsBodyCleanup = false;\n\t\tlet closeHandlerAttached = false;\n\t\tconst ensureCloseHandler = () => {\n\t\t\tif (!req || closeHandlerAttached) return;\n\t\t\tcloseHandlerAttached = true;\n\t\t\toutgoing.on(\"close\", makeCloseHandler(req, incoming, outgoing, needsBodyCleanup));\n\t\t};\n\t\ttry {\n\t\t\treq = newRequest(incoming, options.hostname);\n\t\t\tneedsBodyCleanup = autoCleanupIncoming && !(incoming.method === \"GET\" || incoming.method === \"HEAD\");\n\t\t\tif (needsBodyCleanup) {\n\t\t\t\tincoming[wrapBodyStream] = true;\n\t\t\t\tif (incoming instanceof node_http2.Http2ServerRequest) outgoing[outgoingEnded] = () => {\n\t\t\t\t\tif (!incoming.readableEnded) setTimeout(() => {\n\t\t\t\t\t\tif (!incoming.readableEnded) setTimeout(() => {\n\t\t\t\t\t\t\tincoming.destroy();\n\t\t\t\t\t\t\toutgoing.destroy();\n\t\t\t\t\t\t});\n\t\t\t\t\t});\n\t\t\t\t};\n\t\t\t}\n\t\t\tres = fetchCallback(req, {\n\t\t\t\tincoming,\n\t\t\t\toutgoing\n\t\t\t});\n\t\t\tif (!isPromise(res) && isImmediateCacheableResponse(res)) {\n\t\t\t\tif (needsBodyCleanup && !incoming.readableEnded) outgoing.once(\"finish\", () => {\n\t\t\t\t\tif (!incoming.readableEnded) drainIncoming(incoming);\n\t\t\t\t});\n\t\t\t\treturn responseViaCache(res, outgoing);\n\t\t\t}\n\t\t\tensureCloseHandler();\n\t\t} catch (e) {\n\t\t\tif (!res) if (options.errorHandler) {\n\t\t\t\tensureCloseHandler();\n\t\t\t\tres = await options.errorHandler(req ? e : toRequestError(e));\n\t\t\t\tif (!res) return;\n\t\t\t} else if (!req) res = handleRequestError();\n\t\t\telse res = handleFetchError(e);\n\t\t\telse return handleResponseError(e, outgoing);\n\t\t}\n\t\ttry {\n\t\t\treturn await responseViaResponseObject(res, outgoing, options);\n\t\t} catch (e) {\n\t\t\treturn handleResponseError(e, outgoing);\n\t\t}\n\t};\n};\n\n//#endregion\n//#region src/websocket.ts\n/**\n* @link https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent\n*/\nconst CloseEvent = globalThis.CloseEvent ?? class extends Event {\n\t#eventInitDict;\n\tconstructor(type, eventInitDict = {}) {\n\t\tsuper(type, eventInitDict);\n\t\tthis.#eventInitDict = eventInitDict;\n\t}\n\tget wasClean() {\n\t\treturn this.#eventInitDict.wasClean ?? false;\n\t}\n\tget code() {\n\t\treturn this.#eventInitDict.code ?? 0;\n\t}\n\tget reason() {\n\t\treturn this.#eventInitDict.reason ?? \"\";\n\t}\n};\nconst generateConnectionSymbol = () => Symbol(\"connection\");\nconst CONNECTION_SYMBOL_KEY = Symbol(\"CONNECTION_SYMBOL_KEY\");\nconst WAIT_FOR_WEBSOCKET_SYMBOL = Symbol(\"WAIT_FOR_WEBSOCKET_SYMBOL\");\nconst responseHeadersToSkip = new Set([\n\t\"connection\",\n\t\"content-length\",\n\t\"keep-alive\",\n\t\"proxy-authenticate\",\n\t\"proxy-authorization\",\n\t\"te\",\n\t\"trailer\",\n\t\"transfer-encoding\",\n\t\"upgrade\",\n\t\"sec-websocket-accept\",\n\t\"sec-websocket-extensions\",\n\t\"sec-websocket-protocol\"\n]);\nconst appendResponseHeaders = (headers, responseHeaders) => {\n\tif (!responseHeaders) return;\n\tresponseHeaders.forEach((value, key) => {\n\t\tif (responseHeadersToSkip.has(key.toLowerCase())) return;\n\t\theaders.push(`${key}: ${value}`);\n\t});\n};\nconst rejectUpgradeRequest = (socket, status, responseHeaders) => {\n\tconst responseLines = [\"Connection: close\", \"Content-Length: 0\"];\n\tappendResponseHeaders(responseLines, responseHeaders);\n\tsocket.end(`HTTP/1.1 ${status.toString()} ${node_http.STATUS_CODES[status] ?? \"\"}\\r\\n${responseLines.join(\"\\r\\n\")}\\r\\n\\r\n`);\n};\nconst createUpgradeRequest = (request) => {\n\tconst protocol = request.socket.encrypted ? \"https\" : \"http\";\n\tconst url = new URL(request.url ?? \"/\", `${protocol}://${request.headers.host ?? \"localhost\"}`);\n\tconst headers = new Headers();\n\tfor (const key in request.headers) {\n\t\tconst value = request.headers[key];\n\t\tif (!value) continue;\n\t\theaders.append(key, Array.isArray(value) ? value[0] : value);\n\t}\n\treturn new Request(url, { headers });\n};\nconst setupWebSocket = (options) => {\n\tconst { server, fetchCallback, wss } = options;\n\tconst waiterMap = /* @__PURE__ */ new Map();\n\twss.on(\"connection\", (ws, request) => {\n\t\tconst waiter = waiterMap.get(request);\n\t\tif (waiter) {\n\t\t\twaiter.resolve(ws);\n\t\t\twaiterMap.delete(request);\n\t\t}\n\t});\n\tconst waitForWebSocket = (request, connectionSymbol) => {\n\t\treturn new Promise((resolve) => {\n\t\t\twaiterMap.set(request, {\n\t\t\t\tresolve,\n\t\t\t\tconnectionSymbol\n\t\t\t});\n\t\t});\n\t};\n\tserver.on(\"upgrade\", async (request, socket, head) => {\n\t\tif (request.headers.upgrade?.toLowerCase() !== \"websocket\") return;\n\t\tconst env = {\n\t\t\tincoming: request,\n\t\t\toutgoing: void 0,\n\t\t\twss,\n\t\t\t[WAIT_FOR_WEBSOCKET_SYMBOL]: waitForWebSocket\n\t\t};\n\t\tlet status = 400;\n\t\tlet responseHeaders;\n\t\ttry {\n\t\t\tconst response = await fetchCallback(createUpgradeRequest(request), env);\n\t\t\tif (response instanceof Response) {\n\t\t\t\tstatus = response.status;\n\t\t\t\tresponseHeaders = response.headers;\n\t\t\t}\n\t\t} catch {\n\t\t\tif (server.listenerCount(\"upgrade\") === 1) rejectUpgradeRequest(socket, 500);\n\t\t\treturn;\n\t\t}\n\t\tconst waiter = waiterMap.get(request);\n\t\tif (!waiter || waiter.connectionSymbol !== env[CONNECTION_SYMBOL_KEY]) {\n\t\t\twaiterMap.delete(request);\n\t\t\tif (server.listenerCount(\"upgrade\") === 1) rejectUpgradeRequest(socket, status, responseHeaders);\n\t\t\treturn;\n\t\t}\n\t\tconst addResponseHeaders = (headers) => {\n\t\t\tappendResponseHeaders(headers, responseHeaders);\n\t\t};\n\t\twss.on(\"headers\", addResponseHeaders);\n\t\ttry {\n\t\t\twss.handleUpgrade(request, socket, head, (ws) => {\n\t\t\t\twss.emit(\"connection\", ws, request);\n\t\t\t});\n\t\t} finally {\n\t\t\twss.off(\"headers\", addResponseHeaders);\n\t\t}\n\t});\n\tserver.on(\"close\", () => {\n\t\twss.close();\n\t});\n};\nconst upgradeWebSocket = (0, hono_ws.defineWebSocketHelper)(async (c, events, options) => {\n\tif (c.req.header(\"upgrade\")?.toLowerCase() !== \"websocket\") return;\n\tconst env = c.env;\n\tconst waitForWebSocket = env[WAIT_FOR_WEBSOCKET_SYMBOL];\n\tif (!waitForWebSocket || !env.incoming) return new Response(null, { status: 500 });\n\tconst connectionSymbol = generateConnectionSymbol();\n\tenv[CONNECTION_SYMBOL_KEY] = connectionSymbol;\n\t(async () => {\n\t\tconst ws = await waitForWebSocket(env.incoming, connectionSymbol);\n\t\tconst messagesReceivedInStarting = [];\n\t\tconst bufferMessage = (data, isBinary) => {\n\t\t\tmessagesReceivedInStarting.push([data, isBinary]);\n\t\t};\n\t\tws.on(\"message\", bufferMessage);\n\t\tconst ctx = {\n\t\t\tbinaryType: \"arraybuffer\",\n\t\t\tclose(code, reason) {\n\t\t\t\tws.close(code, reason);\n\t\t\t},\n\t\t\tprotocol: ws.protocol,\n\t\t\traw: ws,\n\t\t\tget readyState() {\n\t\t\t\treturn ws.readyState;\n\t\t\t},\n\t\t\tsend(source, opts) {\n\t\t\t\tws.send(source, { compress: opts?.compress });\n\t\t\t},\n\t\t\turl: new URL(c.req.url)\n\t\t};\n\t\ttry {\n\t\t\tevents?.onOpen?.(new Event(\"open\"), ctx);\n\t\t} catch (e) {\n\t\t\t(options?.onError ?? console.error)(e);\n\t\t}\n\t\tconst handleMessage = (data, isBinary) => {\n\t\t\tconst datas = Array.isArray(data) ? data : [data];\n\t\t\tfor (const data of datas) try {\n\t\t\t\tevents?.onMessage?.(new MessageEvent(\"message\", { data: isBinary ? data instanceof ArrayBuffer ? data : data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength) : typeof data === \"string\" ? data : Buffer.from(data).toString(\"utf-8\") }), ctx);\n\t\t\t} catch (e) {\n\t\t\t\t(options?.onError ?? console.error)(e);\n\t\t\t}\n\t\t};\n\t\tws.off(\"message\", bufferMessage);\n\t\tfor (const message of messagesReceivedInStarting) handleMessage(...message);\n\t\tws.on(\"message\", (data, isBinary) => {\n\t\t\thandleMessage(data, isBinary);\n\t\t});\n\t\tws.on(\"close\", (code, reason) => {\n\t\t\ttry {\n\t\t\t\tevents?.onClose?.(new CloseEvent(\"close\", {\n\t\t\t\t\tcode,\n\t\t\t\t\treason: reason.toString()\n\t\t\t\t}), ctx);\n\t\t\t} catch (e) {\n\t\t\t\t(options?.onError ?? console.error)(e);\n\t\t\t}\n\t\t});\n\t\tws.on(\"error\", (error) => {\n\t\t\ttry {\n\t\t\t\tevents?.onError?.(new ErrorEvent(\"error\", { error }), ctx);\n\t\t\t} catch (e) {\n\t\t\t\t(options?.onError ?? console.error)(e);\n\t\t\t}\n\t\t});\n\t})();\n\treturn new Response();\n});\n\n//#endregion\n//#region src/server.ts\nconst createAdaptorServer = (options) => {\n\tconst fetchCallback = options.fetch;\n\tconst requestListener = getRequestListener(fetchCallback, {\n\t\thostname: options.hostname,\n\t\toverrideGlobalObjects: options.overrideGlobalObjects,\n\t\tautoCleanupIncoming: options.autoCleanupIncoming\n\t});\n\tconst server = (options.createServer || node_http.createServer)(options.serverOptions || {}, requestListener);\n\tif (options.websocket && options.websocket.server) {\n\t\tif (options.websocket.server.options.noServer !== true) throw new Error(\"WebSocket server must be created with { noServer: true } option\");\n\t\tsetupWebSocket({\n\t\t\tserver,\n\t\t\tfetchCallback,\n\t\t\twss: options.websocket.server\n\t\t});\n\t}\n\treturn server;\n};\nconst serve = (options, listeningListener) => {\n\tconst server = createAdaptorServer(options);\n\tserver.listen(options?.port ?? 3e3, options.hostname, () => {\n\t\tconst serverInfo = server.address();\n\t\tlisteningListener && listeningListener(serverInfo);\n\t});\n\treturn server;\n};\n\n//#endregion\nexports.RequestError = RequestError;\nexports.createAdaptorServer = createAdaptorServer;\nexports.getRequestListener = getRequestListener;\nexports.serve = serve;\nexports.upgradeWebSocket = upgradeWebSocket;","import { randomUUID } from 'node:crypto'\nimport { type GitHubChannel, createGitHubChannel } from '@flue/github'\nimport { defineTool, dispatch } from '@flue/runtime'\nimport { Octokit } from 'octokit'\nimport * as v from 'valibot'\nimport mention from '../agents/mention'\n\n/**\n * GitHub channel ā the webhook (server) deployment mode. Lets people summon\n * Shippie by commenting `/shippie ...` on an issue or pull request. Verified\n * deliveries are dispatched to the `mention` agent, which replies via Octokit.\n *\n * Served at `POST /channels/github/webhook` on the built server. Requires\n * GITHUB_WEBHOOK_SECRET (verify inbound) and GITHUB_TOKEN (outbound comments).\n * This is separate from the one-shot CI review (action.yml / `flue run review`).\n */\n\nconst MENTION = '/shippie'\n\nexport interface IssueRef {\n owner: string\n repo: string\n issueNumber: number\n}\n\nexport const client = new Octokit({ auth: process.env.GITHUB_TOKEN })\n\n// Flue bundles and loads every discovered module (including this channel) when\n// the server starts or a workflow runs, so this must NOT throw at import time\n// when the webhook secret is absent (e.g. during one-shot `flue run review`).\n// Fall back to an UNGUESSABLE per-process random secret so the module loads\n// inertly AND signature verification fails closed (all deliveries 401) until a\n// real GITHUB_WEBHOOK_SECRET is configured. A constant fallback would let an\n// attacker forge webhook deliveries when the secret is unset.\nconst WEBHOOK_SECRET =\n process.env.GITHUB_WEBHOOK_SECRET || `shippie-unconfigured-${randomUUID()}`\n\nexport const channel: GitHubChannel = createGitHubChannel({\n webhookSecret: WEBHOOK_SECRET,\n\n async webhook({ delivery }) {\n if (delivery.name === 'issue_comment' && delivery.payload.action === 'created') {\n const { repository, issue, comment, sender } = delivery.payload\n if (sender?.type === 'Bot') return undefined\n if (!comment.body?.toLowerCase().includes(MENTION)) return undefined\n\n const ref: IssueRef = {\n owner: repository.owner.login,\n repo: repository.name,\n issueNumber: issue.number,\n }\n await dispatch(mention, {\n id: channel.conversationKey(ref),\n input: {\n type: 'github.mention',\n isPullRequest: Boolean(issue.pull_request),\n title: issue.title,\n author: sender?.login,\n request: comment.body,\n },\n })\n return undefined\n }\n\n if (\n delivery.name === 'pull_request_review_comment' &&\n delivery.payload.action === 'created'\n ) {\n const { repository, pull_request, comment, sender } = delivery.payload\n if (sender?.type === 'Bot') return undefined\n if (!comment.body?.toLowerCase().includes(MENTION)) return undefined\n\n const ref: IssueRef = {\n owner: repository.owner.login,\n repo: repository.name,\n issueNumber: pull_request.number,\n }\n await dispatch(mention, {\n id: channel.conversationKey(ref),\n input: {\n type: 'github.mention',\n isPullRequest: true,\n title: pull_request.title,\n author: sender?.login,\n request: comment.body,\n path: comment.path,\n line: comment.line ?? null,\n },\n })\n return undefined\n }\n\n return undefined\n },\n})\n\n/** Tool: post a reply comment on the issue/PR that summoned Shippie. */\nexport const commentOnIssue = (ref: IssueRef) =>\n defineTool({\n name: 'comment_on_github_issue',\n description:\n 'Post your reply as a comment on the GitHub issue or pull request that mentioned you.',\n parameters: v.object({\n body: v.pipe(\n v.string(),\n v.minLength(1),\n v.description('The markdown comment to post.')\n ),\n }),\n async execute({ body }) {\n const res = await client.rest.issues.createComment({\n owner: ref.owner,\n repo: ref.repo,\n issue_number: ref.issueNumber,\n body,\n })\n return `Comment posted: ${res.data.html_url}`\n },\n })\n\n/** Tool: fetch the unified diff of the pull request that summoned Shippie. */\nexport const getPullRequestDiff = (ref: IssueRef) =>\n defineTool({\n name: 'get_pull_request_diff',\n description:\n 'Fetch the unified diff of the pull request that mentioned you. Call this before reviewing a PR.',\n parameters: v.object({}),\n async execute() {\n const res = await client.rest.pulls.get({\n owner: ref.owner,\n repo: ref.repo,\n pull_number: ref.issueNumber,\n mediaType: { format: 'diff' },\n })\n // With the `diff` media type, GitHub returns the raw diff as a string.\n return typeof res.data === 'string' ? res.data : JSON.stringify(res.data)\n },\n })\n","import { createAgent } from '@flue/runtime'\nimport { channel, commentOnIssue, getPullRequestDiff } from '../channels/github'\n\n/**\n * The `/shippie` mention agent (webhook/channel mode). Dispatched by the GitHub\n * channel when someone comments `/shippie ...` on an issue or PR. It reads the\n * request, optionally fetches the PR diff, and replies with a single comment.\n *\n * Runs on a deployed Flue server (not a repo checkout), so it works through the\n * GitHub API tools rather than a `local()` sandbox.\n */\nexport default createAgent(({ id }) => {\n const ref = channel.parseConversationKey(id)\n\n return {\n model: process.env.SHIPPIE_MODEL ?? 'anthropic/claude-sonnet-4-6',\n instructions: `You are Shippie, an automated code-review agent summoned by a \"/shippie\" command on ${ref.owner}/${ref.repo} #${ref.issueNumber}.\n\nThe incoming message describes the user's request. Decide what they want:\n- If it is a pull request and they ask you to review it (e.g. \"/shippie review\"), call get_pull_request_diff, review the changed code for bugs, exposed secrets, missing tests, and risky changes, then write a concise review.\n- For any other question, answer it helpfully and concisely based on the request and what you can fetch.\n\nRules:\n- Be brief and specific. Do not restate the whole diff back to the user.\n- Only raise issues you are confident about.\n- ALWAYS finish by calling comment_on_github_issue exactly once with your reply (markdown).`,\n tools: [commentOnIssue(ref), getPullRequestDiff(ref)],\n }\n})\n","/**\n * Constants for formatting comments\n */\nexport const FORMATTING = {\n SUMMARY_TITLE: '## General Summary š“āā ļø',\n SEPARATOR: '\\n\\n---\\n\\n',\n SIGN_OFF: '### Review powered by [Shippie š¢](https://github.com/mattzcarey/shippie)',\n CTA: `<details>\n<summary>š Good review?</summary>\n\n---\n\n**Help us improve!** Your feedback and support make Shippie better for everyone.\n\nā **Quick win?** [Star the repo](https://github.com/mattzcarey/shippie) if you find it useful \nš” **Have ideas?** [Open a discussion](https://github.com/mattzcarey/shippie/discussions)\nš ļø **Wanna chat about agents?** [Send me a DM](https://x.com/mattzcarey)\n\n\n---\n\n*Sponsor the project* to preview features and influence the roadmap\n\nš [YOUR COMPANY HERE](https://sustain.dev/sponsor/shippie) š\n\n</details>`,\n TOOL_CALLS_TITLE: 'š ļø Tool Calls',\n TOKEN_USAGE_TITLE: 'š Token Usage',\n}\n\n/**\n * Formats a thread comment with title, content, and sign-off\n */\nexport const formatSummary = (comment: string): string => {\n return `${FORMATTING.SUMMARY_TITLE}\\n\\n${comment}${FORMATTING.SEPARATOR}${FORMATTING.SIGN_OFF}\\n\\n${FORMATTING.CTA}`\n}\n","import { appendFile, mkdir, writeFile } from 'node:fs/promises'\nimport { isAbsolute, join, relative } from 'node:path'\nimport { Octokit } from 'octokit'\nimport { FORMATTING, formatSummary } from '../common/formatting/summary'\nimport type