@obov/mext 0.6.0 → 0.7.2
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/dist/build.js +16 -2
- package/dist/build.js.map +1 -1
- package/dist/cli/args.js +1 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/build.js +22 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev-server.js +3 -2
- package/dist/cli/dev-server.js.map +1 -1
- package/dist/cli/dev.d.ts +6 -0
- package/dist/cli/dev.js +4 -4
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/main.js +2 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/media.d.ts +19 -0
- package/dist/cli/media.js +77 -0
- package/dist/cli/media.js.map +1 -0
- package/dist/cli/run.js +5 -0
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/serve.d.ts +10 -0
- package/dist/cli/serve.js +114 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/client/index.d.ts +2 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/runner.js +3 -0
- package/dist/client/runner.js.map +1 -1
- package/dist/client/typed.d.ts +3 -1
- package/dist/client/typed.js +39 -3
- package/dist/client/typed.js.map +1 -1
- package/dist/client/types.d.ts +31 -2
- package/dist/client/types.js.map +1 -1
- package/dist/config.d.ts +17 -0
- package/dist/config.js +36 -1
- package/dist/config.js.map +1 -1
- package/dist/content.d.ts +65 -0
- package/dist/content.js +99 -0
- package/dist/content.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/invoke.d.ts +4 -0
- package/dist/invoke.js +12 -5
- package/dist/invoke.js.map +1 -1
- package/dist/manifest.d.ts +6 -1
- package/dist/manifest.js.map +1 -1
- package/dist/mcp/constants.d.ts +2 -0
- package/dist/mcp/constants.js +2 -0
- package/dist/mcp/constants.js.map +1 -1
- package/dist/mcp/dispatch.d.ts +9 -3
- package/dist/mcp/dispatch.js +10 -4
- package/dist/mcp/dispatch.js.map +1 -1
- package/dist/mcp/host.d.ts +14 -0
- package/dist/mcp/host.js +48 -0
- package/dist/mcp/host.js.map +1 -0
- package/dist/mcp/http.d.ts +22 -5
- package/dist/mcp/http.js +154 -19
- package/dist/mcp/http.js.map +1 -1
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/tasks.js +1 -1
- package/dist/mcp/tasks.js.map +1 -1
- package/dist/remote/client.d.ts +24 -1
- package/dist/remote/client.js +177 -53
- package/dist/remote/client.js.map +1 -1
- package/dist/remote/index.d.ts +1 -1
- package/dist/remote/index.js.map +1 -1
- package/dist/route.d.ts +40 -2
- package/dist/route.js +128 -8
- package/dist/route.js.map +1 -1
- package/dist/start.js +3 -2
- package/dist/start.js.map +1 -1
- package/dist/version-constant.d.ts +1 -1
- package/dist/version-constant.js +1 -1
- package/dist/version-constant.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/remote/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../version-constant.ts\"\n\n/**\n * 원격 실행용 최소 MCP 클라이언트 (Streamable HTTP, 프로토콜 2026-07-28, stateless).\n * 요청마다 POST 1회: _meta envelope (버전 · clientInfo · clientCapabilities) + MCP-Protocol-Version · Mcp-Method ·\n * Mcp-Name · Mcp-Param-* 헤더. 응답 = application/json 또는 text/event-stream (progress 알림 → onNotification).\n * MRTR (InputRequiredResult) 재시도 루프는 callTool 의 onInputRequired 가 담당.\n * tasks 확장 (§12.6) 선언: tools/call 이 CreateTaskResult (resultType \"task\") 를 그대로 돌려주고, 폴링 · 답 · 취소 =\n * getTask · updateTask · cancelTask (Mcp-Name = taskId). 폴링 루프는 client/task.ts\n */\n\nexport const PROTOCOL_VERSION = \"2026-07-28\"\n\nexport const META_KEYS = {\n protocolVersion: \"io.modelcontextprotocol/protocolVersion\",\n clientInfo: \"io.modelcontextprotocol/clientInfo\",\n clientCapabilities: \"io.modelcontextprotocol/clientCapabilities\",\n} as const\n\n/** tasks 확장 ID (mcp/tasks.ts TASKS_EXTENSION 과 같은 값. 이 모듈은 서버 SDK 를 import 하지 않는다) */\nexport const TASKS_EXTENSION_ID = \"io.modelcontextprotocol/tasks\"\n\n/** 클라이언트가 처리하는 입력 요청 = elicitation form · url (sampling · roots 없음) + tasks 확장 (폴링 · 답 · 취소) */\nexport const CLIENT_CAPABILITIES = {\n elicitation: { form: {}, url: {} },\n extensions: { [TASKS_EXTENSION_ID]: {} },\n} as const\n\n/** MRTR 재시도 상한 (같은 요청의 input_required 연속 횟수) */\nexport const MAX_INPUT_ROUNDS = 8\n\nexport interface RemoteTool {\n name: string\n description?: string\n inputSchema?: Record<string, unknown>\n outputSchema?: Record<string, unknown>\n annotations?: Record<string, unknown>\n _meta?: Record<string, unknown>\n}\n\nexport interface CallToolResult {\n content?: unknown[]\n structuredContent?: unknown\n isError?: boolean\n [key: string]: unknown\n}\n\n/** InputRequiredResult (resultType: input_required) */\nexport interface InputRequired {\n inputRequests?: Record<string, InputRequestObject>\n requestState?: string\n}\n\nexport interface InputRequestObject {\n method: string\n params?: Record<string, unknown>\n}\n\n/** 입력 요청 key → 응답 (ElicitResult 등). 이번 라운드 요청에 대한 것만 */\nexport type InputResponses = Record<string, unknown>\n\nexport interface RequestOptions {\n signal?: AbortSignal\n /** 서버 → 클라이언트 알림 (notifications/progress 등) */\n onNotification?: (method: string, params: Record<string, unknown>) => void\n /** _meta.progressToken. 있으면 서버가 SSE 로 응답 */\n progressToken?: string | number\n}\n\nexport interface CallToolOptions extends RequestOptions {\n /** input_required 응답 처리 → 이번 라운드의 inputResponses. 없으면 RemoteInputRequiredError */\n onInputRequired?: (request: InputRequired, round: number) => Promise<InputResponses>\n /** tools/call 요청 params._meta 에 실을 값 (예: 확인 표시 \"dev.mext/approval\"). 재시도 라운드에도 같은 값 */\n meta?: Record<string, unknown>\n}\n\n/** HTTP 401. challenge = WWW-Authenticate 파싱 결과, data = JSON-RPC error.data (mext 는 UNAUTHENTICATED toJSON) */\nexport class RemoteUnauthorizedError extends Error {\n readonly challenge: BearerChallenge\n readonly data: unknown\n constructor(message: string, challenge: BearerChallenge, data: unknown) {\n super(message)\n this.name = \"RemoteUnauthorizedError\"\n this.challenge = challenge\n this.data = data\n }\n}\n\n/** JSON-RPC 오류 응답 (HTTP 400 · 403 · 500 포함) */\nexport class RemoteRpcError extends Error {\n readonly code: number\n readonly data: unknown\n readonly status: number\n constructor(message: string, code: number, data: unknown, status: number) {\n super(message)\n this.name = \"RemoteRpcError\"\n this.code = code\n this.data = data\n this.status = status\n }\n}\n\n/** 연결 실패 · JSON-RPC 가 아닌 응답 */\nexport class RemoteTransportError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = \"RemoteTransportError\"\n }\n}\n\n/** onInputRequired 없이 input_required 를 받음 · 라운드 상한 초과 */\nexport class RemoteInputRequiredError extends Error {\n readonly request: InputRequired\n constructor(message: string, request: InputRequired) {\n super(message)\n this.name = \"RemoteInputRequiredError\"\n this.request = request\n }\n}\n\nexport interface RemoteClientOptions {\n /** MCP 엔드포인트 (http(s)://host/mcp) */\n url: string\n /** 요청마다 호출. 없으면 Authorization 헤더 없음 */\n token?: () => string | undefined | Promise<string | undefined>\n fetch?: typeof fetch\n clientInfo?: { name: string; version: string }\n}\n\n/** tools/list 전체 페이지 + 첫 페이지의 캐시 힌트 (2026-07-28 ttlMs · cacheScope) */\nexport interface ToolsListResult {\n tools: RemoteTool[]\n ttlMs?: number\n cacheScope?: string\n}\n\nexport interface RemoteClient {\n readonly url: string\n request(method: string, params?: Record<string, unknown>, options?: RequestOptions): Promise<Record<string, unknown>>\n listTools(options?: RequestOptions): Promise<RemoteTool[]>\n listToolsResult(options?: RequestOptions): Promise<ToolsListResult>\n callTool(tool: RemoteTool, args: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult>\n /** tasks/get (Mcp-Name = taskId) */\n getTask(taskId: string, options?: RequestOptions): Promise<Record<string, unknown>>\n /** tasks/update { taskId, inputResponses } */\n updateTask(taskId: string, inputResponses: InputResponses, options?: RequestOptions): Promise<void>\n /** tasks/cancel { taskId } */\n cancelTask(taskId: string, options?: RequestOptions): Promise<void>\n}\n\nexport function createRemoteClient(options: RemoteClientOptions): RemoteClient {\n const doFetch = options.fetch ?? fetch\n const clientInfo = options.clientInfo ?? { name: \"mext\", version: VERSION }\n let nextId = 1\n\n const request = async (\n method: string,\n params: Record<string, unknown> = {},\n opts: RequestOptions = {},\n extraHeaders: Record<string, string> = {},\n ): Promise<Record<string, unknown>> => {\n const id = nextId++\n const meta: Record<string, unknown> = {\n ...(isRecord(params._meta) ? params._meta : {}),\n [META_KEYS.protocolVersion]: PROTOCOL_VERSION,\n [META_KEYS.clientInfo]: clientInfo,\n [META_KEYS.clientCapabilities]: CLIENT_CAPABILITIES,\n }\n if (opts.progressToken !== undefined) meta.progressToken = opts.progressToken\n const body = { jsonrpc: \"2.0\", id, method, params: { ...params, _meta: meta } }\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n \"MCP-Protocol-Version\": PROTOCOL_VERSION,\n \"Mcp-Method\": method,\n ...extraHeaders,\n }\n const token = await options.token?.()\n if (token) headers.Authorization = `Bearer ${token}`\n\n let res: Response\n try {\n res = await doFetch(options.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...(opts.signal ? { signal: opts.signal } : {}),\n })\n } catch (error) {\n if (opts.signal?.aborted) throw error\n throw new RemoteTransportError(`Cannot reach ${options.url}: ${errorMessage(error)}`, { cause: error })\n }\n\n const type = res.headers.get(\"content-type\") ?? \"\"\n if (res.status === 401) {\n const payload = await readJson(res)\n const err = isRecord(payload) && isRecord(payload.error) ? payload.error : {}\n throw new RemoteUnauthorizedError(\n typeof err.message === \"string\" ? err.message : \"Authentication required.\",\n parseBearerChallenge(res.headers.get(\"www-authenticate\")),\n err.data,\n )\n }\n if (type.includes(\"text/event-stream\")) {\n return handleMessage(await readSse(res, id, opts), id, res.status)\n }\n const payload = await readJson(res)\n if (payload === undefined) {\n throw new RemoteTransportError(`${options.url} returned HTTP ${res.status} without a JSON-RPC response.`)\n }\n return handleMessage(payload, id, res.status)\n }\n\n const handleMessage = (message: unknown, id: number, status: number): Record<string, unknown> => {\n if (!isRecord(message)) throw new RemoteTransportError(`Invalid JSON-RPC response (HTTP ${status}).`)\n if (isRecord(message.error)) {\n const e = message.error\n throw new RemoteRpcError(\n typeof e.message === \"string\" ? e.message : \"JSON-RPC error\",\n typeof e.code === \"number\" ? e.code : -32_603,\n e.data,\n status,\n )\n }\n if (message.id !== id || !isRecord(message.result)) {\n throw new RemoteTransportError(`Invalid JSON-RPC response (HTTP ${status}).`)\n }\n return message.result\n }\n\n const listToolsResult = async (opts: RequestOptions = {}): Promise<ToolsListResult> => {\n const tools: RemoteTool[] = []\n const out: ToolsListResult = { tools }\n let cursor: string | undefined\n for (let page = 0; page < 100; page++) {\n const result = await request(\"tools/list\", cursor === undefined ? {} : { cursor }, opts)\n if (page === 0) {\n if (typeof result.ttlMs === \"number\" && Number.isFinite(result.ttlMs) && result.ttlMs >= 0) out.ttlMs = result.ttlMs\n if (typeof result.cacheScope === \"string\") out.cacheScope = result.cacheScope\n }\n if (Array.isArray(result.tools)) {\n for (const t of result.tools) if (isRecord(t) && typeof t.name === \"string\") tools.push(t as unknown as RemoteTool)\n }\n if (typeof result.nextCursor !== \"string\" || result.nextCursor === \"\") break\n cursor = result.nextCursor\n }\n return out\n }\n\n const callTool = async (\n tool: RemoteTool,\n args: Record<string, unknown>,\n opts: CallToolOptions = {},\n ): Promise<CallToolResult> => {\n const headers: Record<string, string> = { \"Mcp-Name\": tool.name, ...paramHeaders(tool, args) }\n let retry: { inputResponses?: InputResponses; requestState?: string } = {}\n const meta = opts.meta ? { _meta: opts.meta } : {}\n for (let round = 0; ; round++) {\n const result = await request(\"tools/call\", { name: tool.name, arguments: args, ...retry, ...meta }, opts, headers)\n if (result.resultType !== \"input_required\") return result as CallToolResult\n const required: InputRequired = {}\n if (isRecord(result.inputRequests)) required.inputRequests = result.inputRequests as InputRequired[\"inputRequests\"]\n if (typeof result.requestState === \"string\") required.requestState = result.requestState\n if (!opts.onInputRequired) throw new RemoteInputRequiredError(`${tool.name} requires input.`, required)\n if (round >= MAX_INPUT_ROUNDS) {\n throw new RemoteInputRequiredError(`${tool.name} still required input after ${MAX_INPUT_ROUNDS} rounds.`, required)\n }\n // 요청이 있으면 응답을 만든 뒤 재시도. requestState 는 그대로 되돌려 보내고, 없으면 보내지 않는다\n const responses = required.inputRequests ? await opts.onInputRequired(required, round) : undefined\n retry = {}\n if (responses !== undefined) retry.inputResponses = responses\n if (required.requestState !== undefined) retry.requestState = required.requestState\n }\n }\n\n /** tasks/* = Mcp-Name 헤더 = taskId (SDK 검증, 없으면 400) */\n const taskRequest = (method: string, taskId: string, params: Record<string, unknown>, opts: RequestOptions = {}) =>\n request(method, { taskId, ...params }, opts, { \"Mcp-Name\": taskId })\n\n return {\n url: options.url,\n request: (method, params, opts) => request(method, params, opts),\n listTools: async (opts) => (await listToolsResult(opts)).tools,\n listToolsResult,\n callTool,\n getTask: (taskId, opts) => taskRequest(\"tasks/get\", taskId, {}, opts),\n updateTask: async (taskId, inputResponses, opts) => {\n await taskRequest(\"tasks/update\", taskId, { inputResponses }, opts)\n },\n cancelTask: async (taskId, opts) => {\n await taskRequest(\"tasks/cancel\", taskId, {}, opts)\n },\n }\n}\n\n/** inputSchema 의 x-mcp-header 속성 → Mcp-Param-<Name> 헤더 (SEP-2243). 문자열 · 숫자 · boolean 값만 */\nfunction paramHeaders(tool: RemoteTool, args: Record<string, unknown>): Record<string, string> {\n const props = tool.inputSchema?.properties\n if (!isRecord(props)) return {}\n const out: Record<string, string> = {}\n for (const [key, schema] of Object.entries(props)) {\n if (!isRecord(schema) || typeof schema[\"x-mcp-header\"] !== \"string\") continue\n const value = args[key]\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n out[`Mcp-Param-${schema[\"x-mcp-header\"]}`] = String(value)\n }\n }\n return out\n}\n\n/* SSE */\n\n/** 응답 스트림에서 id 의 응답 메시지가 올 때까지 읽는다. 알림은 콜백, 응답 후 스트림을 닫는다 */\nasync function readSse(res: Response, id: number, opts: RequestOptions): Promise<unknown> {\n if (!res.body) throw new RemoteTransportError(\"Empty event stream.\")\n const reader = res.body.pipeThrough(new TextDecoderStream()).getReader()\n let buffer = \"\"\n let data: string[] = []\n const dispatch = (): unknown => {\n if (data.length === 0) return undefined\n const text = data.join(\"\\n\")\n data = []\n let message: unknown\n try {\n message = JSON.parse(text)\n } catch {\n return undefined\n }\n if (!isRecord(message)) return undefined\n if (typeof message.method === \"string\" && message.id === undefined) {\n try {\n opts.onNotification?.(message.method, isRecord(message.params) ? message.params : {})\n } catch {\n // 표시 오류는 응답에 영향 없음\n }\n return undefined\n }\n if (message.id === id && (\"result\" in message || \"error\" in message)) return message\n return undefined\n }\n try {\n for (;;) {\n const { done, value } = await reader.read()\n if (done) break\n buffer += value\n let nl: number\n while ((nl = buffer.search(/\\r\\n|\\r|\\n/)) >= 0) {\n const line = buffer.slice(0, nl)\n buffer = buffer.slice(nl + (buffer.startsWith(\"\\r\\n\", nl) ? 2 : 1))\n if (line === \"\") {\n const found = dispatch()\n if (found !== undefined) return found\n continue\n }\n if (line.startsWith(\":\")) continue\n const colon = line.indexOf(\":\")\n const field = colon < 0 ? line : line.slice(0, colon)\n let value = colon < 0 ? \"\" : line.slice(colon + 1)\n if (value.startsWith(\" \")) value = value.slice(1)\n if (field === \"data\") data.push(value)\n }\n }\n const found = dispatch()\n if (found !== undefined) return found\n } finally {\n await reader.cancel().catch(() => {})\n }\n if (opts.signal?.aborted) throw opts.signal.reason\n throw new RemoteTransportError(\"Event stream ended without a response.\")\n}\n\nasync function readJson(res: Response): Promise<unknown> {\n const text = await res.text().catch(() => \"\")\n if (text === \"\") return undefined\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n\n/* WWW-Authenticate */\n\nexport interface BearerChallenge {\n /** Bearer challenge 가 있었는지 */\n bearer: boolean\n error?: string\n scope?: string\n resourceMetadata?: string\n}\n\n/** WWW-Authenticate 의 Bearer challenge 파라미터 (RFC 6750 · RFC 9728 resource_metadata) */\nexport function parseBearerChallenge(header: string | null): BearerChallenge {\n if (!header) return { bearer: false }\n const m = /(?:^|,\\s*)Bearer\\b(.*)$/i.exec(header)\n if (!m) return { bearer: false }\n const params: Record<string, string> = {}\n const re = /([A-Za-z_][\\w-]*)\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|([^\\s,]+))/g\n for (let p = re.exec(m[1]!); p !== null; p = re.exec(m[1]!)) {\n params[p[1]!.toLowerCase()] = p[2] !== undefined ? p[2].replace(/\\\\(.)/g, \"$1\") : p[3]!\n }\n const out: BearerChallenge = { bearer: true }\n if (params.error !== undefined) out.error = params.error\n if (params.scope !== undefined) out.scope = params.scope\n if (params.resource_metadata !== undefined) out.resourceMetadata = params.resource_metadata\n return out\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n const cause = (error as { cause?: unknown }).cause\n return cause instanceof Error && cause.message ? cause.message : error.message\n }\n return String(error)\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/remote/client.ts"],"names":[],"mappings":"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","sourcesContent":["import { VERSION } from \"../version-constant.ts\"\n\n/**\n * 원격 실행용 최소 MCP 클라이언트 (Streamable HTTP, 프로토콜 2026-07-28, stateless).\n * 요청마다 POST 1회: _meta envelope (버전 · clientInfo · clientCapabilities) + MCP-Protocol-Version · Mcp-Method ·\n * Mcp-Name · Mcp-Param-* 헤더. 응답 = application/json 또는 text/event-stream (progress 알림 → onNotification).\n * MRTR (InputRequiredResult) 재시도 루프는 callTool 의 onInputRequired 가 담당.\n * tasks 확장 (§12.6) 선언: tools/call 이 CreateTaskResult (resultType \"task\") 를 그대로 돌려주고, 폴링 · 답 · 취소 =\n * getTask · updateTask · cancelTask (Mcp-Name = taskId). 폴링 루프는 client/task.ts.\n * subscriptions/listen (mext.md §12.5) = listen: 응답 SSE 를 ack 뒤에도 계속 읽는다 (타입 client subscribe)\n */\n\nexport const PROTOCOL_VERSION = \"2026-07-28\"\n\nexport const META_KEYS = {\n protocolVersion: \"io.modelcontextprotocol/protocolVersion\",\n clientInfo: \"io.modelcontextprotocol/clientInfo\",\n clientCapabilities: \"io.modelcontextprotocol/clientCapabilities\",\n} as const\n\n/** tasks 확장 ID (mcp/tasks.ts TASKS_EXTENSION 과 같은 값. 이 모듈은 서버 SDK 를 import 하지 않는다) */\nexport const TASKS_EXTENSION_ID = \"io.modelcontextprotocol/tasks\"\n\n/** 클라이언트가 처리하는 입력 요청 = elicitation form · url (sampling · roots 없음) + tasks 확장 (폴링 · 답 · 취소) */\nexport const CLIENT_CAPABILITIES = {\n elicitation: { form: {}, url: {} },\n extensions: { [TASKS_EXTENSION_ID]: {} },\n} as const\n\n/** MRTR 재시도 상한 (같은 요청의 input_required 연속 횟수) */\nexport const MAX_INPUT_ROUNDS = 8\n\nexport interface RemoteTool {\n name: string\n description?: string\n inputSchema?: Record<string, unknown>\n outputSchema?: Record<string, unknown>\n annotations?: Record<string, unknown>\n _meta?: Record<string, unknown>\n}\n\nexport interface CallToolResult {\n content?: unknown[]\n structuredContent?: unknown\n isError?: boolean\n [key: string]: unknown\n}\n\n/** InputRequiredResult (resultType: input_required) */\nexport interface InputRequired {\n inputRequests?: Record<string, InputRequestObject>\n requestState?: string\n}\n\nexport interface InputRequestObject {\n method: string\n params?: Record<string, unknown>\n}\n\n/** 입력 요청 key → 응답 (ElicitResult 등). 이번 라운드 요청에 대한 것만 */\nexport type InputResponses = Record<string, unknown>\n\nexport interface RequestOptions {\n signal?: AbortSignal\n /** 서버 → 클라이언트 알림 (notifications/progress 등) */\n onNotification?: (method: string, params: Record<string, unknown>) => void\n /** _meta.progressToken. 있으면 서버가 SSE 로 응답 */\n progressToken?: string | number\n}\n\nexport interface CallToolOptions extends RequestOptions {\n /** input_required 응답 처리 → 이번 라운드의 inputResponses. 없으면 RemoteInputRequiredError */\n onInputRequired?: (request: InputRequired, round: number) => Promise<InputResponses>\n /** tools/call 요청 params._meta 에 실을 값 (예: 확인 표시 \"dev.mext/approval\"). 재시도 라운드에도 같은 값 */\n meta?: Record<string, unknown>\n}\n\n/** HTTP 401. challenge = WWW-Authenticate 파싱 결과, data = JSON-RPC error.data (mext 는 UNAUTHENTICATED toJSON) */\nexport class RemoteUnauthorizedError extends Error {\n readonly challenge: BearerChallenge\n readonly data: unknown\n constructor(message: string, challenge: BearerChallenge, data: unknown) {\n super(message)\n this.name = \"RemoteUnauthorizedError\"\n this.challenge = challenge\n this.data = data\n }\n}\n\n/** JSON-RPC 오류 응답 (HTTP 400 · 403 · 500 포함) */\nexport class RemoteRpcError extends Error {\n readonly code: number\n readonly data: unknown\n readonly status: number\n constructor(message: string, code: number, data: unknown, status: number) {\n super(message)\n this.name = \"RemoteRpcError\"\n this.code = code\n this.data = data\n this.status = status\n }\n}\n\n/** 연결 실패 · JSON-RPC 가 아닌 응답 */\nexport class RemoteTransportError extends Error {\n constructor(message: string, options?: { cause?: unknown }) {\n super(message, options)\n this.name = \"RemoteTransportError\"\n }\n}\n\n/** onInputRequired 없이 input_required 를 받음 · 라운드 상한 초과 */\nexport class RemoteInputRequiredError extends Error {\n readonly request: InputRequired\n constructor(message: string, request: InputRequired) {\n super(message)\n this.name = \"RemoteInputRequiredError\"\n this.request = request\n }\n}\n\nexport interface RemoteClientOptions {\n /** MCP 엔드포인트 (http(s)://host/mcp) */\n url: string\n /** 요청마다 호출. 없으면 Authorization 헤더 없음 */\n token?: () => string | undefined | Promise<string | undefined>\n fetch?: typeof fetch\n clientInfo?: { name: string; version: string }\n}\n\n/** tools/list 전체 페이지 + 첫 페이지의 캐시 힌트 (2026-07-28 ttlMs · cacheScope) */\nexport interface ToolsListResult {\n tools: RemoteTool[]\n ttlMs?: number\n cacheScope?: string\n}\n\n/** subscriptions/listen 스트림 종료. client = close · signal, server = 완료 result · 스트림 끝, error = 연결 오류 · JSON-RPC 오류 */\nexport type ListenEnd = { reason: \"client\" } | { reason: \"server\" } | { reason: \"error\"; error: unknown }\n\n/** ack 를 받은 subscriptions/listen 스트림 */\nexport interface RemoteListen {\n /** ack (notifications/subscriptions/acknowledged) 의 notifications. ack 없이 완료 = {} */\n readonly acknowledged: Record<string, unknown>\n /** 스트림 종료 (reject 하지 않는다) */\n readonly done: Promise<ListenEnd>\n close(): void\n}\n\nexport interface RemoteClient {\n readonly url: string\n request(method: string, params?: Record<string, unknown>, options?: RequestOptions): Promise<Record<string, unknown>>\n /**\n * subscriptions/listen. ack 까지 기다린 뒤 스트림을 계속 읽는다 (알림 = onNotification).\n * ack 전 실패 = reject (401 · JSON-RPC 오류 · 연결 실패 · ack 전 abort = signal.reason)\n */\n listen(notifications: Record<string, unknown>, options?: RequestOptions): Promise<RemoteListen>\n listTools(options?: RequestOptions): Promise<RemoteTool[]>\n listToolsResult(options?: RequestOptions): Promise<ToolsListResult>\n callTool(tool: RemoteTool, args: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult>\n /** tasks/get (Mcp-Name = taskId) */\n getTask(taskId: string, options?: RequestOptions): Promise<Record<string, unknown>>\n /** tasks/update { taskId, inputResponses } */\n updateTask(taskId: string, inputResponses: InputResponses, options?: RequestOptions): Promise<void>\n /** tasks/cancel { taskId } */\n cancelTask(taskId: string, options?: RequestOptions): Promise<void>\n}\n\nexport function createRemoteClient(options: RemoteClientOptions): RemoteClient {\n const doFetch = options.fetch ?? fetch\n const clientInfo = options.clientInfo ?? { name: \"mext\", version: VERSION }\n let nextId = 1\n\n /** POST 1회. 401 = RemoteUnauthorizedError. 응답 본문은 호출자가 읽는다 */\n const send = async (\n method: string,\n params: Record<string, unknown>,\n opts: RequestOptions,\n extraHeaders: Record<string, string>,\n ): Promise<{ res: Response; id: number }> => {\n const id = nextId++\n const meta: Record<string, unknown> = {\n ...(isRecord(params._meta) ? params._meta : {}),\n [META_KEYS.protocolVersion]: PROTOCOL_VERSION,\n [META_KEYS.clientInfo]: clientInfo,\n [META_KEYS.clientCapabilities]: CLIENT_CAPABILITIES,\n }\n if (opts.progressToken !== undefined) meta.progressToken = opts.progressToken\n const body = { jsonrpc: \"2.0\", id, method, params: { ...params, _meta: meta } }\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json, text/event-stream\",\n \"MCP-Protocol-Version\": PROTOCOL_VERSION,\n \"Mcp-Method\": method,\n ...extraHeaders,\n }\n const token = await options.token?.()\n if (token) headers.Authorization = `Bearer ${token}`\n\n let res: Response\n try {\n res = await doFetch(options.url, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...(opts.signal ? { signal: opts.signal } : {}),\n })\n } catch (error) {\n if (opts.signal?.aborted) throw error\n throw new RemoteTransportError(`Cannot reach ${options.url}: ${errorMessage(error)}`, { cause: error })\n }\n\n if (res.status === 401) {\n const payload = await readJson(res)\n const err = isRecord(payload) && isRecord(payload.error) ? payload.error : {}\n throw new RemoteUnauthorizedError(\n typeof err.message === \"string\" ? err.message : \"Authentication required.\",\n parseBearerChallenge(res.headers.get(\"www-authenticate\")),\n err.data,\n )\n }\n return { res, id }\n }\n\n const request = async (\n method: string,\n params: Record<string, unknown> = {},\n opts: RequestOptions = {},\n extraHeaders: Record<string, string> = {},\n ): Promise<Record<string, unknown>> => {\n const { res, id } = await send(method, params, opts, extraHeaders)\n if (isEventStream(res)) {\n return handleMessage(await readSse(res, id, opts), id, res.status)\n }\n return handleMessage(await jsonMessage(res), id, res.status)\n }\n\n const jsonMessage = async (res: Response): Promise<unknown> => {\n const payload = await readJson(res)\n if (payload === undefined) {\n throw new RemoteTransportError(`${options.url} returned HTTP ${res.status} without a JSON-RPC response.`)\n }\n return payload\n }\n\n const listen = async (notifications: Record<string, unknown>, opts: RequestOptions = {}): Promise<RemoteListen> => {\n const { signal } = opts\n signal?.throwIfAborted()\n const { res, id } = await send(\"subscriptions/listen\", { notifications }, opts, {})\n if (!isEventStream(res)) {\n // JSON 응답 = 오류 (handleMessage 가 던진다) 또는 ack 없는 완료\n handleMessage(await jsonMessage(res), id, res.status)\n return { acknowledged: {}, done: Promise.resolve({ reason: \"server\" }), close() {} }\n }\n const stream = sseStream(res)\n let closed = false\n const close = (): void => {\n if (closed) return\n closed = true\n void stream.cancel()\n }\n signal?.addEventListener(\"abort\", close, { once: true })\n const notify = (message: Record<string, unknown>): void => {\n try {\n opts.onNotification?.(message.method as string, isRecord(message.params) ? message.params : {})\n } catch {\n // 수신자 예외는 스트림에 영향 없음\n }\n }\n\n // ack 까지. 그 전의 완료 result = ack 없는 완료, 오류 = reject\n let acknowledged: Record<string, unknown> | undefined\n try {\n while (acknowledged === undefined) {\n const message = await stream.next()\n if (message === undefined) throw new RemoteTransportError(\"Event stream ended before subscriptions/listen was acknowledged.\")\n if (message.method === \"notifications/subscriptions/acknowledged\") {\n const params = isRecord(message.params) ? message.params : {}\n acknowledged = isRecord(params.notifications) ? params.notifications : {}\n } else if (isNotification(message)) notify(message)\n else if (message.id === id) {\n handleMessage(message, id, res.status)\n signal?.removeEventListener(\"abort\", close)\n await stream.cancel()\n return { acknowledged: {}, done: Promise.resolve({ reason: \"server\" }), close() {} }\n }\n }\n } catch (error) {\n signal?.removeEventListener(\"abort\", close)\n await stream.cancel()\n if (signal?.aborted) throw signal.reason\n throw error\n }\n\n const done = (async (): Promise<ListenEnd> => {\n try {\n for (;;) {\n let message: Record<string, unknown> | undefined\n try {\n message = await stream.next()\n } catch (error) {\n return closed ? { reason: \"client\" } : { reason: \"error\", error }\n }\n if (closed) return { reason: \"client\" }\n if (message === undefined) return { reason: \"server\" }\n if (isNotification(message)) notify(message)\n else if (message.id === id) {\n try {\n handleMessage(message, id, res.status)\n return { reason: \"server\" }\n } catch (error) {\n return { reason: \"error\", error }\n }\n }\n }\n } finally {\n signal?.removeEventListener(\"abort\", close)\n await stream.cancel()\n }\n })()\n return { acknowledged, done, close }\n }\n\n const handleMessage = (message: unknown, id: number, status: number): Record<string, unknown> => {\n if (!isRecord(message)) throw new RemoteTransportError(`Invalid JSON-RPC response (HTTP ${status}).`)\n if (isRecord(message.error)) {\n const e = message.error\n throw new RemoteRpcError(\n typeof e.message === \"string\" ? e.message : \"JSON-RPC error\",\n typeof e.code === \"number\" ? e.code : -32_603,\n e.data,\n status,\n )\n }\n if (message.id !== id || !isRecord(message.result)) {\n throw new RemoteTransportError(`Invalid JSON-RPC response (HTTP ${status}).`)\n }\n return message.result\n }\n\n const listToolsResult = async (opts: RequestOptions = {}): Promise<ToolsListResult> => {\n const tools: RemoteTool[] = []\n const out: ToolsListResult = { tools }\n let cursor: string | undefined\n for (let page = 0; page < 100; page++) {\n const result = await request(\"tools/list\", cursor === undefined ? {} : { cursor }, opts)\n if (page === 0) {\n if (typeof result.ttlMs === \"number\" && Number.isFinite(result.ttlMs) && result.ttlMs >= 0) out.ttlMs = result.ttlMs\n if (typeof result.cacheScope === \"string\") out.cacheScope = result.cacheScope\n }\n if (Array.isArray(result.tools)) {\n for (const t of result.tools) if (isRecord(t) && typeof t.name === \"string\") tools.push(t as unknown as RemoteTool)\n }\n if (typeof result.nextCursor !== \"string\" || result.nextCursor === \"\") break\n cursor = result.nextCursor\n }\n return out\n }\n\n const callTool = async (\n tool: RemoteTool,\n args: Record<string, unknown>,\n opts: CallToolOptions = {},\n ): Promise<CallToolResult> => {\n const headers: Record<string, string> = { \"Mcp-Name\": tool.name, ...paramHeaders(tool, args) }\n let retry: { inputResponses?: InputResponses; requestState?: string } = {}\n const meta = opts.meta ? { _meta: opts.meta } : {}\n for (let round = 0; ; round++) {\n const result = await request(\"tools/call\", { name: tool.name, arguments: args, ...retry, ...meta }, opts, headers)\n if (result.resultType !== \"input_required\") return result as CallToolResult\n const required: InputRequired = {}\n if (isRecord(result.inputRequests)) required.inputRequests = result.inputRequests as InputRequired[\"inputRequests\"]\n if (typeof result.requestState === \"string\") required.requestState = result.requestState\n if (!opts.onInputRequired) throw new RemoteInputRequiredError(`${tool.name} requires input.`, required)\n if (round >= MAX_INPUT_ROUNDS) {\n throw new RemoteInputRequiredError(`${tool.name} still required input after ${MAX_INPUT_ROUNDS} rounds.`, required)\n }\n // 요청이 있으면 응답을 만든 뒤 재시도. requestState 는 그대로 되돌려 보내고, 없으면 보내지 않는다\n const responses = required.inputRequests ? await opts.onInputRequired(required, round) : undefined\n retry = {}\n if (responses !== undefined) retry.inputResponses = responses\n if (required.requestState !== undefined) retry.requestState = required.requestState\n }\n }\n\n /** tasks/* = Mcp-Name 헤더 = taskId (SDK 검증, 없으면 400) */\n const taskRequest = (method: string, taskId: string, params: Record<string, unknown>, opts: RequestOptions = {}) =>\n request(method, { taskId, ...params }, opts, { \"Mcp-Name\": taskId })\n\n return {\n url: options.url,\n request: (method, params, opts) => request(method, params, opts),\n listen,\n listTools: async (opts) => (await listToolsResult(opts)).tools,\n listToolsResult,\n callTool,\n getTask: (taskId, opts) => taskRequest(\"tasks/get\", taskId, {}, opts),\n updateTask: async (taskId, inputResponses, opts) => {\n await taskRequest(\"tasks/update\", taskId, { inputResponses }, opts)\n },\n cancelTask: async (taskId, opts) => {\n await taskRequest(\"tasks/cancel\", taskId, {}, opts)\n },\n }\n}\n\n/** inputSchema 의 x-mcp-header 속성 → Mcp-Param-<Name> 헤더 (SEP-2243). 문자열 · 숫자 · boolean 값만 */\nfunction paramHeaders(tool: RemoteTool, args: Record<string, unknown>): Record<string, string> {\n const props = tool.inputSchema?.properties\n if (!isRecord(props)) return {}\n const out: Record<string, string> = {}\n for (const [key, schema] of Object.entries(props)) {\n if (!isRecord(schema) || typeof schema[\"x-mcp-header\"] !== \"string\") continue\n const value = args[key]\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n out[`Mcp-Param-${schema[\"x-mcp-header\"]}`] = String(value)\n }\n }\n return out\n}\n\n/* SSE */\n\nfunction isEventStream(res: Response): boolean {\n return (res.headers.get(\"content-type\") ?? \"\").includes(\"text/event-stream\")\n}\n\nfunction isNotification(message: Record<string, unknown>): boolean {\n return typeof message.method === \"string\" && message.id === undefined\n}\n\n/** 응답 스트림에서 id 의 응답 메시지가 올 때까지 읽는다. 알림은 콜백, 응답 후 스트림을 닫는다 */\nasync function readSse(res: Response, id: number, opts: RequestOptions): Promise<unknown> {\n const stream = sseStream(res)\n try {\n for (let message = await stream.next(); message !== undefined; message = await stream.next()) {\n if (isNotification(message)) {\n try {\n opts.onNotification?.(message.method as string, isRecord(message.params) ? message.params : {})\n } catch {\n // 표시 오류는 응답에 영향 없음\n }\n continue\n }\n if (message.id === id && (\"result\" in message || \"error\" in message)) return message\n }\n } finally {\n await stream.cancel()\n }\n if (opts.signal?.aborted) throw opts.signal.reason\n throw new RemoteTransportError(\"Event stream ended without a response.\")\n}\n\ninterface SseStream {\n /** 다음 JSON 객체 메시지 (data 이벤트 1개, JSON 이 아닌 data 는 건너뛴다). 끝 = undefined */\n next(): Promise<Record<string, unknown> | undefined>\n /** 읽기 중단 (진행 중 next = undefined). 여러 번 불러도 된다 */\n cancel(): Promise<void>\n}\n\nfunction sseStream(res: Response): SseStream {\n if (!res.body) throw new RemoteTransportError(\"Empty event stream.\")\n const reader = res.body.pipeThrough(new TextDecoderStream()).getReader()\n let buffer = \"\"\n let data: string[] = []\n let ended = false\n const dispatch = (): Record<string, unknown> | undefined => {\n if (data.length === 0) return undefined\n const text = data.join(\"\\n\")\n data = []\n try {\n const message: unknown = JSON.parse(text)\n return isRecord(message) ? message : undefined\n } catch {\n return undefined\n }\n }\n /** buffer 의 완성된 줄을 처리. 이벤트 경계에서 메시지가 나오면 그 메시지 */\n const drain = (): Record<string, unknown> | undefined => {\n let nl: number\n while ((nl = buffer.search(/\\r\\n|\\r|\\n/)) >= 0) {\n const line = buffer.slice(0, nl)\n buffer = buffer.slice(nl + (buffer.startsWith(\"\\r\\n\", nl) ? 2 : 1))\n if (line === \"\") {\n const found = dispatch()\n if (found !== undefined) return found\n continue\n }\n if (line.startsWith(\":\")) continue\n const colon = line.indexOf(\":\")\n const field = colon < 0 ? line : line.slice(0, colon)\n let value = colon < 0 ? \"\" : line.slice(colon + 1)\n if (value.startsWith(\" \")) value = value.slice(1)\n if (field === \"data\") data.push(value)\n }\n return undefined\n }\n return {\n async next() {\n for (;;) {\n const found = drain()\n if (found !== undefined) return found\n if (ended) return undefined\n const { done, value } = await reader.read()\n if (done) {\n ended = true\n return dispatch()\n }\n buffer += value\n }\n },\n async cancel() {\n ended = true\n buffer = \"\"\n data = []\n await reader.cancel().catch(() => {})\n },\n }\n}\n\nasync function readJson(res: Response): Promise<unknown> {\n const text = await res.text().catch(() => \"\")\n if (text === \"\") return undefined\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n\n/* WWW-Authenticate */\n\nexport interface BearerChallenge {\n /** Bearer challenge 가 있었는지 */\n bearer: boolean\n error?: string\n scope?: string\n resourceMetadata?: string\n}\n\n/** WWW-Authenticate 의 Bearer challenge 파라미터 (RFC 6750 · RFC 9728 resource_metadata) */\nexport function parseBearerChallenge(header: string | null): BearerChallenge {\n if (!header) return { bearer: false }\n const m = /(?:^|,\\s*)Bearer\\b(.*)$/i.exec(header)\n if (!m) return { bearer: false }\n const params: Record<string, string> = {}\n const re = /([A-Za-z_][\\w-]*)\\s*=\\s*(?:\"((?:[^\"\\\\]|\\\\.)*)\"|([^\\s,]+))/g\n for (let p = re.exec(m[1]!); p !== null; p = re.exec(m[1]!)) {\n params[p[1]!.toLowerCase()] = p[2] !== undefined ? p[2].replace(/\\\\(.)/g, \"$1\") : p[3]!\n }\n const out: BearerChallenge = { bearer: true }\n if (params.error !== undefined) out.error = params.error\n if (params.scope !== undefined) out.scope = params.scope\n if (params.resource_metadata !== undefined) out.resourceMetadata = params.resource_metadata\n return out\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n const cause = (error as { cause?: unknown }).cause\n return cause instanceof Error && cause.message ? cause.message : error.message\n }\n return String(error)\n}\n"]}
|
package/dist/remote/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { CLIENT_CAPABILITIES, createRemoteClient, MAX_INPUT_ROUNDS, parseBearerChallenge, PROTOCOL_VERSION, RemoteInputRequiredError, RemoteRpcError, RemoteTransportError, RemoteUnauthorizedError, } from "./client.ts";
|
|
2
|
-
export type { BearerChallenge, CallToolOptions, CallToolResult, InputRequestObject, InputRequired, InputResponses, RemoteClient, RemoteClientOptions, RemoteTool, ToolsListResult, RequestOptions, } from "./client.ts";
|
|
2
|
+
export type { BearerChallenge, CallToolOptions, CallToolResult, InputRequestObject, InputRequired, InputResponses, ListenEnd, RemoteClient, RemoteListen, RemoteClientOptions, RemoteTool, ToolsListResult, RequestOptions, } from "./client.ts";
|
|
3
3
|
export { browserDecision, systemBrowserOpener } from "./browser.ts";
|
|
4
4
|
export type { BrowserDecision, BrowserOpener } from "./browser.ts";
|
|
5
5
|
export { canonicalServerUrl, credentialStore, envFlag, envPrefix, fileStore } from "./credentials.ts";
|
package/dist/remote/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/remote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/remote/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,wBAAwB,EACxB,cAAc,EACd,oBAAoB,EACpB,uBAAuB,GACxB,MAAM,aAAa,CAAA;AAgBpB,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAEnE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAA;AAErG,OAAO,EACL,sBAAsB,EACtB,+BAA+B,EAC/B,iBAAiB,EACjB,WAAW,EACX,2BAA2B,EAC3B,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,EACL,cAAc,EACd,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,YAAY,CAAA","sourcesContent":["export {\n CLIENT_CAPABILITIES,\n createRemoteClient,\n MAX_INPUT_ROUNDS,\n parseBearerChallenge,\n PROTOCOL_VERSION,\n RemoteInputRequiredError,\n RemoteRpcError,\n RemoteTransportError,\n RemoteUnauthorizedError,\n} from \"./client.ts\"\nexport type {\n BearerChallenge,\n CallToolOptions,\n CallToolResult,\n InputRequestObject,\n InputRequired,\n InputResponses,\n ListenEnd,\n RemoteClient,\n RemoteListen,\n RemoteClientOptions,\n RemoteTool,\n ToolsListResult,\n RequestOptions,\n} from \"./client.ts\"\nexport { browserDecision, systemBrowserOpener } from \"./browser.ts\"\nexport type { BrowserDecision, BrowserOpener } from \"./browser.ts\"\nexport { canonicalServerUrl, credentialStore, envFlag, envPrefix, fileStore } from \"./credentials.ts\"\nexport type { CredentialStore, CredentialStoreOptions, StoredCredentials } from \"./credentials.ts\"\nexport {\n authorizationCodeLogin,\n authorizationServerMetadataUrls,\n DEVICE_CODE_GRANT,\n deviceLogin,\n discoverAuthorizationServer,\n discoverLoginTarget,\n discoverProtectedResource,\n login,\n OAuthFlowError,\n parseRedirectUrl,\n protectedResourceMetadataUrls,\n refreshCredentials,\n revokeCredentials,\n} from \"./oauth.ts\"\nexport type {\n AuthorizationCodeLoginOptions,\n AuthorizationServerMetadata,\n DeviceAuthorization,\n DeviceLoginOptions,\n DiscoverLoginOptions,\n LoginOptions,\n LoginTarget,\n ProtectedResourceMetadata,\n RevokeResult,\n} from \"./oauth.ts\"\n"]}
|
package/dist/route.d.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { MextApp } from "./command.ts";
|
|
2
2
|
import { type BuildIssue } from "./errors.ts";
|
|
3
|
+
import type { Principal } from "./principal.ts";
|
|
3
4
|
/**
|
|
4
5
|
* Routes (§12.4): MCP 엔드포인트 밖 HTTP 경로. routes/**\/*.ts 파일 경로 = URL 경로.
|
|
5
|
-
* HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음.
|
|
6
|
+
* HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음.
|
|
7
|
+
* Origin 검사 · auth = 기본 없음. 모듈의 export origin · auth 로 route 마다 켠다 (설정 routes = 모든 route 의 기본값, export 가 덮어씀).
|
|
6
8
|
* Registry 와 별개 집합 (D1): 명령어 계약 (help · tools · manifestHash) 과 공유하는 것이 없다
|
|
7
9
|
*/
|
|
8
10
|
export declare const ROUTE_METHODS: readonly ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
@@ -15,10 +17,40 @@ export interface RouteContext {
|
|
|
15
17
|
signal: AbortSignal;
|
|
16
18
|
/** 자원 갱신 알림 (§12.5). 명령어 ctx.resourceUpdated 와 같음 (state 없음 = no-op) */
|
|
17
19
|
resourceUpdated(uri: string): Promise<void>;
|
|
20
|
+
/** 설정 auth 가 만든 주체. 모듈이 export auth (true · "optional") 를 둔 route 만, 그 외 undefined */
|
|
21
|
+
principal?: Principal;
|
|
18
22
|
}
|
|
19
23
|
/** routes/ 모듈의 GET · POST · PUT · PATCH · DELETE export */
|
|
20
24
|
export type RouteHandler = (request: Request, ctx: RouteContext) => Response | Promise<Response>;
|
|
21
|
-
|
|
25
|
+
/**
|
|
26
|
+
* route 모듈의 선택 export.
|
|
27
|
+
* auth true = 설정 auth 필수 (anonymous · UNAUTHENTICATED = 401), "optional" = anonymous 허용 (UNAUTHENTICATED = 401). 없음 · false = auth 없음
|
|
28
|
+
* origin true = /mcp 와 같은 Origin 규칙 (server.allowedOrigins). 없음 · false = 검사 없음
|
|
29
|
+
* maxBodyBytes 양의 정수 = 본문 상한 (바이트), true = server.maxBodyBytes (기본 4 MiB). 없음 · false = 상한 없음. 넘으면 413
|
|
30
|
+
*/
|
|
31
|
+
export interface RouteOptions {
|
|
32
|
+
auth?: RouteAuth;
|
|
33
|
+
origin?: boolean;
|
|
34
|
+
maxBodyBytes?: number | boolean;
|
|
35
|
+
}
|
|
36
|
+
export type RouteAuth = boolean | "optional";
|
|
37
|
+
export type RouteModule = Partial<Record<RouteMethod, RouteHandler>> & RouteOptions;
|
|
38
|
+
/**
|
|
39
|
+
* route 경계 판정 (mcp/http.ts 가 구현). Response = 그 응답으로 끝 (403 · 401 · 500), 그 외 = 통과
|
|
40
|
+
*/
|
|
41
|
+
export interface RouteGuard {
|
|
42
|
+
/** export origin = true. Origin 헤더가 있고 허용 밖 = 403 */
|
|
43
|
+
origin(request: Request): Response | undefined;
|
|
44
|
+
/** export auth. 반환 Principal = ctx.principal */
|
|
45
|
+
authenticate(request: Request, auth: true | "optional", route: {
|
|
46
|
+
method: RouteMethod;
|
|
47
|
+
path: string;
|
|
48
|
+
}): Promise<Principal | Response>;
|
|
49
|
+
}
|
|
50
|
+
/** export auth · origin · maxBodyBytes 의 형식 문제. 없으면 undefined */
|
|
51
|
+
export declare function routeOptionsProblem(mod: Record<string, unknown>): string | undefined;
|
|
52
|
+
/** 적용 값: export (undefined 가 아니면, false 포함) > 설정 기본값 (routes) > 없음. 키별 독립 */
|
|
53
|
+
export declare function resolveRouteOptions(mod: RouteOptions, defaults: RouteOptions | undefined): RouteOptions;
|
|
22
54
|
export interface ScannedRoute {
|
|
23
55
|
/** URL 경로 패턴. routes/items/[id].ts → "/items/[id]", routes/index.ts → "/" */
|
|
24
56
|
path: string;
|
|
@@ -62,6 +94,12 @@ export interface RouteDispatchOptions {
|
|
|
62
94
|
log?: (line: string) => void;
|
|
63
95
|
/** ctx.resourceUpdated. 기본 = no-op (uri 형식만 검사) */
|
|
64
96
|
resourceUpdated?: (uri: string) => Promise<void>;
|
|
97
|
+
/** export origin · auth 판정 (HTTP 어댑터). 없으면 그 export 를 둔 route = 500 (구성 오류) */
|
|
98
|
+
guard?: RouteGuard;
|
|
99
|
+
/** export maxBodyBytes = true 의 상한 (server.maxBodyBytes). 기본 MAX_BODY_BYTES */
|
|
100
|
+
maxBodyBytes?: number;
|
|
101
|
+
/** 설정 routes: export 가 없는 키의 기본값 */
|
|
102
|
+
defaults?: RouteOptions;
|
|
65
103
|
}
|
|
66
104
|
/**
|
|
67
105
|
* route 처리기. 맞는 route 없음 = undefined (호출자가 404).
|
package/dist/route.js
CHANGED
|
@@ -12,13 +12,78 @@ import { pathToFileURL } from "node:url";
|
|
|
12
12
|
import { MextBuildError } from "./errors.js";
|
|
13
13
|
import { isSegment } from "./ids.js";
|
|
14
14
|
import { assertResourceUri } from "./invoke.js";
|
|
15
|
-
import { MCP_PATH } from "./mcp/constants.js";
|
|
15
|
+
import { MAX_BODY_BYTES, MCP_PATH } from "./mcp/constants.js";
|
|
16
16
|
/**
|
|
17
17
|
* Routes (§12.4): MCP 엔드포인트 밖 HTTP 경로. routes/**\/*.ts 파일 경로 = URL 경로.
|
|
18
|
-
* HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음.
|
|
18
|
+
* HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음.
|
|
19
|
+
* Origin 검사 · auth = 기본 없음. 모듈의 export origin · auth 로 route 마다 켠다 (설정 routes = 모든 route 의 기본값, export 가 덮어씀).
|
|
19
20
|
* Registry 와 별개 집합 (D1): 명령어 계약 (help · tools · manifestHash) 과 공유하는 것이 없다
|
|
20
21
|
*/
|
|
21
22
|
export const ROUTE_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
23
|
+
/** export auth · origin · maxBodyBytes 의 형식 문제. 없으면 undefined */
|
|
24
|
+
export function routeOptionsProblem(mod) {
|
|
25
|
+
if (mod.auth !== undefined && typeof mod.auth !== "boolean" && mod.auth !== "optional") {
|
|
26
|
+
return 'export auth must be true, false or "optional"';
|
|
27
|
+
}
|
|
28
|
+
if (mod.origin !== undefined && typeof mod.origin !== "boolean")
|
|
29
|
+
return "export origin must be a boolean";
|
|
30
|
+
const max = mod.maxBodyBytes;
|
|
31
|
+
if (max !== undefined && typeof max !== "boolean" && !(typeof max === "number" && Number.isSafeInteger(max) && max > 0)) {
|
|
32
|
+
return "export maxBodyBytes must be a positive integer (bytes) or a boolean";
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
/** 적용 값: export (undefined 가 아니면, false 포함) > 설정 기본값 (routes) > 없음. 키별 독립 */
|
|
37
|
+
export function resolveRouteOptions(mod, defaults) {
|
|
38
|
+
const out = {};
|
|
39
|
+
const auth = mod.auth ?? defaults?.auth;
|
|
40
|
+
const origin = mod.origin ?? defaults?.origin;
|
|
41
|
+
const maxBodyBytes = mod.maxBodyBytes ?? defaults?.maxBodyBytes;
|
|
42
|
+
if (auth !== undefined)
|
|
43
|
+
out.auth = auth;
|
|
44
|
+
if (origin !== undefined)
|
|
45
|
+
out.origin = origin;
|
|
46
|
+
if (maxBodyBytes !== undefined)
|
|
47
|
+
out.maxBodyBytes = maxBodyBytes;
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
/** route 본문 상한 초과 응답 (specs/http.md REQUEST_REJECTED too_large 와 같은 모양) */
|
|
51
|
+
function tooLarge(limit) {
|
|
52
|
+
const error = { code: "REQUEST_REJECTED", message: "Request body too large.", reason: "too_large", limit };
|
|
53
|
+
return new Response(JSON.stringify({ error }), { status: 413, headers: { "Content-Type": "application/json" } });
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 본문을 limit 바이트로 제한한 Request. Content-Length 초과 = "too-large" (본문을 읽지 않는다).
|
|
57
|
+
* 스트림이 넘으면 본문 읽기가 실패하고 exceeded() = true
|
|
58
|
+
*/
|
|
59
|
+
function limitBody(request, limit) {
|
|
60
|
+
const declared = Number(request.headers.get("content-length") ?? "");
|
|
61
|
+
if (Number.isFinite(declared) && declared > limit)
|
|
62
|
+
return "too-large";
|
|
63
|
+
if (request.body === null)
|
|
64
|
+
return { request, exceeded: () => false };
|
|
65
|
+
let size = 0;
|
|
66
|
+
let over = false;
|
|
67
|
+
const counted = request.body.pipeThrough(new TransformStream({
|
|
68
|
+
transform(chunk, controller) {
|
|
69
|
+
size += chunk.byteLength;
|
|
70
|
+
if (size > limit) {
|
|
71
|
+
over = true;
|
|
72
|
+
controller.error(new RangeError(`request body exceeds ${limit} bytes`));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
controller.enqueue(chunk);
|
|
76
|
+
},
|
|
77
|
+
}));
|
|
78
|
+
const limited = new Request(request.url, {
|
|
79
|
+
method: request.method,
|
|
80
|
+
headers: request.headers,
|
|
81
|
+
body: counted,
|
|
82
|
+
signal: request.signal,
|
|
83
|
+
duplex: "half",
|
|
84
|
+
});
|
|
85
|
+
return { request: limited, exceeded: () => over };
|
|
86
|
+
}
|
|
22
87
|
/** RFC 9728 well-known 경로 (mcp/http.ts PROTECTED_RESOURCE_METADATA_PATH 와 같음) */
|
|
23
88
|
const PROTECTED_RESOURCE_PREFIX = "/.well-known/oauth-protected-resource";
|
|
24
89
|
const EXCLUDED_SUFFIXES = [".test.ts", ".spec.ts", ".d.ts"];
|
|
@@ -121,6 +186,11 @@ export async function collectRoutes(dir) {
|
|
|
121
186
|
issues.push({ code: "INVALID_ROUTE", message: `no handler export (${ROUTE_METHODS.join(" · ")})`, ...where });
|
|
122
187
|
continue;
|
|
123
188
|
}
|
|
189
|
+
const problem = routeOptionsProblem(mod);
|
|
190
|
+
if (problem !== undefined) {
|
|
191
|
+
issues.push({ code: "INVALID_ROUTE", message: problem, ...where });
|
|
192
|
+
continue;
|
|
193
|
+
}
|
|
124
194
|
routes.push({ ...route, methods, module: mod });
|
|
125
195
|
}
|
|
126
196
|
return { dir: root, routes, issues };
|
|
@@ -216,21 +286,66 @@ export function createRouteDispatcher(options) {
|
|
|
216
286
|
headers: { Allow: allow.join(", "), "Content-Type": "text/plain; charset=utf-8" },
|
|
217
287
|
});
|
|
218
288
|
}
|
|
289
|
+
// export maxBodyBytes 의 스트림 초과 = 핸들러 결과 · 예외와 무관하게 413
|
|
290
|
+
let limited;
|
|
219
291
|
try {
|
|
220
292
|
const mod = await loadModule(route);
|
|
221
293
|
const handler = mod[method];
|
|
222
294
|
if (typeof handler !== "function")
|
|
223
295
|
throw new TypeError(`${route.file ?? route.path}: export ${method} is not a function`);
|
|
224
|
-
|
|
225
|
-
const
|
|
296
|
+
// export origin · maxBodyBytes · auth (§12.4). 순서 = Origin → 본문 상한 → auth → 핸들러
|
|
297
|
+
const problem = routeOptionsProblem(mod);
|
|
298
|
+
if (problem !== undefined)
|
|
299
|
+
throw new TypeError(`${route.file ?? route.path}: ${problem}`);
|
|
300
|
+
const applied = resolveRouteOptions(mod, options.defaults);
|
|
301
|
+
const guard = options.guard;
|
|
302
|
+
if (applied.origin === true) {
|
|
303
|
+
if (!guard)
|
|
304
|
+
throw new TypeError(`${route.file ?? route.path}: export origin needs the HTTP adapter`);
|
|
305
|
+
const rejected = guard.origin(request);
|
|
306
|
+
if (rejected)
|
|
307
|
+
return head ? await withoutBody(rejected) : rejected;
|
|
308
|
+
}
|
|
309
|
+
let input = request;
|
|
310
|
+
if (applied.maxBodyBytes !== undefined && applied.maxBodyBytes !== false) {
|
|
311
|
+
const limit = applied.maxBodyBytes === true ? (options.maxBodyBytes ?? MAX_BODY_BYTES) : applied.maxBodyBytes;
|
|
312
|
+
const body = limitBody(request, limit);
|
|
313
|
+
if (body === "too-large") {
|
|
314
|
+
await request.body?.cancel().catch(() => { });
|
|
315
|
+
return tooLarge(limit);
|
|
316
|
+
}
|
|
317
|
+
input = body.request;
|
|
318
|
+
limited = { exceeded: body.exceeded, limit };
|
|
319
|
+
}
|
|
320
|
+
let principal;
|
|
321
|
+
if (applied.auth === true || applied.auth === "optional") {
|
|
322
|
+
if (!guard)
|
|
323
|
+
throw new TypeError(`${route.file ?? route.path}: export auth needs the HTTP adapter`);
|
|
324
|
+
const result = await guard.authenticate(request, applied.auth, { method, path: route.path });
|
|
325
|
+
if (result instanceof Response)
|
|
326
|
+
return head ? await withoutBody(result) : result;
|
|
327
|
+
principal = result;
|
|
328
|
+
}
|
|
329
|
+
const ctx = {
|
|
330
|
+
params: Object.freeze(params),
|
|
331
|
+
app: await options.app(),
|
|
332
|
+
signal: request.signal,
|
|
333
|
+
resourceUpdated,
|
|
334
|
+
...(principal !== undefined ? { principal } : {}),
|
|
335
|
+
};
|
|
336
|
+
const response = await handler(input, ctx);
|
|
337
|
+
if (limited?.exceeded()) {
|
|
338
|
+
if (response instanceof Response)
|
|
339
|
+
await response.body?.cancel().catch(() => { });
|
|
340
|
+
return tooLarge(limited.limit);
|
|
341
|
+
}
|
|
226
342
|
if (!(response instanceof Response))
|
|
227
343
|
throw new TypeError(`route ${method} ${route.path} did not return a Response`);
|
|
228
|
-
|
|
229
|
-
return response;
|
|
230
|
-
await response.body?.cancel().catch(() => { });
|
|
231
|
-
return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
344
|
+
return head ? await withoutBody(response) : response;
|
|
232
345
|
}
|
|
233
346
|
catch (error) {
|
|
347
|
+
if (limited?.exceeded())
|
|
348
|
+
return tooLarge(limited.limit);
|
|
234
349
|
try {
|
|
235
350
|
log(`route ${request.method} ${route.path}: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`);
|
|
236
351
|
}
|
|
@@ -241,6 +356,11 @@ export function createRouteDispatcher(options) {
|
|
|
241
356
|
}
|
|
242
357
|
};
|
|
243
358
|
}
|
|
359
|
+
/** HEAD 응답: 본문 제거 · 상태 · 헤더 유지 */
|
|
360
|
+
async function withoutBody(response) {
|
|
361
|
+
await response.body?.cancel().catch(() => { });
|
|
362
|
+
return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers });
|
|
363
|
+
}
|
|
244
364
|
/** 앞 세그먼트부터 고정 < 동적 */
|
|
245
365
|
function compareSpecificity(a, b) {
|
|
246
366
|
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
package/dist/route.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, statSync, type Dirent } from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport type { MextApp } from \"./command.ts\"\nimport { MextBuildError, type BuildIssue } from \"./errors.ts\"\nimport { isSegment } from \"./ids.ts\"\nimport { assertResourceUri } from \"./invoke.ts\"\nimport { MCP_PATH } from \"./mcp/constants.ts\"\n\n/**\n * Routes (§12.4): MCP 엔드포인트 밖 HTTP 경로. routes/**\\/*.ts 파일 경로 = URL 경로.\n * HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음. Origin 검사 · auth 대상 아님.\n * Registry 와 별개 집합 (D1): 명령어 계약 (help · tools · manifestHash) 과 공유하는 것이 없다\n */\n\nexport const ROUTE_METHODS = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"] as const\nexport type RouteMethod = (typeof ROUTE_METHODS)[number]\n\nexport interface RouteContext {\n /** [name] 세그먼트 값 (디코딩) */\n params: Readonly<Record<string, string>>\n app: MextApp\n /** 요청 취소 (클라이언트 연결 종료) */\n signal: AbortSignal\n /** 자원 갱신 알림 (§12.5). 명령어 ctx.resourceUpdated 와 같음 (state 없음 = no-op) */\n resourceUpdated(uri: string): Promise<void>\n}\n\n/** routes/ 모듈의 GET · POST · PUT · PATCH · DELETE export */\nexport type RouteHandler = (request: Request, ctx: RouteContext) => Response | Promise<Response>\n\nexport type RouteModule = Partial<Record<RouteMethod, RouteHandler>>\n\nexport interface ScannedRoute {\n /** URL 경로 패턴. routes/items/[id].ts → \"/items/[id]\", routes/index.ts → \"/\" */\n path: string\n /** routes/ 기준 상대 경로 (posix) */\n file: string\n}\n\n/** 실행 가능한 route. eager (loadRoutes) = 모듈 그대로, lazy (manifest) = 처음 요청에서 import */\nexport interface RouteEntry {\n path: string\n file?: string\n /** export 한 메서드 (ROUTE_METHODS 순) */\n methods: readonly RouteMethod[]\n load: () => Promise<RouteModule>\n}\n\n/** RFC 9728 well-known 경로 (mcp/http.ts PROTECTED_RESOURCE_METADATA_PATH 와 같음) */\nconst PROTECTED_RESOURCE_PREFIX = \"/.well-known/oauth-protected-resource\"\nconst EXCLUDED_SUFFIXES = [\".test.ts\", \".spec.ts\", \".d.ts\"]\n/** [name]: ctx.params 의 키 = JS 식별자 */\nconst DYNAMIC_SEGMENT = /^\\[([A-Za-z_][A-Za-z0-9_]*)\\]$/\n\n/**\n * routes/ 파일 트리 해석 (import 없음). 폴더 없음 = route 없음.\n * index.ts = 폴더 경로 · [name] = 동적 · `_` `.` 접두 = private · *.test.ts *.spec.ts *.d.ts 제외 · 그 외 kebab-case.\n * 충돌 (MCP 엔드포인트 · /.well-known/oauth-protected-resource* · 같은 경로) = issue\n */\nexport function walkRoutes(dir: string): { routes: ScannedRoute[]; issues: BuildIssue[] } {\n const root = resolve(dir)\n const routes: ScannedRoute[] = []\n const issues: BuildIssue[] = []\n if (!isDirectory(root)) return { routes, issues }\n\n const visit = (abs: string, segments: string[]): void => {\n const entries = readdirSync(abs, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))\n for (const entry of entries) {\n const name = entry.name\n if (name.startsWith(\"_\") || name.startsWith(\".\")) continue\n const rel = [...segments, name].join(\"/\")\n if (isDirEntry(abs, entry)) {\n if (!isRouteSegment(name)) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `directory \"${name}\" is not kebab-case or [name]`, file: rel })\n continue\n }\n visit(join(abs, name), [...segments, name])\n continue\n }\n if (!name.endsWith(\".ts\") || EXCLUDED_SUFFIXES.some((s) => name.endsWith(s))) continue\n if (!isFileEntry(abs, entry)) continue\n const base = name.slice(0, -\".ts\".length)\n if (base !== \"index\" && !isRouteSegment(base)) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `file \"${name}\" is not kebab-case or [name]`, file: rel })\n continue\n }\n const pathSegments = base === \"index\" ? segments : [...segments, base]\n const path = `/${pathSegments.join(\"/\")}`\n const params = pathSegments.map((s) => DYNAMIC_SEGMENT.exec(s)?.[1]).filter((p): p is string => p !== undefined)\n const repeated = params.find((p, i) => params.indexOf(p) !== i)\n if (repeated !== undefined) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `route ${path}: parameter [${repeated}] appears twice`, file: rel, id: path })\n continue\n }\n routes.push({ path, file: rel })\n }\n }\n visit(root, [])\n\n const accepted: ScannedRoute[] = []\n const seen = new Map<string, ScannedRoute>()\n for (const route of routes) {\n const where = { file: route.file, id: route.path }\n if (route.path === MCP_PATH) {\n issues.push({ code: \"ROUTE_CONFLICT\", message: `route ${route.path} conflicts with the MCP endpoint`, ...where })\n continue\n }\n if (route.path.startsWith(PROTECTED_RESOURCE_PREFIX)) {\n issues.push({ code: \"ROUTE_CONFLICT\", message: `route ${route.path} conflicts with ${PROTECTED_RESOURCE_PREFIX}*`, ...where })\n continue\n }\n // 동적 세그먼트 이름만 다른 경로 (/items/[id] · /items/[slug]) = 같은 경로\n const shape = route.path.replace(/\\[[^\\]/]*\\]/g, \"[]\")\n const prev = seen.get(shape)\n if (prev) {\n issues.push({ code: \"DUPLICATE_ROUTE\", message: `route ${route.path} duplicates ${prev.path} (${prev.file})`, ...where })\n continue\n }\n seen.set(shape, route)\n accepted.push(route)\n }\n return { routes: accepted, issues }\n}\n\n/** walkRoutes + 모듈 import · export 검사의 수집형 (mext build 일괄 검증용). 던지지 않는다 */\nexport async function collectRoutes(\n dir: string,\n): Promise<{ dir: string; routes: (ScannedRoute & { methods: RouteMethod[]; module: RouteModule })[]; issues: BuildIssue[] }> {\n const root = resolve(dir)\n const walked = walkRoutes(root)\n const issues = [...walked.issues]\n const routes: (ScannedRoute & { methods: RouteMethod[]; module: RouteModule })[] = []\n for (const route of walked.routes) {\n const where = { file: route.file, id: route.path }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(join(root, route.file)).href)) as Record<string, unknown>\n } catch (error) {\n issues.push({ code: \"LOAD_FAILED\", message: error instanceof Error ? error.message : String(error), ...where })\n continue\n }\n const bad = ROUTE_METHODS.filter((m) => mod[m] !== undefined && typeof mod[m] !== \"function\")\n if (bad.length > 0) {\n issues.push({ code: \"INVALID_ROUTE\", message: `export ${bad.join(\", \")} must be a function (request, ctx) => Response`, ...where })\n continue\n }\n const methods = ROUTE_METHODS.filter((m) => typeof mod[m] === \"function\")\n if (methods.length === 0) {\n issues.push({ code: \"INVALID_ROUTE\", message: `no handler export (${ROUTE_METHODS.join(\" · \")})`, ...where })\n continue\n }\n routes.push({ ...route, methods, module: mod as RouteModule })\n }\n return { dir: root, routes, issues }\n}\n\n/** 개발 모드 런타임 스캔: routes/ → RouteEntry[] (eager). 규칙 위반 = MextBuildError */\nexport async function loadRoutes(dir: string): Promise<RouteEntry[]> {\n const { routes, issues } = await collectRoutes(dir)\n if (issues.length > 0) throw new MextBuildError(issues)\n return routes.map((r) => ({ path: r.path, file: r.file, methods: r.methods, load: () => Promise.resolve(r.module) }))\n}\n\n/** 처음 호출에서 1회 (실패는 다음 호출에서 재시도) */\nexport function onceApp(factory: (() => MextApp | Promise<MextApp>) | undefined): () => Promise<MextApp> {\n if (!factory) return async () => ({}) as MextApp\n let pending: Promise<MextApp> | undefined\n return () =>\n (pending ??= Promise.resolve()\n .then(factory)\n .catch((error: unknown) => {\n pending = undefined\n throw error\n }))\n}\n\nexport interface RouteDispatchOptions {\n routes: readonly RouteEntry[]\n app: () => Promise<MextApp>\n /** 예외 보고. 기본 console.error (stderr) */\n log?: (line: string) => void\n /** ctx.resourceUpdated. 기본 = no-op (uri 형식만 검사) */\n resourceUpdated?: (uri: string) => Promise<void>\n}\n\n/**\n * route 처리기. 맞는 route 없음 = undefined (호출자가 404).\n * 매칭 = 세그먼트 수가 같고 앞 세그먼트부터 고정이 동적보다 우선. 끝 \"/\" 1개 무시. MCP 엔드포인트 · well-known 은 대상 아님.\n * export 없는 메서드 = 405 (Allow). HEAD = GET 의 본문 제거. 예외 · Response 아닌 반환 = 500 + log (onCommandError 미보고)\n */\nexport function createRouteDispatcher(options: RouteDispatchOptions): (request: Request, url: URL) => Promise<Response | undefined> {\n const log = options.log ?? ((line: string) => console.error(line))\n const resourceUpdated = options.resourceUpdated ?? (async (uri: string) => assertResourceUri(uri))\n const compiled = options.routes\n .map((route) => ({ route, segments: route.path === \"/\" ? [] : route.path.slice(1).split(\"/\") }))\n .map(({ route, segments }) => ({\n route,\n segments: segments.map((s) => ({ literal: DYNAMIC_SEGMENT.exec(s) ? undefined : s, param: DYNAMIC_SEGMENT.exec(s)?.[1] })),\n }))\n .sort((a, b) => compareSpecificity(a.segments, b.segments) || (a.route.path < b.route.path ? -1 : 1))\n // 모듈 로드 1회 캐시 (lazy 실패는 다음 요청에서 재시도)\n const modules = new Map<RouteEntry, Promise<RouteModule>>()\n const loadModule = (route: RouteEntry): Promise<RouteModule> => {\n let pending = modules.get(route)\n if (!pending) {\n pending = route.load().catch((error: unknown) => {\n modules.delete(route)\n throw error\n })\n modules.set(route, pending)\n }\n return pending\n }\n\n const match = (pathname: string): { route: RouteEntry; params: Record<string, string> } | undefined => {\n if (pathname === MCP_PATH || pathname.startsWith(PROTECTED_RESOURCE_PREFIX)) return undefined\n const trimmed = pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname\n const parts = trimmed === \"/\" ? [] : trimmed.slice(1).split(\"/\")\n candidates: for (const { route, segments } of compiled) {\n if (segments.length !== parts.length) continue\n const params: Record<string, string> = {}\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n const seg = segments[i]!\n if (seg.literal !== undefined) {\n if (part !== seg.literal) continue candidates\n continue\n }\n if (part === \"\") continue candidates\n try {\n params[seg.param!] = decodeURIComponent(part)\n } catch {\n continue candidates\n }\n }\n return { route, params }\n }\n return undefined\n }\n\n return async (request, url) => {\n const found = match(url.pathname)\n if (!found) return undefined\n const { route, params } = found\n const head = request.method === \"HEAD\"\n const method = (head ? \"GET\" : request.method) as RouteMethod\n if (!route.methods.includes(method)) {\n const allow = route.methods.includes(\"GET\") ? [...route.methods, \"HEAD\"] : [...route.methods]\n return new Response(\"Method Not Allowed\\n\", {\n status: 405,\n headers: { Allow: allow.join(\", \"), \"Content-Type\": \"text/plain; charset=utf-8\" },\n })\n }\n try {\n const mod = await loadModule(route)\n const handler = mod[method]\n if (typeof handler !== \"function\") throw new TypeError(`${route.file ?? route.path}: export ${method} is not a function`)\n const ctx: RouteContext = { params: Object.freeze(params), app: await options.app(), signal: request.signal, resourceUpdated }\n const response: unknown = await handler(request, ctx)\n if (!(response instanceof Response)) throw new TypeError(`route ${method} ${route.path} did not return a Response`)\n if (!head) return response\n await response.body?.cancel().catch(() => {})\n return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers })\n } catch (error) {\n try {\n log(`route ${request.method} ${route.path}: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n return new Response(\"Internal Server Error\\n\", { status: 500, headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } })\n }\n }\n}\n\n/** 앞 세그먼트부터 고정 < 동적 */\nfunction compareSpecificity(a: readonly { literal?: string }[], b: readonly { literal?: string }[]): number {\n for (let i = 0; i < Math.min(a.length, b.length); i++) {\n const x = a[i]!.literal === undefined ? 1 : 0\n const y = b[i]!.literal === undefined ? 1 : 0\n if (x !== y) return x - y\n }\n return a.length - b.length\n}\n\nfunction isRouteSegment(name: string): boolean {\n return isSegment(name) || DYNAMIC_SEGMENT.test(name)\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n\nfunction isDirEntry(parent: string, entry: Dirent): boolean {\n return entry.isDirectory() || (entry.isSymbolicLink() && isDirectory(join(parent, entry.name)))\n}\n\nfunction isFileEntry(parent: string, entry: Dirent): boolean {\n if (entry.isFile()) return true\n if (!entry.isSymbolicLink()) return false\n try {\n return statSync(join(parent, entry.name)).isFile()\n } catch {\n return false\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"route.js","sourceRoot":"","sources":["../src/route.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdirSync, statSync, type Dirent } from \"node:fs\"\nimport { join, resolve } from \"node:path\"\nimport { pathToFileURL } from \"node:url\"\nimport type { MextApp } from \"./command.ts\"\nimport { MextBuildError, type BuildIssue } from \"./errors.ts\"\nimport { isSegment } from \"./ids.ts\"\nimport { assertResourceUri } from \"./invoke.ts\"\nimport { MAX_BODY_BYTES, MCP_PATH } from \"./mcp/constants.ts\"\nimport type { Principal } from \"./principal.ts\"\n\n/**\n * Routes (§12.4): MCP 엔드포인트 밖 HTTP 경로. routes/**\\/*.ts 파일 경로 = URL 경로.\n * HTTP (dev · start · server.js · handler.js) 전용. stdio · CLI 없음.\n * Origin 검사 · auth = 기본 없음. 모듈의 export origin · auth 로 route 마다 켠다 (설정 routes = 모든 route 의 기본값, export 가 덮어씀).\n * Registry 와 별개 집합 (D1): 명령어 계약 (help · tools · manifestHash) 과 공유하는 것이 없다\n */\n\nexport const ROUTE_METHODS = [\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"] as const\nexport type RouteMethod = (typeof ROUTE_METHODS)[number]\n\nexport interface RouteContext {\n /** [name] 세그먼트 값 (디코딩) */\n params: Readonly<Record<string, string>>\n app: MextApp\n /** 요청 취소 (클라이언트 연결 종료) */\n signal: AbortSignal\n /** 자원 갱신 알림 (§12.5). 명령어 ctx.resourceUpdated 와 같음 (state 없음 = no-op) */\n resourceUpdated(uri: string): Promise<void>\n /** 설정 auth 가 만든 주체. 모듈이 export auth (true · \"optional\") 를 둔 route 만, 그 외 undefined */\n principal?: Principal\n}\n\n/** routes/ 모듈의 GET · POST · PUT · PATCH · DELETE export */\nexport type RouteHandler = (request: Request, ctx: RouteContext) => Response | Promise<Response>\n\n/**\n * route 모듈의 선택 export.\n * auth true = 설정 auth 필수 (anonymous · UNAUTHENTICATED = 401), \"optional\" = anonymous 허용 (UNAUTHENTICATED = 401). 없음 · false = auth 없음\n * origin true = /mcp 와 같은 Origin 규칙 (server.allowedOrigins). 없음 · false = 검사 없음\n * maxBodyBytes 양의 정수 = 본문 상한 (바이트), true = server.maxBodyBytes (기본 4 MiB). 없음 · false = 상한 없음. 넘으면 413\n */\nexport interface RouteOptions {\n auth?: RouteAuth\n origin?: boolean\n maxBodyBytes?: number | boolean\n}\n\nexport type RouteAuth = boolean | \"optional\"\n\nexport type RouteModule = Partial<Record<RouteMethod, RouteHandler>> & RouteOptions\n\n/**\n * route 경계 판정 (mcp/http.ts 가 구현). Response = 그 응답으로 끝 (403 · 401 · 500), 그 외 = 통과\n */\nexport interface RouteGuard {\n /** export origin = true. Origin 헤더가 있고 허용 밖 = 403 */\n origin(request: Request): Response | undefined\n /** export auth. 반환 Principal = ctx.principal */\n authenticate(request: Request, auth: true | \"optional\", route: { method: RouteMethod; path: string }): Promise<Principal | Response>\n}\n\n/** export auth · origin · maxBodyBytes 의 형식 문제. 없으면 undefined */\nexport function routeOptionsProblem(mod: Record<string, unknown>): string | undefined {\n if (mod.auth !== undefined && typeof mod.auth !== \"boolean\" && mod.auth !== \"optional\") {\n return 'export auth must be true, false or \"optional\"'\n }\n if (mod.origin !== undefined && typeof mod.origin !== \"boolean\") return \"export origin must be a boolean\"\n const max = mod.maxBodyBytes\n if (max !== undefined && typeof max !== \"boolean\" && !(typeof max === \"number\" && Number.isSafeInteger(max) && max > 0)) {\n return \"export maxBodyBytes must be a positive integer (bytes) or a boolean\"\n }\n return undefined\n}\n\n/** 적용 값: export (undefined 가 아니면, false 포함) > 설정 기본값 (routes) > 없음. 키별 독립 */\nexport function resolveRouteOptions(mod: RouteOptions, defaults: RouteOptions | undefined): RouteOptions {\n const out: RouteOptions = {}\n const auth = mod.auth ?? defaults?.auth\n const origin = mod.origin ?? defaults?.origin\n const maxBodyBytes = mod.maxBodyBytes ?? defaults?.maxBodyBytes\n if (auth !== undefined) out.auth = auth\n if (origin !== undefined) out.origin = origin\n if (maxBodyBytes !== undefined) out.maxBodyBytes = maxBodyBytes\n return out\n}\n\n/** route 본문 상한 초과 응답 (specs/http.md REQUEST_REJECTED too_large 와 같은 모양) */\nfunction tooLarge(limit: number): Response {\n const error = { code: \"REQUEST_REJECTED\", message: \"Request body too large.\", reason: \"too_large\", limit }\n return new Response(JSON.stringify({ error }), { status: 413, headers: { \"Content-Type\": \"application/json\" } })\n}\n\n/**\n * 본문을 limit 바이트로 제한한 Request. Content-Length 초과 = \"too-large\" (본문을 읽지 않는다).\n * 스트림이 넘으면 본문 읽기가 실패하고 exceeded() = true\n */\nfunction limitBody(request: Request, limit: number): { request: Request; exceeded: () => boolean } | \"too-large\" {\n const declared = Number(request.headers.get(\"content-length\") ?? \"\")\n if (Number.isFinite(declared) && declared > limit) return \"too-large\"\n if (request.body === null) return { request, exceeded: () => false }\n let size = 0\n let over = false\n const counted = request.body.pipeThrough(\n new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n size += chunk.byteLength\n if (size > limit) {\n over = true\n controller.error(new RangeError(`request body exceeds ${limit} bytes`))\n return\n }\n controller.enqueue(chunk)\n },\n }),\n )\n const limited = new Request(request.url, {\n method: request.method,\n headers: request.headers,\n body: counted,\n signal: request.signal,\n duplex: \"half\",\n } as RequestInit)\n return { request: limited, exceeded: () => over }\n}\n\nexport interface ScannedRoute {\n /** URL 경로 패턴. routes/items/[id].ts → \"/items/[id]\", routes/index.ts → \"/\" */\n path: string\n /** routes/ 기준 상대 경로 (posix) */\n file: string\n}\n\n/** 실행 가능한 route. eager (loadRoutes) = 모듈 그대로, lazy (manifest) = 처음 요청에서 import */\nexport interface RouteEntry {\n path: string\n file?: string\n /** export 한 메서드 (ROUTE_METHODS 순) */\n methods: readonly RouteMethod[]\n load: () => Promise<RouteModule>\n}\n\n/** RFC 9728 well-known 경로 (mcp/http.ts PROTECTED_RESOURCE_METADATA_PATH 와 같음) */\nconst PROTECTED_RESOURCE_PREFIX = \"/.well-known/oauth-protected-resource\"\nconst EXCLUDED_SUFFIXES = [\".test.ts\", \".spec.ts\", \".d.ts\"]\n/** [name]: ctx.params 의 키 = JS 식별자 */\nconst DYNAMIC_SEGMENT = /^\\[([A-Za-z_][A-Za-z0-9_]*)\\]$/\n\n/**\n * routes/ 파일 트리 해석 (import 없음). 폴더 없음 = route 없음.\n * index.ts = 폴더 경로 · [name] = 동적 · `_` `.` 접두 = private · *.test.ts *.spec.ts *.d.ts 제외 · 그 외 kebab-case.\n * 충돌 (MCP 엔드포인트 · /.well-known/oauth-protected-resource* · 같은 경로) = issue\n */\nexport function walkRoutes(dir: string): { routes: ScannedRoute[]; issues: BuildIssue[] } {\n const root = resolve(dir)\n const routes: ScannedRoute[] = []\n const issues: BuildIssue[] = []\n if (!isDirectory(root)) return { routes, issues }\n\n const visit = (abs: string, segments: string[]): void => {\n const entries = readdirSync(abs, { withFileTypes: true }).sort((a, b) => (a.name < b.name ? -1 : 1))\n for (const entry of entries) {\n const name = entry.name\n if (name.startsWith(\"_\") || name.startsWith(\".\")) continue\n const rel = [...segments, name].join(\"/\")\n if (isDirEntry(abs, entry)) {\n if (!isRouteSegment(name)) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `directory \"${name}\" is not kebab-case or [name]`, file: rel })\n continue\n }\n visit(join(abs, name), [...segments, name])\n continue\n }\n if (!name.endsWith(\".ts\") || EXCLUDED_SUFFIXES.some((s) => name.endsWith(s))) continue\n if (!isFileEntry(abs, entry)) continue\n const base = name.slice(0, -\".ts\".length)\n if (base !== \"index\" && !isRouteSegment(base)) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `file \"${name}\" is not kebab-case or [name]`, file: rel })\n continue\n }\n const pathSegments = base === \"index\" ? segments : [...segments, base]\n const path = `/${pathSegments.join(\"/\")}`\n const params = pathSegments.map((s) => DYNAMIC_SEGMENT.exec(s)?.[1]).filter((p): p is string => p !== undefined)\n const repeated = params.find((p, i) => params.indexOf(p) !== i)\n if (repeated !== undefined) {\n issues.push({ code: \"INVALID_SEGMENT\", message: `route ${path}: parameter [${repeated}] appears twice`, file: rel, id: path })\n continue\n }\n routes.push({ path, file: rel })\n }\n }\n visit(root, [])\n\n const accepted: ScannedRoute[] = []\n const seen = new Map<string, ScannedRoute>()\n for (const route of routes) {\n const where = { file: route.file, id: route.path }\n if (route.path === MCP_PATH) {\n issues.push({ code: \"ROUTE_CONFLICT\", message: `route ${route.path} conflicts with the MCP endpoint`, ...where })\n continue\n }\n if (route.path.startsWith(PROTECTED_RESOURCE_PREFIX)) {\n issues.push({ code: \"ROUTE_CONFLICT\", message: `route ${route.path} conflicts with ${PROTECTED_RESOURCE_PREFIX}*`, ...where })\n continue\n }\n // 동적 세그먼트 이름만 다른 경로 (/items/[id] · /items/[slug]) = 같은 경로\n const shape = route.path.replace(/\\[[^\\]/]*\\]/g, \"[]\")\n const prev = seen.get(shape)\n if (prev) {\n issues.push({ code: \"DUPLICATE_ROUTE\", message: `route ${route.path} duplicates ${prev.path} (${prev.file})`, ...where })\n continue\n }\n seen.set(shape, route)\n accepted.push(route)\n }\n return { routes: accepted, issues }\n}\n\n/** walkRoutes + 모듈 import · export 검사의 수집형 (mext build 일괄 검증용). 던지지 않는다 */\nexport async function collectRoutes(\n dir: string,\n): Promise<{ dir: string; routes: (ScannedRoute & { methods: RouteMethod[]; module: RouteModule })[]; issues: BuildIssue[] }> {\n const root = resolve(dir)\n const walked = walkRoutes(root)\n const issues = [...walked.issues]\n const routes: (ScannedRoute & { methods: RouteMethod[]; module: RouteModule })[] = []\n for (const route of walked.routes) {\n const where = { file: route.file, id: route.path }\n let mod: Record<string, unknown>\n try {\n mod = (await import(pathToFileURL(join(root, route.file)).href)) as Record<string, unknown>\n } catch (error) {\n issues.push({ code: \"LOAD_FAILED\", message: error instanceof Error ? error.message : String(error), ...where })\n continue\n }\n const bad = ROUTE_METHODS.filter((m) => mod[m] !== undefined && typeof mod[m] !== \"function\")\n if (bad.length > 0) {\n issues.push({ code: \"INVALID_ROUTE\", message: `export ${bad.join(\", \")} must be a function (request, ctx) => Response`, ...where })\n continue\n }\n const methods = ROUTE_METHODS.filter((m) => typeof mod[m] === \"function\")\n if (methods.length === 0) {\n issues.push({ code: \"INVALID_ROUTE\", message: `no handler export (${ROUTE_METHODS.join(\" · \")})`, ...where })\n continue\n }\n const problem = routeOptionsProblem(mod)\n if (problem !== undefined) {\n issues.push({ code: \"INVALID_ROUTE\", message: problem, ...where })\n continue\n }\n routes.push({ ...route, methods, module: mod as RouteModule })\n }\n return { dir: root, routes, issues }\n}\n\n/** 개발 모드 런타임 스캔: routes/ → RouteEntry[] (eager). 규칙 위반 = MextBuildError */\nexport async function loadRoutes(dir: string): Promise<RouteEntry[]> {\n const { routes, issues } = await collectRoutes(dir)\n if (issues.length > 0) throw new MextBuildError(issues)\n return routes.map((r) => ({ path: r.path, file: r.file, methods: r.methods, load: () => Promise.resolve(r.module) }))\n}\n\n/** 처음 호출에서 1회 (실패는 다음 호출에서 재시도) */\nexport function onceApp(factory: (() => MextApp | Promise<MextApp>) | undefined): () => Promise<MextApp> {\n if (!factory) return async () => ({}) as MextApp\n let pending: Promise<MextApp> | undefined\n return () =>\n (pending ??= Promise.resolve()\n .then(factory)\n .catch((error: unknown) => {\n pending = undefined\n throw error\n }))\n}\n\nexport interface RouteDispatchOptions {\n routes: readonly RouteEntry[]\n app: () => Promise<MextApp>\n /** 예외 보고. 기본 console.error (stderr) */\n log?: (line: string) => void\n /** ctx.resourceUpdated. 기본 = no-op (uri 형식만 검사) */\n resourceUpdated?: (uri: string) => Promise<void>\n /** export origin · auth 판정 (HTTP 어댑터). 없으면 그 export 를 둔 route = 500 (구성 오류) */\n guard?: RouteGuard\n /** export maxBodyBytes = true 의 상한 (server.maxBodyBytes). 기본 MAX_BODY_BYTES */\n maxBodyBytes?: number\n /** 설정 routes: export 가 없는 키의 기본값 */\n defaults?: RouteOptions\n}\n\n/**\n * route 처리기. 맞는 route 없음 = undefined (호출자가 404).\n * 매칭 = 세그먼트 수가 같고 앞 세그먼트부터 고정이 동적보다 우선. 끝 \"/\" 1개 무시. MCP 엔드포인트 · well-known 은 대상 아님.\n * export 없는 메서드 = 405 (Allow). HEAD = GET 의 본문 제거. 예외 · Response 아닌 반환 = 500 + log (onCommandError 미보고)\n */\nexport function createRouteDispatcher(options: RouteDispatchOptions): (request: Request, url: URL) => Promise<Response | undefined> {\n const log = options.log ?? ((line: string) => console.error(line))\n const resourceUpdated = options.resourceUpdated ?? (async (uri: string) => assertResourceUri(uri))\n const compiled = options.routes\n .map((route) => ({ route, segments: route.path === \"/\" ? [] : route.path.slice(1).split(\"/\") }))\n .map(({ route, segments }) => ({\n route,\n segments: segments.map((s) => ({ literal: DYNAMIC_SEGMENT.exec(s) ? undefined : s, param: DYNAMIC_SEGMENT.exec(s)?.[1] })),\n }))\n .sort((a, b) => compareSpecificity(a.segments, b.segments) || (a.route.path < b.route.path ? -1 : 1))\n // 모듈 로드 1회 캐시 (lazy 실패는 다음 요청에서 재시도)\n const modules = new Map<RouteEntry, Promise<RouteModule>>()\n const loadModule = (route: RouteEntry): Promise<RouteModule> => {\n let pending = modules.get(route)\n if (!pending) {\n pending = route.load().catch((error: unknown) => {\n modules.delete(route)\n throw error\n })\n modules.set(route, pending)\n }\n return pending\n }\n\n const match = (pathname: string): { route: RouteEntry; params: Record<string, string> } | undefined => {\n if (pathname === MCP_PATH || pathname.startsWith(PROTECTED_RESOURCE_PREFIX)) return undefined\n const trimmed = pathname.length > 1 && pathname.endsWith(\"/\") ? pathname.slice(0, -1) : pathname\n const parts = trimmed === \"/\" ? [] : trimmed.slice(1).split(\"/\")\n candidates: for (const { route, segments } of compiled) {\n if (segments.length !== parts.length) continue\n const params: Record<string, string> = {}\n for (let i = 0; i < parts.length; i++) {\n const part = parts[i]!\n const seg = segments[i]!\n if (seg.literal !== undefined) {\n if (part !== seg.literal) continue candidates\n continue\n }\n if (part === \"\") continue candidates\n try {\n params[seg.param!] = decodeURIComponent(part)\n } catch {\n continue candidates\n }\n }\n return { route, params }\n }\n return undefined\n }\n\n return async (request, url) => {\n const found = match(url.pathname)\n if (!found) return undefined\n const { route, params } = found\n const head = request.method === \"HEAD\"\n const method = (head ? \"GET\" : request.method) as RouteMethod\n if (!route.methods.includes(method)) {\n const allow = route.methods.includes(\"GET\") ? [...route.methods, \"HEAD\"] : [...route.methods]\n return new Response(\"Method Not Allowed\\n\", {\n status: 405,\n headers: { Allow: allow.join(\", \"), \"Content-Type\": \"text/plain; charset=utf-8\" },\n })\n }\n // export maxBodyBytes 의 스트림 초과 = 핸들러 결과 · 예외와 무관하게 413\n let limited: { exceeded: () => boolean; limit: number } | undefined\n try {\n const mod = await loadModule(route)\n const handler = mod[method]\n if (typeof handler !== \"function\") throw new TypeError(`${route.file ?? route.path}: export ${method} is not a function`)\n // export origin · maxBodyBytes · auth (§12.4). 순서 = Origin → 본문 상한 → auth → 핸들러\n const problem = routeOptionsProblem(mod as Record<string, unknown>)\n if (problem !== undefined) throw new TypeError(`${route.file ?? route.path}: ${problem}`)\n const applied = resolveRouteOptions(mod, options.defaults)\n const guard = options.guard\n if (applied.origin === true) {\n if (!guard) throw new TypeError(`${route.file ?? route.path}: export origin needs the HTTP adapter`)\n const rejected = guard.origin(request)\n if (rejected) return head ? await withoutBody(rejected) : rejected\n }\n let input = request\n if (applied.maxBodyBytes !== undefined && applied.maxBodyBytes !== false) {\n const limit = applied.maxBodyBytes === true ? (options.maxBodyBytes ?? MAX_BODY_BYTES) : applied.maxBodyBytes\n const body = limitBody(request, limit)\n if (body === \"too-large\") {\n await request.body?.cancel().catch(() => {})\n return tooLarge(limit)\n }\n input = body.request\n limited = { exceeded: body.exceeded, limit }\n }\n let principal: Principal | undefined\n if (applied.auth === true || applied.auth === \"optional\") {\n if (!guard) throw new TypeError(`${route.file ?? route.path}: export auth needs the HTTP adapter`)\n const result = await guard.authenticate(request, applied.auth, { method, path: route.path })\n if (result instanceof Response) return head ? await withoutBody(result) : result\n principal = result\n }\n const ctx: RouteContext = {\n params: Object.freeze(params),\n app: await options.app(),\n signal: request.signal,\n resourceUpdated,\n ...(principal !== undefined ? { principal } : {}),\n }\n const response: unknown = await handler(input, ctx)\n if (limited?.exceeded()) {\n if (response instanceof Response) await response.body?.cancel().catch(() => {})\n return tooLarge(limited.limit)\n }\n if (!(response instanceof Response)) throw new TypeError(`route ${method} ${route.path} did not return a Response`)\n return head ? await withoutBody(response) : response\n } catch (error) {\n if (limited?.exceeded()) return tooLarge(limited.limit)\n try {\n log(`route ${request.method} ${route.path}: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`)\n } catch {\n // 보고는 응답을 바꾸지 않는다\n }\n return new Response(\"Internal Server Error\\n\", { status: 500, headers: { \"Content-Type\": \"text/plain; charset=utf-8\" } })\n }\n }\n}\n\n/** HEAD 응답: 본문 제거 · 상태 · 헤더 유지 */\nasync function withoutBody(response: Response): Promise<Response> {\n await response.body?.cancel().catch(() => {})\n return new Response(null, { status: response.status, statusText: response.statusText, headers: response.headers })\n}\n\n/** 앞 세그먼트부터 고정 < 동적 */\nfunction compareSpecificity(a: readonly { literal?: string }[], b: readonly { literal?: string }[]): number {\n for (let i = 0; i < Math.min(a.length, b.length); i++) {\n const x = a[i]!.literal === undefined ? 1 : 0\n const y = b[i]!.literal === undefined ? 1 : 0\n if (x !== y) return x - y\n }\n return a.length - b.length\n}\n\nfunction isRouteSegment(name: string): boolean {\n return isSegment(name) || DYNAMIC_SEGMENT.test(name)\n}\n\nfunction isDirectory(path: string): boolean {\n try {\n return statSync(path).isDirectory()\n } catch {\n return false\n }\n}\n\nfunction isDirEntry(parent: string, entry: Dirent): boolean {\n return entry.isDirectory() || (entry.isSymbolicLink() && isDirectory(join(parent, entry.name)))\n}\n\nfunction isFileEntry(parent: string, entry: Dirent): boolean {\n if (entry.isFile()) return true\n if (!entry.isSymbolicLink()) return false\n try {\n return statSync(join(parent, entry.name)).isFile()\n } catch {\n return false\n }\n}\n"]}
|