@openclaw/crabline 0.1.17 → 0.1.18
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/README.md +8 -0
- package/dist/src/openclaw/private-file.js +71 -24
- package/dist/src/openclaw/private-file.js.map +1 -1
- package/dist/src/platform/process-owned-lock.d.ts +5 -2
- package/dist/src/platform/process-owned-lock.js +20 -10
- package/dist/src/platform/process-owned-lock.js.map +1 -1
- package/dist/src/servers/discord.js +25 -35
- package/dist/src/servers/discord.js.map +1 -1
- package/dist/src/servers/http.d.ts +3 -0
- package/dist/src/servers/http.js +15 -0
- package/dist/src/servers/http.js.map +1 -1
- package/dist/src/servers/matrix.js +8 -8
- package/dist/src/servers/matrix.js.map +1 -1
- package/dist/src/servers/mattermost.js +7 -10
- package/dist/src/servers/mattermost.js.map +1 -1
- package/dist/src/servers/recorder.d.ts +16 -6
- package/dist/src/servers/recorder.js +52 -12
- package/dist/src/servers/recorder.js.map +1 -1
- package/dist/src/servers/signal.js +8 -8
- package/dist/src/servers/signal.js.map +1 -1
- package/dist/src/servers/slack.js +8 -8
- package/dist/src/servers/slack.js.map +1 -1
- package/dist/src/servers/telegram.d.ts +2 -2
- package/dist/src/servers/telegram.js +8 -8
- package/dist/src/servers/telegram.js.map +1 -1
- package/dist/src/servers/whatsapp-baileys-websocket.js +1 -1
- package/dist/src/servers/whatsapp-baileys-websocket.js.map +1 -1
- package/dist/src/servers/whatsapp.js +13 -18
- package/dist/src/servers/whatsapp.js.map +1 -1
- package/dist/src/servers/zalo.js +8 -7
- package/dist/src/servers/zalo.js.map +1 -1
- package/docs/channel-setup.md +14 -1
- package/package.json +11 -11
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/servers/http.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { createHash, timingSafeEqual } from \"node:crypto\";\nimport { BlockList, isIP } from \"node:net\";\nimport { CrablineError } from \"../core/errors.js\";\n\nexport type ServerRequestEvent = {\n at: string;\n body?: unknown;\n method: string;\n path: string;\n query: Record<string, string>;\n type: \"admin\" | \"api\";\n};\n\nexport type HttpJsonHandlerResult =\n | Response\n | {\n onWriteFailure?(): Promise<void> | void;\n onWriteSuccess?(): Promise<void> | void;\n response: Response;\n };\n\nexport const ADMIN_TOKEN_HEADER = \"x-crabline-admin-token\";\nexport const DEFAULT_MAX_REQUEST_BODY_BYTES = 1024 * 1024;\nexport const DEFAULT_MAX_RESPONSE_BODY_BYTES = 8 * 1024 * 1024;\nexport const DEFAULT_SERVER_SHUTDOWN_GRACE_MS = 250;\nconst DRAINING_REQUESTS = new WeakSet<IncomingMessage>();\nconst LOOPBACK_ADDRESSES = new BlockList();\nLOOPBACK_ADDRESSES.addSubnet(\"127.0.0.0\", 8, \"ipv4\");\nLOOPBACK_ADDRESSES.addAddress(\"::1\", \"ipv6\");\nLOOPBACK_ADDRESSES.addSubnet(\"::ffff:127.0.0.0\", 104, \"ipv6\");\nconst UNSPECIFIED_ADDRESSES = new BlockList();\nUNSPECIFIED_ADDRESSES.addAddress(\"0.0.0.0\", \"ipv4\");\nUNSPECIFIED_ADDRESSES.addAddress(\"::\", \"ipv6\");\nconst HOP_BY_HOP_RESPONSE_HEADERS = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n]);\n\nexport class InvalidJsonBodyError extends Error {\n constructor(cause: unknown, message = \"Request body is not valid JSON.\") {\n super(message, { cause });\n this.name = \"InvalidJsonBodyError\";\n }\n}\n\nexport class RequestBodyTooLargeError extends Error {\n constructor(readonly maxBytes: number) {\n super(`Request body exceeds the ${maxBytes} byte limit.`);\n this.name = \"RequestBodyTooLargeError\";\n }\n}\n\nexport class ResponseBodyTooLargeError extends Error {\n constructor(readonly maxBytes: number) {\n super(`Response body exceeds the ${maxBytes} byte limit.`);\n this.name = \"ResponseBodyTooLargeError\";\n }\n}\n\nexport function jsonResponse(value: unknown, status = 200): Response {\n return Response.json(value, { status });\n}\n\nexport function drainRequestBody(request: IncomingMessage): void {\n if (request.readableEnded || DRAINING_REQUESTS.has(request)) {\n return;\n }\n DRAINING_REQUESTS.add(request);\n const ignoreError = () => {};\n request.on(\"error\", ignoreError);\n if (request.destroyed) {\n // IncomingMessage may emit its terminal error after destroyed becomes true.\n return;\n }\n const cleanup = () => {\n DRAINING_REQUESTS.delete(request);\n request.off(\"close\", cleanup);\n request.off(\"end\", cleanup);\n request.off(\"error\", ignoreError);\n };\n\n request.once(\"close\", cleanup);\n request.once(\"end\", cleanup);\n request.resume();\n}\n\nexport async function readBody(\n request: IncomingMessage,\n maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES,\n): Promise<Buffer> {\n requirePositiveSafeInteger(maxBytes, \"maxBytes\");\n if (request.aborted) {\n throw new Error(\"Request body stream was aborted.\");\n }\n const contentLengthHeader = request.headers[\"content-length\"];\n const contentLengthValue = Array.isArray(contentLengthHeader)\n ? contentLengthHeader[0]\n : contentLengthHeader;\n if (contentLengthValue && /^\\d+$/u.test(contentLengthValue)) {\n const contentLength = Number(contentLengthValue);\n if (!Number.isSafeInteger(contentLength) || contentLength > maxBytes) {\n drainRequestBody(request);\n throw new RequestBodyTooLargeError(maxBytes);\n }\n }\n\n return await new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let length = 0;\n let settled = false;\n\n const cleanup = () => {\n request.off(\"aborted\", onAborted);\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n request.off(\"error\", onError);\n };\n const fail = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n drainRequestBody(request);\n cleanup();\n reject(error);\n };\n const onAborted = () => fail(new Error(\"Request body stream was aborted.\"));\n const onData = (chunk: Buffer | string) => {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n length += buffer.length;\n if (length > maxBytes) {\n fail(new RequestBodyTooLargeError(maxBytes));\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n resolve(Buffer.concat(chunks, length));\n };\n const onError = (error: Error) => fail(error);\n\n request.on(\"aborted\", onAborted);\n request.on(\"data\", onData);\n request.on(\"end\", onEnd);\n request.on(\"error\", onError);\n if (request.aborted) {\n onAborted();\n }\n });\n}\n\nexport async function parseUnknownRequestBody(\n request: IncomingMessage,\n maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES,\n): Promise<unknown> {\n const body = await readBody(request, maxBytes);\n if (body.length === 0) {\n return {};\n }\n const contentType = request.headers[\"content-type\"] ?? \"\";\n const isJson = Array.isArray(contentType)\n ? contentType.some(isJsonMediaType)\n : isJsonMediaType(contentType);\n if (isJson) {\n try {\n return JSON.parse(body.toString(\"utf8\")) as unknown;\n } catch (error) {\n throw new InvalidJsonBodyError(error);\n }\n }\n const params = new URLSearchParams(body.toString(\"utf8\"));\n return Object.fromEntries(params.entries());\n}\n\nexport function isJsonMediaType(value: string): boolean {\n const mediaType = value.split(\";\", 1)[0]?.trim().toLowerCase();\n return (\n mediaType === \"application/json\" ||\n /^[a-z0-9!#$%&'*+.^_`|~-]+\\/[a-z0-9!#$%&'*+.^_`|~-]+\\+json$/u.test(mediaType ?? \"\")\n );\n}\n\nexport async function parseRequestBody(request: IncomingMessage): Promise<Record<string, unknown>> {\n const body = await parseUnknownRequestBody(request);\n if (!isJsonObject(body)) {\n throw new InvalidJsonBodyError(undefined, \"Request body must be a JSON object.\");\n }\n return body;\n}\n\nexport function isJsonObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function queryRecord(url: URL): Record<string, string> {\n return Object.fromEntries(url.searchParams.entries());\n}\n\nexport function formatUrlHost(host: string): string {\n return host.includes(\":\") ? `[${host}]` : host;\n}\n\nfunction normalizeHost(host: string): string {\n return host\n .trim()\n .replace(/^\\[(.*)\\]$/u, \"$1\")\n .toLowerCase()\n .replace(/\\.$/u, \"\");\n}\n\nexport function isLoopbackAddress(address: string): boolean {\n const normalized = normalizeHost(address);\n const family = isIP(normalized);\n return family === 4\n ? LOOPBACK_ADDRESSES.check(normalized, \"ipv4\")\n : family === 6\n ? LOOPBACK_ADDRESSES.check(normalized, \"ipv6\")\n : false;\n}\n\nexport function isLoopbackHost(host: string): boolean {\n const normalized = normalizeHost(host);\n if (normalized === \"localhost\" || normalized.endsWith(\".localhost\")) {\n return true;\n }\n return isLoopbackAddress(normalized);\n}\n\nexport function advertisedHostForBindAddress(host: string, boundAddress: string): string {\n const normalizedBoundAddress = normalizeHost(boundAddress);\n const boundFamily = isIP(normalizedBoundAddress);\n if (boundFamily === 4 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, \"ipv4\")) {\n return \"127.0.0.1\";\n }\n if (boundFamily === 6 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, \"ipv6\")) {\n return \"::1\";\n }\n return isLoopbackHost(host) && isLoopbackAddress(boundAddress) ? boundAddress : host;\n}\n\nexport function assertLoopbackBindAddress(\n configuredHost: string,\n boundAddress: string,\n serverName: string,\n): void {\n if (isLoopbackHost(configuredHost) && !isLoopbackAddress(boundAddress)) {\n throw new CrablineError(\n `${serverName} resolved a loopback hostname to non-loopback address ${boundAddress}.`,\n { kind: \"connectivity\" },\n );\n }\n}\n\nexport function writeFetchResponseHeaders(response: ServerResponse, fetchResponse: Response): void {\n const preserveRepresentationLength =\n response.req?.method === \"HEAD\" || fetchResponse.status === 304;\n const connectionHeaders = new Set(\n (fetchResponse.headers.get(\"connection\") ?? \"\")\n .split(\",\")\n .map((name) => name.trim().toLowerCase())\n .filter(Boolean),\n );\n if (connectionHeaders.has(\"close\")) {\n response.shouldKeepAlive = false;\n }\n\n for (const [name, value] of fetchResponse.headers) {\n const normalizedName = name.toLowerCase();\n if (\n normalizedName === \"set-cookie\" ||\n HOP_BY_HOP_RESPONSE_HEADERS.has(normalizedName) ||\n connectionHeaders.has(normalizedName) ||\n (normalizedName === \"content-length\" && !preserveRepresentationLength)\n ) {\n continue;\n }\n response.setHeader(name, value);\n }\n\n const setCookies = fetchResponse.headers.getSetCookie();\n if (setCookies.length > 0 && !connectionHeaders.has(\"set-cookie\")) {\n response.setHeader(\"set-cookie\", setCookies);\n }\n}\n\nexport async function writeResponse(\n response: ServerResponse,\n fetchResponse: Response,\n maxBytes = DEFAULT_MAX_RESPONSE_BODY_BYTES,\n): Promise<void> {\n requirePositiveSafeInteger(maxBytes, \"maxResponseBodyBytes\");\n const reader = fetchResponse.body?.getReader();\n let cancellation: Promise<void> | undefined;\n let rejectStopped!: (error: Error) => void;\n let stoppedError: Error | undefined;\n const stopped = new Promise<never>((_, reject) => {\n rejectStopped = reject;\n });\n void stopped.catch(() => {});\n\n const cancelBody = (reason: Error) => {\n if (!reader || cancellation) {\n return;\n }\n cancellation = reader.cancel(reason).catch(() => {});\n };\n const stop = (error: Error) => {\n if (stoppedError) {\n return;\n }\n stoppedError = error;\n cancelBody(error);\n rejectStopped(error);\n };\n const onClose = () => {\n if (!response.writableFinished) {\n stop(new Error(\"HTTP response closed before delivery completed.\"));\n }\n };\n const onError = (error: Error) => stop(error);\n const onRequestAborted = () => stop(new Error(\"HTTP response request was aborted.\"));\n response.once(\"close\", onClose);\n response.once(\"error\", onError);\n response.req?.once(\"aborted\", onRequestAborted);\n\n try {\n if (\n response.destroyed ||\n response.req?.aborted ||\n response.req?.socket.destroyed ||\n response.socket?.destroyed\n ) {\n throw new Error(\"HTTP response closed before delivery completed.\");\n }\n\n if (response.req?.method === \"HEAD\") {\n cancelBody(new Error(\"HEAD response body is not transferred.\"));\n response.statusCode = fetchResponse.status;\n writeFetchResponseHeaders(response, fetchResponse);\n let onFinish!: () => void;\n const finished = new Promise<void>((resolve) => {\n onFinish = resolve;\n response.once(\"finish\", onFinish);\n });\n try {\n response.end();\n await Promise.race([finished, stopped]);\n } finally {\n response.off(\"finish\", onFinish);\n }\n return;\n }\n\n const chunks: Buffer[] = [];\n let bodyLength = 0;\n if (reader) {\n while (true) {\n const chunk = await Promise.race([reader.read(), stopped]);\n if (chunk.done) {\n break;\n }\n if (chunk.value.byteLength > 0) {\n if (bodyLength + chunk.value.byteLength > maxBytes) {\n throw new ResponseBodyTooLargeError(maxBytes);\n }\n const buffer = Buffer.from(chunk.value);\n chunks.push(buffer);\n bodyLength += buffer.length;\n }\n }\n }\n\n const body = Buffer.concat(chunks, bodyLength);\n response.statusCode = fetchResponse.status;\n writeFetchResponseHeaders(response, fetchResponse);\n let onFinish!: () => void;\n const finished = new Promise<void>((resolve) => {\n onFinish = resolve;\n response.once(\"finish\", onFinish);\n });\n try {\n response.end(body);\n await Promise.race([finished, stopped]);\n } finally {\n response.off(\"finish\", onFinish);\n }\n } catch (error) {\n cancelBody(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n response.off(\"close\", onClose);\n response.off(\"error\", onError);\n response.req?.off(\"aborted\", onRequestAborted);\n }\n}\n\nexport function closeServer(\n server: Server,\n graceMs = DEFAULT_SERVER_SHUTDOWN_GRACE_MS,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const closeIdleInterval = setInterval(() => server.closeIdleConnections(), 25);\n closeIdleInterval.unref();\n const forceCloseTimer = setTimeout(() => {\n server.closeAllConnections();\n }, graceMs);\n forceCloseTimer.unref();\n server.close((error) => {\n clearInterval(closeIdleInterval);\n clearTimeout(forceCloseTimer);\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n server.closeIdleConnections();\n });\n}\n\nexport async function startHttpJsonServer(params: {\n handle: (request: IncomingMessage, response: ServerResponse) => Promise<HttpJsonHandlerResult>;\n handleError?: (error: unknown, request: IncomingMessage) => Response | undefined;\n host: string;\n maxResponseBodyBytes?: number | undefined;\n port: number;\n serverName: string;\n}): Promise<{ baseUrl: string; close(): Promise<void>; server: Server }> {\n const maxResponseBodyBytes = requirePositiveSafeInteger(\n params.maxResponseBodyBytes ?? DEFAULT_MAX_RESPONSE_BODY_BYTES,\n \"maxResponseBodyBytes\",\n );\n const handleRequest = async (request: IncomingMessage, response: ServerResponse) => {\n try {\n const result = await params.handle(request, response);\n drainRequestBody(request);\n const handled = result instanceof Response ? { response: result } : result;\n try {\n await writeResponse(response, handled.response, maxResponseBodyBytes);\n } catch (error) {\n await handled.onWriteFailure?.();\n throw error;\n }\n try {\n await handled.onWriteSuccess?.();\n } catch {\n // Delivery is already committed; lifecycle failures must not trigger another response.\n }\n } catch (error) {\n drainRequestBody(request);\n let handled: Response | undefined;\n try {\n handled = params.handleError?.(error, request);\n } catch {\n handled = undefined;\n }\n try {\n await writeResponse(\n response,\n handled ??\n jsonResponse(\n {\n error: \"internal server error\",\n ok: false,\n },\n 500,\n ),\n maxResponseBodyBytes,\n );\n } catch {\n response.destroy();\n }\n }\n };\n const server = createServer((request, response) => {\n void handleRequest(request, response);\n });\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(params.port, params.host, () => {\n server.off(\"error\", reject);\n resolve();\n });\n });\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new CrablineError(`Unable to resolve ${params.serverName} local server address.`, {\n kind: \"connectivity\",\n });\n }\n try {\n assertLoopbackBindAddress(params.host, address.address, params.serverName);\n } catch (error) {\n await closeServer(server);\n throw error;\n }\n const advertisedHost = advertisedHostForBindAddress(params.host, address.address);\n return {\n baseUrl: `http://${formatUrlHost(advertisedHost)}:${address.port}`,\n async close() {\n await closeServer(server);\n },\n server,\n };\n}\n\nfunction requirePositiveSafeInteger(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new RangeError(`${name} must be a positive safe integer.`);\n }\n return value;\n}\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"bigint\") {\n return value.toString();\n }\n return undefined;\n}\n\nexport function readTrimmedString(value: unknown): string | undefined {\n const stringValue = readString(value)?.trim();\n return stringValue ? stringValue : undefined;\n}\n\nexport function readInteger(value: unknown): number | undefined {\n const stringValue = readTrimmedString(value);\n if (!stringValue || !/^-?\\d+$/u.test(stringValue)) {\n return undefined;\n }\n const parsed = Number(stringValue);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\nfunction readBearerToken(authorization: string | undefined): string | undefined {\n if (!authorization) {\n return undefined;\n }\n const trimmed = authorization.trimStart();\n if (trimmed.slice(0, 7).toLowerCase() !== \"bearer \") {\n return undefined;\n }\n return trimmed.slice(7);\n}\n\nexport function constantTimeTokenEqual(providedToken: string, expectedToken: string): boolean {\n const provided = createHash(\"sha256\").update(providedToken).digest();\n const expected = createHash(\"sha256\").update(expectedToken).digest();\n return timingSafeEqual(provided, expected);\n}\n\nexport function hasAdminToken(request: IncomingMessage, expectedToken: string): boolean {\n const header = request.headers[ADMIN_TOKEN_HEADER];\n const directToken = Array.isArray(header) ? header[0] : header;\n const providedToken = directToken ?? readBearerToken(request.headers.authorization);\n if (!providedToken) {\n return false;\n }\n\n return constantTimeTokenEqual(providedToken, expectedToken);\n}\n\nexport function adminAuthError(): Response {\n return new Response(\"unauthorized\", {\n headers: { \"www-authenticate\": \"Bearer\" },\n status: 401,\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/servers/http.ts"],"names":[],"mappings":"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","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport { createHash, timingSafeEqual } from \"node:crypto\";\nimport { BlockList, isIP } from \"node:net\";\nimport { CrablineError } from \"../core/errors.js\";\n\nexport type ServerRequestEvent = {\n at: string;\n body?: unknown;\n method: string;\n path: string;\n query: Record<string, string>;\n type: \"admin\" | \"api\";\n};\n\nexport type HttpJsonHandlerResult =\n | Response\n | {\n onWriteFailure?(): Promise<void> | void;\n onWriteSuccess?(): Promise<void> | void;\n response: Response;\n };\n\nexport const ADMIN_TOKEN_HEADER = \"x-crabline-admin-token\";\nexport const DEFAULT_MAX_REQUEST_BODY_BYTES = 1024 * 1024;\nexport const DEFAULT_MAX_RESPONSE_BODY_BYTES = 8 * 1024 * 1024;\nexport const DEFAULT_SERVER_SHUTDOWN_GRACE_MS = 250;\nconst DRAINING_REQUESTS = new WeakSet<IncomingMessage>();\nconst LOOPBACK_ADDRESSES = new BlockList();\nLOOPBACK_ADDRESSES.addSubnet(\"127.0.0.0\", 8, \"ipv4\");\nLOOPBACK_ADDRESSES.addAddress(\"::1\", \"ipv6\");\nLOOPBACK_ADDRESSES.addSubnet(\"::ffff:127.0.0.0\", 104, \"ipv6\");\nconst UNSPECIFIED_ADDRESSES = new BlockList();\nUNSPECIFIED_ADDRESSES.addAddress(\"0.0.0.0\", \"ipv4\");\nUNSPECIFIED_ADDRESSES.addAddress(\"::\", \"ipv6\");\nconst HOP_BY_HOP_RESPONSE_HEADERS = new Set([\n \"connection\",\n \"keep-alive\",\n \"proxy-authenticate\",\n \"proxy-authorization\",\n \"proxy-connection\",\n \"te\",\n \"trailer\",\n \"transfer-encoding\",\n \"upgrade\",\n]);\n\nexport class InvalidJsonBodyError extends Error {\n constructor(cause: unknown, message = \"Request body is not valid JSON.\") {\n super(message, { cause });\n this.name = \"InvalidJsonBodyError\";\n }\n}\n\nexport class RequestBodyTooLargeError extends Error {\n constructor(readonly maxBytes: number) {\n super(`Request body exceeds the ${maxBytes} byte limit.`);\n this.name = \"RequestBodyTooLargeError\";\n }\n}\n\nexport class ResponseBodyTooLargeError extends Error {\n constructor(readonly maxBytes: number) {\n super(`Response body exceeds the ${maxBytes} byte limit.`);\n this.name = \"ResponseBodyTooLargeError\";\n }\n}\n\nexport function jsonResponse(value: unknown, status = 200): Response {\n return Response.json(value, { status });\n}\n\nexport function drainRequestBody(request: IncomingMessage): void {\n if (request.readableEnded || DRAINING_REQUESTS.has(request)) {\n return;\n }\n DRAINING_REQUESTS.add(request);\n const ignoreError = () => {};\n request.on(\"error\", ignoreError);\n if (request.destroyed) {\n // IncomingMessage may emit its terminal error after destroyed becomes true.\n return;\n }\n const cleanup = () => {\n DRAINING_REQUESTS.delete(request);\n request.off(\"close\", cleanup);\n request.off(\"end\", cleanup);\n request.off(\"error\", ignoreError);\n };\n\n request.once(\"close\", cleanup);\n request.once(\"end\", cleanup);\n request.resume();\n}\n\nexport async function readBody(\n request: IncomingMessage,\n maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES,\n): Promise<Buffer> {\n requirePositiveSafeInteger(maxBytes, \"maxBytes\");\n if (request.aborted) {\n throw new Error(\"Request body stream was aborted.\");\n }\n const contentLengthHeader = request.headers[\"content-length\"];\n const contentLengthValue = Array.isArray(contentLengthHeader)\n ? contentLengthHeader[0]\n : contentLengthHeader;\n if (contentLengthValue && /^\\d+$/u.test(contentLengthValue)) {\n const contentLength = Number(contentLengthValue);\n if (!Number.isSafeInteger(contentLength) || contentLength > maxBytes) {\n drainRequestBody(request);\n throw new RequestBodyTooLargeError(maxBytes);\n }\n }\n\n return await new Promise<Buffer>((resolve, reject) => {\n const chunks: Buffer[] = [];\n let length = 0;\n let settled = false;\n\n const cleanup = () => {\n request.off(\"aborted\", onAborted);\n request.off(\"data\", onData);\n request.off(\"end\", onEnd);\n request.off(\"error\", onError);\n };\n const fail = (error: Error) => {\n if (settled) {\n return;\n }\n settled = true;\n drainRequestBody(request);\n cleanup();\n reject(error);\n };\n const onAborted = () => fail(new Error(\"Request body stream was aborted.\"));\n const onData = (chunk: Buffer | string) => {\n const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);\n length += buffer.length;\n if (length > maxBytes) {\n fail(new RequestBodyTooLargeError(maxBytes));\n return;\n }\n chunks.push(buffer);\n };\n const onEnd = () => {\n if (settled) {\n return;\n }\n settled = true;\n cleanup();\n resolve(Buffer.concat(chunks, length));\n };\n const onError = (error: Error) => fail(error);\n\n request.on(\"aborted\", onAborted);\n request.on(\"data\", onData);\n request.on(\"end\", onEnd);\n request.on(\"error\", onError);\n if (request.aborted) {\n onAborted();\n }\n });\n}\n\nexport async function parseUnknownRequestBody(\n request: IncomingMessage,\n maxBytes = DEFAULT_MAX_REQUEST_BODY_BYTES,\n): Promise<unknown> {\n const body = await readBody(request, maxBytes);\n if (body.length === 0) {\n return {};\n }\n const contentType = request.headers[\"content-type\"] ?? \"\";\n const isJson = Array.isArray(contentType)\n ? contentType.some(isJsonMediaType)\n : isJsonMediaType(contentType);\n if (isJson) {\n try {\n return JSON.parse(body.toString(\"utf8\")) as unknown;\n } catch (error) {\n throw new InvalidJsonBodyError(error);\n }\n }\n const params = new URLSearchParams(body.toString(\"utf8\"));\n return Object.fromEntries(params.entries());\n}\n\nexport function isJsonMediaType(value: string): boolean {\n const mediaType = value.split(\";\", 1)[0]?.trim().toLowerCase();\n return (\n mediaType === \"application/json\" ||\n /^[a-z0-9!#$%&'*+.^_`|~-]+\\/[a-z0-9!#$%&'*+.^_`|~-]+\\+json$/u.test(mediaType ?? \"\")\n );\n}\n\nexport async function parseRequestBody(request: IncomingMessage): Promise<Record<string, unknown>> {\n const body = await parseUnknownRequestBody(request);\n if (!isJsonObject(body)) {\n throw new InvalidJsonBodyError(undefined, \"Request body must be a JSON object.\");\n }\n return body;\n}\n\nexport function isJsonObject(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\nexport function queryRecord(url: URL): Record<string, string> {\n return Object.fromEntries(url.searchParams.entries());\n}\n\nexport function formatUrlHost(host: string): string {\n return host.includes(\":\") ? `[${host}]` : host;\n}\n\nfunction normalizeHost(host: string): string {\n return host\n .trim()\n .replace(/^\\[(.*)\\]$/u, \"$1\")\n .toLowerCase()\n .replace(/\\.$/u, \"\");\n}\n\nexport function isLoopbackAddress(address: string): boolean {\n const normalized = normalizeHost(address);\n const family = isIP(normalized);\n return family === 4\n ? LOOPBACK_ADDRESSES.check(normalized, \"ipv4\")\n : family === 6\n ? LOOPBACK_ADDRESSES.check(normalized, \"ipv6\")\n : false;\n}\n\nexport function isLoopbackHost(host: string): boolean {\n const normalized = normalizeHost(host);\n if (normalized === \"localhost\" || normalized.endsWith(\".localhost\")) {\n return true;\n }\n return isLoopbackAddress(normalized);\n}\n\nexport function advertisedHostForBindAddress(host: string, boundAddress: string): string {\n const normalizedBoundAddress = normalizeHost(boundAddress);\n const boundFamily = isIP(normalizedBoundAddress);\n if (boundFamily === 4 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, \"ipv4\")) {\n return \"127.0.0.1\";\n }\n if (boundFamily === 6 && UNSPECIFIED_ADDRESSES.check(normalizedBoundAddress, \"ipv6\")) {\n return \"::1\";\n }\n return isLoopbackHost(host) && isLoopbackAddress(boundAddress) ? boundAddress : host;\n}\n\nexport function assertLoopbackBindAddress(\n configuredHost: string,\n boundAddress: string,\n serverName: string,\n): void {\n if (isLoopbackHost(configuredHost) && !isLoopbackAddress(boundAddress)) {\n throw new CrablineError(\n `${serverName} resolved a loopback hostname to non-loopback address ${boundAddress}.`,\n { kind: \"connectivity\" },\n );\n }\n}\n\nexport function writeFetchResponseHeaders(response: ServerResponse, fetchResponse: Response): void {\n const preserveRepresentationLength =\n response.req?.method === \"HEAD\" || fetchResponse.status === 304;\n const connectionHeaders = new Set(\n (fetchResponse.headers.get(\"connection\") ?? \"\")\n .split(\",\")\n .map((name) => name.trim().toLowerCase())\n .filter(Boolean),\n );\n if (connectionHeaders.has(\"close\")) {\n response.shouldKeepAlive = false;\n }\n\n for (const [name, value] of fetchResponse.headers) {\n const normalizedName = name.toLowerCase();\n if (\n normalizedName === \"set-cookie\" ||\n HOP_BY_HOP_RESPONSE_HEADERS.has(normalizedName) ||\n connectionHeaders.has(normalizedName) ||\n (normalizedName === \"content-length\" && !preserveRepresentationLength)\n ) {\n continue;\n }\n response.setHeader(name, value);\n }\n\n const setCookies = fetchResponse.headers.getSetCookie();\n if (setCookies.length > 0 && !connectionHeaders.has(\"set-cookie\")) {\n response.setHeader(\"set-cookie\", setCookies);\n }\n}\n\nexport async function writeResponse(\n response: ServerResponse,\n fetchResponse: Response,\n maxBytes = DEFAULT_MAX_RESPONSE_BODY_BYTES,\n): Promise<void> {\n requirePositiveSafeInteger(maxBytes, \"maxResponseBodyBytes\");\n const reader = fetchResponse.body?.getReader();\n let cancellation: Promise<void> | undefined;\n let rejectStopped!: (error: Error) => void;\n let stoppedError: Error | undefined;\n const stopped = new Promise<never>((_, reject) => {\n rejectStopped = reject;\n });\n void stopped.catch(() => {});\n\n const cancelBody = (reason: Error) => {\n if (!reader || cancellation) {\n return;\n }\n cancellation = reader.cancel(reason).catch(() => {});\n };\n const stop = (error: Error) => {\n if (stoppedError) {\n return;\n }\n stoppedError = error;\n cancelBody(error);\n rejectStopped(error);\n };\n const onClose = () => {\n if (!response.writableFinished) {\n stop(new Error(\"HTTP response closed before delivery completed.\"));\n }\n };\n const onError = (error: Error) => stop(error);\n const onRequestAborted = () => stop(new Error(\"HTTP response request was aborted.\"));\n response.once(\"close\", onClose);\n response.once(\"error\", onError);\n response.req?.once(\"aborted\", onRequestAborted);\n\n try {\n if (\n response.destroyed ||\n response.req?.aborted ||\n response.req?.socket.destroyed ||\n response.socket?.destroyed\n ) {\n throw new Error(\"HTTP response closed before delivery completed.\");\n }\n\n if (response.req?.method === \"HEAD\") {\n cancelBody(new Error(\"HEAD response body is not transferred.\"));\n response.statusCode = fetchResponse.status;\n writeFetchResponseHeaders(response, fetchResponse);\n let onFinish!: () => void;\n const finished = new Promise<void>((resolve) => {\n onFinish = resolve;\n response.once(\"finish\", onFinish);\n });\n try {\n response.end();\n await Promise.race([finished, stopped]);\n } finally {\n response.off(\"finish\", onFinish);\n }\n return;\n }\n\n const chunks: Buffer[] = [];\n let bodyLength = 0;\n if (reader) {\n while (true) {\n const chunk = await Promise.race([reader.read(), stopped]);\n if (chunk.done) {\n break;\n }\n if (chunk.value.byteLength > 0) {\n if (bodyLength + chunk.value.byteLength > maxBytes) {\n throw new ResponseBodyTooLargeError(maxBytes);\n }\n const buffer = Buffer.from(chunk.value);\n chunks.push(buffer);\n bodyLength += buffer.length;\n }\n }\n }\n\n const body = Buffer.concat(chunks, bodyLength);\n response.statusCode = fetchResponse.status;\n writeFetchResponseHeaders(response, fetchResponse);\n let onFinish!: () => void;\n const finished = new Promise<void>((resolve) => {\n onFinish = resolve;\n response.once(\"finish\", onFinish);\n });\n try {\n response.end(body);\n await Promise.race([finished, stopped]);\n } finally {\n response.off(\"finish\", onFinish);\n }\n } catch (error) {\n cancelBody(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n response.off(\"close\", onClose);\n response.off(\"error\", onError);\n response.req?.off(\"aborted\", onRequestAborted);\n }\n}\n\nexport function createServerClose(\n recorder: { close(): Promise<void> },\n ...closeResources: Array<() => void | Promise<void>>\n): () => Promise<void> {\n let closing: Promise<void> | undefined;\n return () =>\n (closing ??= (async () => {\n const results = await Promise.allSettled(closeResources.map(async (close) => await close()));\n // Let native polling responses finish during transport grace, then fence late writes.\n results.push(...(await Promise.allSettled([recorder.close()])));\n const errors = results.flatMap((result) =>\n result.status === \"rejected\" ? [result.reason] : [],\n );\n if (errors.length === 1) {\n throw errors[0];\n }\n if (errors.length > 1) {\n throw new AggregateError(errors, \"Server shutdown failed.\");\n }\n })());\n}\n\nexport function closeServer(\n server: Server,\n graceMs = DEFAULT_SERVER_SHUTDOWN_GRACE_MS,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const closeIdleInterval = setInterval(() => server.closeIdleConnections(), 25);\n closeIdleInterval.unref();\n const forceCloseTimer = setTimeout(() => {\n server.closeAllConnections();\n }, graceMs);\n forceCloseTimer.unref();\n server.close((error) => {\n clearInterval(closeIdleInterval);\n clearTimeout(forceCloseTimer);\n if (error) {\n reject(error);\n return;\n }\n resolve();\n });\n server.closeIdleConnections();\n });\n}\n\nexport async function startHttpJsonServer(params: {\n handle: (request: IncomingMessage, response: ServerResponse) => Promise<HttpJsonHandlerResult>;\n handleError?: (error: unknown, request: IncomingMessage) => Response | undefined;\n host: string;\n maxResponseBodyBytes?: number | undefined;\n port: number;\n serverName: string;\n}): Promise<{ baseUrl: string; close(): Promise<void>; server: Server }> {\n const maxResponseBodyBytes = requirePositiveSafeInteger(\n params.maxResponseBodyBytes ?? DEFAULT_MAX_RESPONSE_BODY_BYTES,\n \"maxResponseBodyBytes\",\n );\n const handleRequest = async (request: IncomingMessage, response: ServerResponse) => {\n try {\n const result = await params.handle(request, response);\n drainRequestBody(request);\n const handled = result instanceof Response ? { response: result } : result;\n try {\n await writeResponse(response, handled.response, maxResponseBodyBytes);\n } catch (error) {\n await handled.onWriteFailure?.();\n throw error;\n }\n try {\n await handled.onWriteSuccess?.();\n } catch {\n // Delivery is already committed; lifecycle failures must not trigger another response.\n }\n } catch (error) {\n drainRequestBody(request);\n let handled: Response | undefined;\n try {\n handled = params.handleError?.(error, request);\n } catch {\n handled = undefined;\n }\n try {\n await writeResponse(\n response,\n handled ??\n jsonResponse(\n {\n error: \"internal server error\",\n ok: false,\n },\n 500,\n ),\n maxResponseBodyBytes,\n );\n } catch {\n response.destroy();\n }\n }\n };\n const server = createServer((request, response) => {\n void handleRequest(request, response);\n });\n await new Promise<void>((resolve, reject) => {\n server.once(\"error\", reject);\n server.listen(params.port, params.host, () => {\n server.off(\"error\", reject);\n resolve();\n });\n });\n const address = server.address();\n if (!address || typeof address === \"string\") {\n throw new CrablineError(`Unable to resolve ${params.serverName} local server address.`, {\n kind: \"connectivity\",\n });\n }\n try {\n assertLoopbackBindAddress(params.host, address.address, params.serverName);\n } catch (error) {\n await closeServer(server);\n throw error;\n }\n const advertisedHost = advertisedHostForBindAddress(params.host, address.address);\n return {\n baseUrl: `http://${formatUrlHost(advertisedHost)}:${address.port}`,\n async close() {\n await closeServer(server);\n },\n server,\n };\n}\n\nfunction requirePositiveSafeInteger(value: number, name: string): number {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new RangeError(`${name} must be a positive safe integer.`);\n }\n return value;\n}\n\nexport function readString(value: unknown): string | undefined {\n if (typeof value === \"string\" && value.length > 0) {\n return value;\n }\n if (typeof value === \"number\" || typeof value === \"bigint\") {\n return value.toString();\n }\n return undefined;\n}\n\nexport function readTrimmedString(value: unknown): string | undefined {\n const stringValue = readString(value)?.trim();\n return stringValue ? stringValue : undefined;\n}\n\nexport function readInteger(value: unknown): number | undefined {\n const stringValue = readTrimmedString(value);\n if (!stringValue || !/^-?\\d+$/u.test(stringValue)) {\n return undefined;\n }\n const parsed = Number(stringValue);\n return Number.isSafeInteger(parsed) ? parsed : undefined;\n}\n\nfunction readBearerToken(authorization: string | undefined): string | undefined {\n if (!authorization) {\n return undefined;\n }\n const trimmed = authorization.trimStart();\n if (trimmed.slice(0, 7).toLowerCase() !== \"bearer \") {\n return undefined;\n }\n return trimmed.slice(7);\n}\n\nexport function constantTimeTokenEqual(providedToken: string, expectedToken: string): boolean {\n const provided = createHash(\"sha256\").update(providedToken).digest();\n const expected = createHash(\"sha256\").update(expectedToken).digest();\n return timingSafeEqual(provided, expected);\n}\n\nexport function hasAdminToken(request: IncomingMessage, expectedToken: string): boolean {\n const header = request.headers[ADMIN_TOKEN_HEADER];\n const directToken = Array.isArray(header) ? header[0] : header;\n const providedToken = directToken ?? readBearerToken(request.headers.authorization);\n if (!providedToken) {\n return false;\n }\n\n return constantTimeTokenEqual(providedToken, expectedToken);\n}\n\nexport function adminAuthError(): Response {\n return new Response(\"unauthorized\", {\n headers: { \"www-authenticate\": \"Bearer\" },\n status: 401,\n });\n}\n"]}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { isHistoricalMatrixUserId, isMatrixEventId, isMatrixRoomId, isMatrixUserId, } from "../matrix-ids.js";
|
|
4
|
-
import { adminAuthError, constantTimeTokenEqual, DEFAULT_MAX_RESPONSE_BODY_BYTES, hasAdminToken, InvalidJsonBodyError, isJsonObject, jsonResponse, parseUnknownRequestBody, queryRecord, readInteger, readTrimmedString, RequestBodyTooLargeError, startHttpJsonServer, } from "./http.js";
|
|
5
|
-
import {
|
|
4
|
+
import { adminAuthError, createServerClose, constantTimeTokenEqual, DEFAULT_MAX_RESPONSE_BODY_BYTES, hasAdminToken, InvalidJsonBodyError, isJsonObject, jsonResponse, parseUnknownRequestBody, queryRecord, readInteger, readTrimmedString, RequestBodyTooLargeError, startHttpJsonServer, } from "./http.js";
|
|
5
|
+
import { createServerRecorder } from "./recorder.js";
|
|
6
6
|
const MAX_MATRIX_FILTER_BYTES = 1024 * 1024;
|
|
7
7
|
const MAX_MATRIX_FILTERS = 100;
|
|
8
8
|
const MAX_MATRIX_TIMELINE_EVENTS = 1_000;
|
|
@@ -22,8 +22,7 @@ function matrixRoomId(value, serverName) {
|
|
|
22
22
|
return `!${createHash("sha256").update(value).digest("hex").slice(0, 16)}:${serverName}`;
|
|
23
23
|
}
|
|
24
24
|
async function appendEvent(state, event, committed = false) {
|
|
25
|
-
|
|
26
|
-
await (committed ? recordCommittedServerEvent(params) : recordServerEvent(params));
|
|
25
|
+
await (committed ? state.recorder.recordCommitted(event) : state.recorder.record(event));
|
|
27
26
|
}
|
|
28
27
|
function authorized(request, token) {
|
|
29
28
|
const match = /^Bearer\s+(\S+)$/iu.exec(request.headers.authorization ?? "");
|
|
@@ -804,6 +803,7 @@ export async function startMatrixServer(params = {}) {
|
|
|
804
803
|
if (!isMatrixUserId(botUserId)) {
|
|
805
804
|
throw new Error("botUserId must be a canonical Matrix user ID.");
|
|
806
805
|
}
|
|
806
|
+
const recorderPath = params.recorderPath ?? path.resolve("artifacts/crabline/matrix.jsonl");
|
|
807
807
|
const state = {
|
|
808
808
|
accessToken: params.accessToken ?? `syt_crabline_${randomBytes(12).toString("hex")}`,
|
|
809
809
|
adminToken: params.adminToken ?? randomBytes(24).toString("hex"),
|
|
@@ -819,9 +819,9 @@ export async function startMatrixServer(params = {}) {
|
|
|
819
819
|
nextEvent: 1,
|
|
820
820
|
nextFilter: 1,
|
|
821
821
|
nextSequence: 1,
|
|
822
|
-
onEvent: params.onEvent,
|
|
822
|
+
recorder: createServerRecorder({ recorderPath, onEvent: params.onEvent }),
|
|
823
823
|
profiles: new Map([[botUserId, { display_name: "OpenClaw QA" }]]),
|
|
824
|
-
recorderPath
|
|
824
|
+
recorderPath,
|
|
825
825
|
rooms: new Map(),
|
|
826
826
|
serverName,
|
|
827
827
|
syncWaiters: new Set(),
|
|
@@ -925,7 +925,7 @@ export async function startMatrixServer(params = {}) {
|
|
|
925
925
|
});
|
|
926
926
|
const clientApiRoot = `${server.baseUrl}/_matrix/client/v3`;
|
|
927
927
|
return {
|
|
928
|
-
async
|
|
928
|
+
close: createServerClose(state.recorder, async () => {
|
|
929
929
|
for (const room of state.rooms.values()) {
|
|
930
930
|
for (const timer of room.typingTimeouts.values()) {
|
|
931
931
|
clearTimeout(timer);
|
|
@@ -933,7 +933,7 @@ export async function startMatrixServer(params = {}) {
|
|
|
933
933
|
room.typingTimeouts.clear();
|
|
934
934
|
}
|
|
935
935
|
await server.close();
|
|
936
|
-
},
|
|
936
|
+
}),
|
|
937
937
|
manifest: {
|
|
938
938
|
accessToken: state.accessToken,
|
|
939
939
|
adminToken: state.adminToken,
|