@meekojs/meeko 0.0.4 → 0.1.0

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.
Files changed (139) hide show
  1. package/README.md +21 -19
  2. package/dist/autoimports-ts.d.ts +4 -4
  3. package/dist/autoimports-ts.js +86 -30
  4. package/dist/autoimports-ts.js.map +1 -1
  5. package/dist/autoimports.d.ts +2 -2
  6. package/dist/autoimports.js +23 -7
  7. package/dist/autoimports.js.map +1 -1
  8. package/dist/check.js +39 -10
  9. package/dist/check.js.map +1 -1
  10. package/dist/cli.js +37 -4
  11. package/dist/cli.js.map +1 -1
  12. package/dist/compiler/events.d.ts +2 -0
  13. package/dist/compiler/events.js +6 -0
  14. package/dist/compiler/events.js.map +1 -0
  15. package/dist/compiler/props.d.ts +12 -0
  16. package/dist/compiler/props.js +32 -0
  17. package/dist/compiler/props.js.map +1 -0
  18. package/dist/compiler.js +55 -12
  19. package/dist/compiler.js.map +1 -1
  20. package/dist/component-errors.d.ts +18 -0
  21. package/dist/component-errors.js +65 -0
  22. package/dist/component-errors.js.map +1 -0
  23. package/dist/devtools.js +2 -4
  24. package/dist/devtools.js.map +1 -1
  25. package/dist/dom.d.ts +11 -5
  26. package/dist/dom.js +288 -88
  27. package/dist/dom.js.map +1 -1
  28. package/dist/error-observer.d.ts +6 -0
  29. package/dist/error-observer.js +41 -0
  30. package/dist/error-observer.js.map +1 -0
  31. package/dist/framework/check-app.js +160 -5
  32. package/dist/framework/check-app.js.map +1 -1
  33. package/dist/framework/check-project.d.ts +4 -0
  34. package/dist/framework/check-project.js +42 -0
  35. package/dist/framework/check-project.js.map +1 -0
  36. package/dist/framework/client.d.ts +3 -0
  37. package/dist/framework/client.js +136 -33
  38. package/dist/framework/client.js.map +1 -1
  39. package/dist/framework/clients.js +12 -4
  40. package/dist/framework/clients.js.map +1 -1
  41. package/dist/framework/contracts-generate.js +66 -3
  42. package/dist/framework/contracts-generate.js.map +1 -1
  43. package/dist/framework/init.js +21 -200
  44. package/dist/framework/init.js.map +1 -1
  45. package/dist/framework/middleware.d.ts +14 -0
  46. package/dist/framework/middleware.js +16 -0
  47. package/dist/framework/middleware.js.map +1 -0
  48. package/dist/framework/page-contracts-check.d.ts +8 -0
  49. package/dist/framework/page-contracts-check.js +110 -0
  50. package/dist/framework/page-contracts-check.js.map +1 -0
  51. package/dist/framework/page-contracts-generate.d.ts +2 -0
  52. package/dist/framework/page-contracts-generate.js +94 -0
  53. package/dist/framework/page-contracts-generate.js.map +1 -0
  54. package/dist/framework/page.d.ts +7 -3
  55. package/dist/framework/page.js +3 -1
  56. package/dist/framework/page.js.map +1 -1
  57. package/dist/framework/prerender.js +11 -5
  58. package/dist/framework/prerender.js.map +1 -1
  59. package/dist/framework/project-templates.d.ts +3 -0
  60. package/dist/framework/project-templates.js +119 -0
  61. package/dist/framework/project-templates.js.map +1 -0
  62. package/dist/framework/project.d.ts +9 -0
  63. package/dist/framework/project.js +272 -0
  64. package/dist/framework/project.js.map +1 -0
  65. package/dist/framework/router.d.ts +3 -1
  66. package/dist/framework/router.js +94 -8
  67. package/dist/framework/router.js.map +1 -1
  68. package/dist/framework/server.d.ts +17 -3
  69. package/dist/framework/server.js +71 -24
  70. package/dist/framework/server.js.map +1 -1
  71. package/dist/framework/socket-contracts-generate.js +8 -5
  72. package/dist/framework/socket-contracts-generate.js.map +1 -1
  73. package/dist/framework/socket.d.ts +2 -0
  74. package/dist/framework/socket.js +119 -17
  75. package/dist/framework/socket.js.map +1 -1
  76. package/dist/framework/standard-schema-types.d.ts +7 -0
  77. package/dist/framework/standard-schema-types.js +69 -0
  78. package/dist/framework/standard-schema-types.js.map +1 -0
  79. package/dist/framework/state.d.ts +7 -0
  80. package/dist/framework/state.js +78 -14
  81. package/dist/framework/state.js.map +1 -1
  82. package/dist/framework/styles.d.ts +2 -0
  83. package/dist/framework/styles.js +6 -0
  84. package/dist/framework/styles.js.map +1 -0
  85. package/dist/framework/type-declarations.d.ts +5 -0
  86. package/dist/framework/type-declarations.js +84 -0
  87. package/dist/framework/type-declarations.js.map +1 -0
  88. package/dist/framework-server/contracts.d.ts +11 -2
  89. package/dist/framework-server/contracts.js +62 -7
  90. package/dist/framework-server/contracts.js.map +1 -1
  91. package/dist/framework-server/discovery.d.ts +4 -1
  92. package/dist/framework-server/discovery.js +21 -16
  93. package/dist/framework-server/discovery.js.map +1 -1
  94. package/dist/framework-server/local.d.ts +2 -0
  95. package/dist/framework-server/local.js +5 -3
  96. package/dist/framework-server/local.js.map +1 -1
  97. package/dist/framework-server/middleware.d.ts +4 -0
  98. package/dist/framework-server/middleware.js +56 -0
  99. package/dist/framework-server/middleware.js.map +1 -0
  100. package/dist/framework-server/node-upgrade.js +27 -9
  101. package/dist/framework-server/node-upgrade.js.map +1 -1
  102. package/dist/framework-server/node-websocket.js +4 -2
  103. package/dist/framework-server/node-websocket.js.map +1 -1
  104. package/dist/framework-server/session-stores.d.ts +9 -2
  105. package/dist/framework-server/session-stores.js +37 -11
  106. package/dist/framework-server/session-stores.js.map +1 -1
  107. package/dist/framework-server/sessions.d.ts +6 -0
  108. package/dist/framework-server/sessions.js +41 -10
  109. package/dist/framework-server/sessions.js.map +1 -1
  110. package/dist/framework-server/socket.js +62 -27
  111. package/dist/framework-server/socket.js.map +1 -1
  112. package/dist/framework-server.d.ts +2 -0
  113. package/dist/framework-server.js +1 -0
  114. package/dist/framework-server.js.map +1 -1
  115. package/dist/framework.d.ts +3 -1
  116. package/dist/framework.js +1 -0
  117. package/dist/framework.js.map +1 -1
  118. package/dist/hmr.js +74 -24
  119. package/dist/hmr.js.map +1 -1
  120. package/dist/index.d.ts +2 -0
  121. package/dist/index.js +1 -0
  122. package/dist/index.js.map +1 -1
  123. package/dist/init.js +27 -1
  124. package/dist/init.js.map +1 -1
  125. package/dist/internal.d.ts +2 -2
  126. package/dist/internal.js +2 -2
  127. package/dist/internal.js.map +1 -1
  128. package/dist/node.d.ts +5 -1
  129. package/dist/node.js +80 -10
  130. package/dist/node.js.map +1 -1
  131. package/dist/reactivity.d.ts +12 -3
  132. package/dist/reactivity.js +94 -17
  133. package/dist/reactivity.js.map +1 -1
  134. package/dist/types.d.ts +2 -0
  135. package/dist/types.js +3 -1
  136. package/dist/types.js.map +1 -1
  137. package/dist/vite.js +29 -9
  138. package/dist/vite.js.map +1 -1
  139. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/framework-server/contracts.ts"],"names":[],"mappings":"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","sourcesContent":["import { serializeJson } from \"../server.js\";\nimport type { RequestContext } from \"./context.js\";\nimport { SessionSecurityError, type SessionManager } from \"./sessions.js\";\n\n/** Valibot schemas implement this public Standard Schema contract. */\nexport interface Schema<I = unknown, O = I> {\n readonly \"~standard\": {\n readonly version: 1;\n readonly validate: (value: unknown) => { value: O; issues?: undefined } | { issues: readonly unknown[] } | Promise<{ value: O; issues?: undefined } | { issues: readonly unknown[] }>;\n readonly types?: { readonly input: I; readonly output: O } | undefined;\n };\n}\n\ntype Input<S> = S extends Schema<infer I, unknown> ? I : never;\ntype Output<S> = S extends Schema<unknown, infer O> ? O : never;\ntype OptionalOutput<S> = S extends Schema ? Output<S> : undefined;\n\nexport class ApiError extends Error {\n constructor(public readonly code: string, public readonly status: number, message = code) {\n super(message);\n }\n}\n\nexport interface ApiRouteDefinition<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S = unknown> {\n params?: P;\n query?: Q;\n body?: B;\n response?: R;\n auth?: \"required\" | \"optional\";\n contentType?: \"json\" | \"response\";\n authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;\n handler: (args: { params: OptionalOutput<P>; query: OptionalOutput<Q>; body: OptionalOutput<B>; context: RequestContext<S> }) => Promise<R extends Schema ? Output<R> : Response> | (R extends Schema ? Output<R> : Response);\n}\n\nexport function defineApiRoute<P extends Schema | undefined = undefined, Q extends Schema | undefined = undefined, B extends Schema | undefined = undefined, R extends Schema | undefined = undefined, S = unknown>(definition: ApiRouteDefinition<P, Q, B, R, S>): ApiRouteDefinition<P, Q, B, R, S> {\n return definition;\n}\n\nexport interface RpcDefinition<I extends Schema, O extends Schema, S = unknown> {\n input: I;\n output: O;\n auth?: \"required\" | \"optional\";\n authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;\n handler: (args: { input: Output<I>; context: RequestContext<S> }) => Promise<Input<O> | Output<O>> | Input<O> | Output<O>;\n}\n\nexport function defineRpc<I extends Schema, O extends Schema, S = unknown>(definition: RpcDefinition<I, O, S>): RpcDefinition<I, O, S> {\n return definition;\n}\n\nasync function validate<S extends Schema>(schema: S, value: unknown, label: string): Promise<Output<S>> {\n const result = await schema[\"~standard\"].validate(value);\n if (\"issues\" in result && result.issues) throw new ApiError(`INVALID_${label.toUpperCase()}`, label === \"response\" || label === \"output\" ? 500 : 400);\n return (result as { value: Output<S> }).value;\n}\n\nasync function readJson(request: Request, maxBytes = 1024 * 1024): Promise<unknown> {\n if (!request.headers.get(\"content-type\")?.toLowerCase().startsWith(\"application/json\")) throw new ApiError(\"UNSUPPORTED_MEDIA_TYPE\", 415);\n const reader = request.body?.getReader();\n if (!reader) throw new ApiError(\"INVALID_JSON\", 400);\n let length = 0;\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) break;\n length += next.value.byteLength;\n if (length > maxBytes) throw new ApiError(\"BODY_TOO_LARGE\", 413);\n chunks.push(next.value);\n }\n } finally { reader.releaseLock(); }\n const bytes = new Uint8Array(length);\n let position = 0;\n for (const chunk of chunks) { bytes.set(chunk, position); position += chunk.byteLength; }\n try { return JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes)) as unknown; }\n catch { throw new ApiError(\"INVALID_JSON\", 400); }\n}\n\nfunction queryObject(url: URL): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = Object.create(null);\n for (const [key, value] of url.searchParams) {\n const previous = result[key];\n result[key] = previous === undefined ? value : Array.isArray(previous) ? [...previous, value] : [previous, value];\n }\n return result;\n}\n\nasync function guard<S>(definition: { auth?: \"required\" | \"optional\"; authorize?: (context: RequestContext<S>) => boolean | Promise<boolean> }, context: RequestContext<S>, sessions: SessionManager, mutating?: boolean): Promise<void> {\n sessions.assertMutationAllowed(context.request, context.session, mutating);\n if (definition.auth === \"required\" && !context.session.current) throw new ApiError(\"UNAUTHENTICATED\", 401);\n if (definition.authorize && !(await definition.authorize(context))) throw new ApiError(\"FORBIDDEN\", 403);\n}\n\nexport async function executeApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, rawParams: unknown = {}): Promise<Response> {\n await guard(definition, context, sessions);\n const params = definition.params ? await validate(definition.params, rawParams, \"params\") : undefined;\n const query = definition.query ? await validate(definition.query, queryObject(new URL(context.request.url)), \"query\") : undefined;\n const body = definition.body ? await validate(definition.body, await readJson(context.request), \"body\") : undefined;\n const result = await definition.handler({ params: params as OptionalOutput<P>, query: query as OptionalOutput<Q>, body: body as OptionalOutput<B>, context });\n if (definition.contentType === \"response\") {\n if (!(result instanceof Response)) throw new ApiError(\"INVALID_RESPONSE\", 500);\n return result;\n }\n if (!definition.response) throw new ApiError(\"MISSING_RESPONSE_SCHEMA\", 500);\n const output = await validate(definition.response, result, \"response\");\n return new Response(serializeJson(output), { headers: { \"content-type\": \"application/json; charset=utf-8\" } });\n}\n\nexport async function executeRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, rawInput: unknown, context: RequestContext<S>, sessions: SessionManager): Promise<Output<O>> {\n await guard(definition, context, sessions, true);\n const input = await validate(definition.input, rawInput, \"input\");\n const result = await definition.handler({ input, context });\n const output = await validate(definition.output, result, \"output\");\n serializeJson(output);\n return output;\n}\n\nexport function errorResponse(error: unknown, requestId: string): Response {\n const known = error instanceof ApiError ? error : error instanceof SessionSecurityError ? new ApiError(error.code, 403) : new ApiError(\"INTERNAL_ERROR\", 500);\n return new Response(serializeJson({ code: known.code, status: known.status, requestId }), { status: known.status, headers: { \"content-type\": \"application/json; charset=utf-8\", \"x-request-id\": requestId } });\n}\n\nfunction finish(response: Response, context: RequestContext): Response {\n response.headers.set(\"x-request-id\", context.requestId);\n if (context.session.cookieHeader) response.headers.append(\"set-cookie\", context.session.cookieHeader);\n if (context.session.current) response.headers.set(\"x-meeko-csrf-token\", context.session.current.csrfToken);\n return response;\n}\n\nexport async function dispatchApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, params: unknown = {}): Promise<Response> {\n try { return finish(await executeApiRoute(definition, context, sessions, params), context); }\n catch (error) { return finish(errorResponse(error, context.requestId), context); }\n}\n\nexport async function dispatchRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, context: RequestContext<S>, sessions: SessionManager): Promise<Response> {\n try {\n if (context.request.method !== \"POST\") throw new ApiError(\"METHOD_NOT_ALLOWED\", 405);\n const output = await executeRpc(definition, await readJson(context.request), context, sessions);\n return finish(new Response(serializeJson(output), { headers: { \"content-type\": \"application/json; charset=utf-8\" } }), context);\n } catch (error) { return finish(errorResponse(error, context.requestId), context); }\n}\n"]}
1
+ {"version":3,"file":"contracts.js","sourceRoot":"","sources":["../../src/framework-server/contracts.ts"],"names":[],"mappings":"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","sourcesContent":["import { serializeJson } from \"../server.js\";\nimport type { RequestContext } from \"./context.js\";\nimport { SessionSecurityError, type SessionManager } from \"./sessions.js\";\n\n/** Valibot schemas implement this public Standard Schema contract. */\nexport interface Schema<I = unknown, O = I> {\n readonly \"~standard\": {\n readonly version: 1;\n readonly validate: (value: unknown) => { value: O; issues?: undefined } | { issues: readonly unknown[] } | Promise<{ value: O; issues?: undefined } | { issues: readonly unknown[] }>;\n readonly types?: { readonly input: I; readonly output: O } | undefined;\n };\n}\n\ntype Input<S> = S extends Schema<infer I, unknown> ? I : never;\ntype Output<S> = S extends Schema<unknown, infer O> ? O : never;\ntype OptionalOutput<S> = S extends Schema ? Output<S> : undefined;\n\nexport class ApiError extends Error {\n constructor(public readonly code: string, public readonly status: number, message = code) {\n super(message);\n this.name = \"ApiError\";\n }\n}\n\n/** Preserve public errors loaded through separate Vite module graphs; hide all others. */\nexport function normalizeServerError(error: unknown): ApiError {\n if (error instanceof SessionSecurityError) return new ApiError(error.code, 403);\n if (error instanceof Error && (error.name === \"SessionSecurityError\" || error.constructor.name === \"SessionSecurityError\")) {\n const code = (error as Error & { code?: unknown }).code;\n if (code === \"INVALID_ORIGIN\" || code === \"INVALID_CSRF\") return new ApiError(code, 403);\n }\n if (error instanceof Error && (error instanceof ApiError || error.name === \"ApiError\" || error.constructor.name === \"ApiError\")) {\n const candidate = error as Error & { code?: unknown; status?: unknown };\n if (typeof candidate.code === \"string\" && candidate.code.length > 0\n && typeof candidate.status === \"number\" && Number.isInteger(candidate.status)\n && candidate.status >= 400 && candidate.status <= 599) {\n return error instanceof ApiError ? error : new ApiError(candidate.code, candidate.status);\n }\n }\n return new ApiError(\"INTERNAL_ERROR\", 500);\n}\n\nexport type ServerErrorObserver = (error: unknown, requestId: string) => void;\n\nfunction reportObserverFailure(error: unknown, observerError: unknown, requestId?: string): void {\n try {\n const label = requestId ? `Meeko server error observer failed (${requestId})` : \"Meeko server error observer failed\";\n // Error messages and custom properties may contain private server data.\n console.error(label, { original: error instanceof Error ? \"Error\" : typeof error, observer: observerError instanceof Error ? \"Error\" : typeof observerError });\n } catch { /* The fallback logger cannot change the original response. */ }\n}\n\n/** Observer failures cannot replace a response or escape as unhandled rejections. */\nexport function observeErrorCallback(error: unknown, observer?: (error: unknown) => void, requestId?: string): void {\n try { void Promise.resolve(observer?.(error)).catch((observerError: unknown) => reportObserverFailure(error, observerError, requestId)); }\n catch (observerError) { reportObserverFailure(error, observerError, requestId); }\n}\n\n/** Apply the same isolation to observers that also receive a request ID. */\nexport function observeServerError(error: unknown, requestId: string, observer?: ServerErrorObserver): void {\n observeErrorCallback(error, observer ? (failure) => observer(failure, requestId) : undefined, requestId);\n}\n\n/** Surface internal failures to the host while keeping observers out of the response path. */\nexport function reportServerError(error: unknown, requestId: string, observer?: ServerErrorObserver): void {\n if (normalizeServerError(error).status < 500) return;\n observeServerError(error, requestId, observer);\n}\n\nexport interface ApiRouteDefinition<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S = unknown> {\n params?: P;\n query?: Q;\n body?: B;\n response?: R;\n auth?: \"required\" | \"optional\";\n contentType?: \"json\" | \"response\";\n authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;\n handler: (args: { params: OptionalOutput<P>; query: OptionalOutput<Q>; body: OptionalOutput<B>; context: RequestContext<S> }) => Promise<R extends Schema ? Output<R> : Response> | (R extends Schema ? Output<R> : Response);\n}\n\nexport function defineApiRoute<P extends Schema | undefined = undefined, Q extends Schema | undefined = undefined, B extends Schema | undefined = undefined, R extends Schema | undefined = undefined, S = unknown>(definition: ApiRouteDefinition<P, Q, B, R, S>): ApiRouteDefinition<P, Q, B, R, S> {\n return definition;\n}\n\nexport interface RpcDefinition<I extends Schema, O extends Schema, S = unknown> {\n input: I;\n output: O;\n auth?: \"required\" | \"optional\";\n authorize?: (context: RequestContext<S>) => boolean | Promise<boolean>;\n handler: (args: { input: Output<I>; context: RequestContext<S> }) => Promise<Input<O> | Output<O>> | Input<O> | Output<O>;\n}\n\nexport function defineRpc<I extends Schema, O extends Schema, S = unknown>(definition: RpcDefinition<I, O, S>): RpcDefinition<I, O, S> {\n return definition;\n}\n\nasync function validate<S extends Schema>(schema: S, value: unknown, label: string): Promise<Output<S>> {\n const result = await schema[\"~standard\"].validate(value);\n if (\"issues\" in result && result.issues) throw new ApiError(`INVALID_${label.toUpperCase()}`, label === \"response\" || label === \"output\" ? 500 : 400);\n return (result as { value: Output<S> }).value;\n}\n\nasync function readJson(request: Request, maxBytes = 1024 * 1024): Promise<unknown> {\n if (!request.headers.get(\"content-type\")?.toLowerCase().startsWith(\"application/json\")) throw new ApiError(\"UNSUPPORTED_MEDIA_TYPE\", 415);\n const reader = request.body?.getReader();\n if (!reader) throw new ApiError(\"INVALID_JSON\", 400);\n let length = 0;\n const chunks: Uint8Array[] = [];\n try {\n while (true) {\n const next = await reader.read();\n if (next.done) break;\n length += next.value.byteLength;\n if (length > maxBytes) throw new ApiError(\"BODY_TOO_LARGE\", 413);\n chunks.push(next.value);\n }\n } finally { reader.releaseLock(); }\n const bytes = new Uint8Array(length);\n let position = 0;\n for (const chunk of chunks) { bytes.set(chunk, position); position += chunk.byteLength; }\n try { return JSON.parse(new TextDecoder(\"utf-8\", { fatal: true }).decode(bytes)) as unknown; }\n catch { throw new ApiError(\"INVALID_JSON\", 400); }\n}\n\nfunction queryObject(url: URL): Record<string, string | string[]> {\n const result: Record<string, string | string[]> = Object.create(null);\n for (const [key, value] of url.searchParams) {\n const previous = result[key];\n result[key] = previous === undefined ? value : Array.isArray(previous) ? [...previous, value] : [previous, value];\n }\n return result;\n}\n\nasync function guard<S>(definition: { auth?: \"required\" | \"optional\"; authorize?: (context: RequestContext<S>) => boolean | Promise<boolean> }, context: RequestContext<S>, sessions: SessionManager, mutating?: boolean): Promise<void> {\n sessions.assertMutationAllowed(context.request, context.session, mutating);\n if (definition.auth === \"required\" && !context.session.current) throw new ApiError(\"UNAUTHENTICATED\", 401);\n if (definition.authorize && !(await definition.authorize(context))) throw new ApiError(\"FORBIDDEN\", 403);\n}\n\nexport async function executeApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, rawParams: unknown = {}): Promise<Response> {\n await guard(definition, context, sessions);\n const params = definition.params ? await validate(definition.params, rawParams, \"params\") : undefined;\n const query = definition.query ? await validate(definition.query, queryObject(new URL(context.request.url)), \"query\") : undefined;\n const body = definition.body ? await validate(definition.body, await readJson(context.request), \"body\") : undefined;\n const result = await definition.handler({ params: params as OptionalOutput<P>, query: query as OptionalOutput<Q>, body: body as OptionalOutput<B>, context });\n if (definition.contentType === \"response\") {\n if (!(result instanceof Response)) throw new ApiError(\"INVALID_RESPONSE\", 500);\n return result;\n }\n if (!definition.response) throw new ApiError(\"MISSING_RESPONSE_SCHEMA\", 500);\n const output = await validate(definition.response, result, \"response\");\n return new Response(serializeJson(output), { headers: { \"content-type\": \"application/json; charset=utf-8\" } });\n}\n\nexport async function executeRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, rawInput: unknown, context: RequestContext<S>, sessions: SessionManager): Promise<Output<O>> {\n await guard(definition, context, sessions, true);\n const input = await validate(definition.input, rawInput, \"input\");\n const result = await definition.handler({ input, context });\n const output = await validate(definition.output, result, \"output\");\n serializeJson(output);\n return output;\n}\n\nexport function errorResponse(error: unknown, requestId: string): Response {\n const known = normalizeServerError(error);\n return new Response(serializeJson({ code: known.code, status: known.status, requestId }), { status: known.status, headers: { \"content-type\": \"application/json; charset=utf-8\", \"x-request-id\": requestId } });\n}\n\nfunction finish(response: Response, context: RequestContext): Response {\n // Fetch-created responses such as Response.redirect have immutable headers.\n // Wrap the response to preserve its status, body, and headers before adding\n // request metadata and session changes.\n const finished = new Response(response.body, response);\n finished.headers.set(\"x-request-id\", context.requestId);\n if (context.session.cookieHeader) finished.headers.append(\"set-cookie\", context.session.cookieHeader);\n if (context.session.current) finished.headers.set(\"x-meeko-csrf-token\", context.session.current.csrfToken);\n else if (context.session.cookieHeader) finished.headers.set(\"x-meeko-csrf-token\", \"\");\n return finished;\n}\n\nexport async function dispatchApiRoute<P extends Schema | undefined, Q extends Schema | undefined, B extends Schema | undefined, R extends Schema | undefined, S>(definition: ApiRouteDefinition<P, Q, B, R, S>, context: RequestContext<S>, sessions: SessionManager, params: unknown = {}, onError?: ServerErrorObserver): Promise<Response> {\n try { return finish(await executeApiRoute(definition, context, sessions, params), context); }\n catch (error) { reportServerError(error, context.requestId, onError); return finish(errorResponse(error, context.requestId), context); }\n}\n\nexport async function dispatchRpc<I extends Schema, O extends Schema, S>(definition: RpcDefinition<I, O, S>, context: RequestContext<S>, sessions: SessionManager, onError?: ServerErrorObserver): Promise<Response> {\n try {\n if (context.request.method !== \"POST\") throw new ApiError(\"METHOD_NOT_ALLOWED\", 405);\n const output = await executeRpc(definition, await readJson(context.request), context, sessions);\n return finish(new Response(serializeJson(output), { headers: { \"content-type\": \"application/json; charset=utf-8\" } }), context);\n } catch (error) { reportServerError(error, context.requestId, onError); return finish(errorResponse(error, context.requestId), context); }\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { ServerFetch } from "./context.js";
2
+ import type { ServerErrorObserver } from "./contracts.js";
2
3
  import type { SessionManager } from "./sessions.js";
3
4
  export type ApiMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
4
5
  export interface ApiEndpoint {
@@ -34,7 +35,9 @@ export interface ServerDispatcherOptions<S = unknown> {
34
35
  sessions: SessionManager;
35
36
  services: S | ((request: Request) => S | Promise<S>);
36
37
  load?: (file: string) => Promise<unknown>;
38
+ /** Observes internal failures without exposing their details to clients. */
39
+ onError?: ServerErrorObserver;
37
40
  }
38
41
  export declare function createServerDispatcher<S>(options: ServerDispatcherOptions<S>): (request: Request) => Promise<Response>;
39
42
  /** SSR dispatch reuses the original session, services, state and request ID. */
40
- export declare function createLocalServerFetch<S>(options: Pick<ServerDispatcherOptions<S>, "manifest" | "sessions" | "load">): ServerFetch;
43
+ export declare function createLocalServerFetch<S>(options: Pick<ServerDispatcherOptions<S>, "manifest" | "sessions" | "load" | "onError">): ServerFetch;
@@ -3,7 +3,7 @@ import { randomUUID } from "node:crypto";
3
3
  import { join, relative, resolve, sep } from "node:path";
4
4
  import { pathToFileURL } from "node:url";
5
5
  import { createRequestContext } from "./context.js";
6
- import { ApiError, dispatchApiRoute, dispatchRpc, errorResponse } from "./contracts.js";
6
+ import { ApiError, dispatchApiRoute, dispatchRpc, errorResponse, reportServerError } from "./contracts.js";
7
7
  function parts(pathname) {
8
8
  return pathname.split("/").filter(Boolean).map((part, index, all) => {
9
9
  if (/^\[\.\.\.[A-Za-z_$][\w$]*\]$/.test(part)) {
@@ -24,6 +24,18 @@ function collisionKey(pathname) {
24
24
  function clientKey(pathname) {
25
25
  return parts(pathname).map((part) => part.kind === "static" ? part.value : part.kind === "param" ? `by${part.value[0].toUpperCase()}${part.value.slice(1)}` : `by${part.value[0].toUpperCase()}${part.value.slice(1)}`).join(".");
26
26
  }
27
+ /** A callable cannot also be the parent object of another generated client member. */
28
+ function assertCallablePaths(entries, label) {
29
+ const seen = new Map();
30
+ for (const entry of entries) {
31
+ for (const [previousPath, previousFile] of seen) {
32
+ if (entry.path !== previousPath && !entry.path.startsWith(`${previousPath}.`) && !previousPath.startsWith(`${entry.path}.`))
33
+ continue;
34
+ throw new Error(`${label}: ${previousFile} (${previousPath}) and ${entry.file} (${entry.path}) cannot both be callable client paths`);
35
+ }
36
+ seen.set(entry.path, entry.file);
37
+ }
38
+ }
27
39
  async function files(directory) {
28
40
  let entries;
29
41
  try {
@@ -57,6 +69,8 @@ function apiEndpoint(directory, file) {
57
69
  const route = match[1].split("/");
58
70
  if (route.at(-1) === "index")
59
71
  route.pop();
72
+ if (route.length === 0)
73
+ throw new Error(`API handler cannot target /api because it has no generated client key: ${file}`);
60
74
  const pathname = `/api${route.length ? `/${route.join("/")}` : ""}`;
61
75
  parts(pathname);
62
76
  return { kind: "api", file, pathname, method: match[2].toUpperCase(), clientKey: clientKey(pathname.slice(4)) };
@@ -91,26 +105,15 @@ export async function discoverServerManifest(projectRoot) {
91
105
  socketNames.set(endpoint.name, endpoint.file);
92
106
  }
93
107
  const paths = new Map();
94
- const keys = new Map();
95
108
  for (const endpoint of api) {
96
109
  const pathKey = `${endpoint.method} ${collisionKey(endpoint.pathname)}`;
97
110
  const previous = paths.get(pathKey);
98
111
  if (previous)
99
112
  throw new Error(`API route collision: ${previous} and ${endpoint.file} both resolve to ${pathKey}`);
100
113
  paths.set(pathKey, endpoint.file);
101
- const key = `${endpoint.method} ${endpoint.clientKey}`;
102
- const keyPrevious = keys.get(key);
103
- if (keyPrevious)
104
- throw new Error(`API client name collision: ${keyPrevious} and ${endpoint.file} both generate ${key}`);
105
- keys.set(key, endpoint.file);
106
- }
107
- const ids = new Map();
108
- for (const endpoint of rpc) {
109
- const previous = ids.get(endpoint.id);
110
- if (previous)
111
- throw new Error(`RPC collision: ${previous} and ${endpoint.file} both resolve to ${endpoint.id}`);
112
- ids.set(endpoint.id, endpoint.file);
113
114
  }
115
+ assertCallablePaths(api.map((endpoint) => ({ file: endpoint.file, path: `${endpoint.clientKey}.${endpoint.method.toLowerCase()}` })), "API client name collision");
116
+ assertCallablePaths(rpc.map((endpoint) => ({ file: endpoint.file, path: endpoint.id })), "RPC collision");
114
117
  return Object.freeze({ api: Object.freeze(api), rpc: Object.freeze(rpc), socket: Object.freeze(socket) });
115
118
  }
116
119
  /** Loads server-only channel definitions; callers pass the result to createSocketHub. */
@@ -190,7 +193,7 @@ function requestDispatcher(options) {
190
193
  if (request.method !== "POST")
191
194
  throw new ApiError("METHOD_NOT_ALLOWED", 405);
192
195
  const definition = exportedDefinition(await load(endpoint.file));
193
- return dispatchRpc(definition, context, options.sessions);
196
+ return dispatchRpc(definition, context, options.sessions, options.onError);
194
197
  }
195
198
  let allowed = [];
196
199
  for (const endpoint of api) {
@@ -202,7 +205,7 @@ function requestDispatcher(options) {
202
205
  continue;
203
206
  }
204
207
  const definition = exportedDefinition(await load(endpoint.file));
205
- return dispatchApiRoute(definition, context, options.sessions, params);
208
+ return dispatchApiRoute(definition, context, options.sessions, params, options.onError);
206
209
  }
207
210
  if (allowed.length) {
208
211
  const response = errorResponse(new ApiError("METHOD_NOT_ALLOWED", 405), context.requestId);
@@ -212,6 +215,7 @@ function requestDispatcher(options) {
212
215
  throw new ApiError("NOT_FOUND", 404);
213
216
  }
214
217
  catch (error) {
218
+ reportServerError(error, context.requestId, options.onError);
215
219
  return errorResponse(error, context.requestId);
216
220
  }
217
221
  };
@@ -228,6 +232,7 @@ export function createServerDispatcher(options) {
228
232
  return dispatch(context);
229
233
  }
230
234
  catch (error) {
235
+ reportServerError(error, requestId, options.onError);
231
236
  return errorResponse(error, requestId);
232
237
  }
233
238
  };
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/framework-server/discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { randomUUID } from \"node:crypto\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createRequestContext } from \"./context.js\";\nimport type { RequestContext, ServerFetch } from \"./context.js\";\nimport { ApiError, dispatchApiRoute, dispatchRpc, errorResponse } from \"./contracts.js\";\nimport type { ApiRouteDefinition, RpcDefinition, Schema } from \"./contracts.js\";\nimport type { SessionManager } from \"./sessions.js\";\n\nexport type ApiMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\nexport interface ApiEndpoint { readonly kind: \"api\"; readonly file: string; readonly pathname: string; readonly method: ApiMethod; readonly clientKey: string; }\nexport interface RpcEndpoint { readonly kind: \"rpc\"; readonly file: string; readonly pathname: string; readonly id: string; }\nexport interface SocketEndpoint { readonly kind: \"socket\"; readonly file: string; readonly name: string; readonly pathname: string; }\nexport interface ServerManifest { readonly api: readonly ApiEndpoint[]; readonly rpc: readonly RpcEndpoint[]; readonly socket?: readonly SocketEndpoint[]; }\ntype PatternPart = { kind: \"static\" | \"param\" | \"rest\"; value: string };\n\nfunction parts(pathname: string): PatternPart[] {\n return pathname.split(\"/\").filter(Boolean).map((part, index, all) => {\n if (/^\\[\\.\\.\\.[A-Za-z_$][\\w$]*\\]$/.test(part)) {\n if (index !== all.length - 1) throw new Error(`Catch-all must be last: ${pathname}`);\n return { kind: \"rest\", value: part.slice(4, -1) };\n }\n if (/^\\[[A-Za-z_$][\\w$]*\\]$/.test(part)) return { kind: \"param\", value: part.slice(1, -1) };\n if (!/^[A-Za-z0-9_-]+$/.test(part)) throw new Error(`Invalid server route segment: ${part}`);\n return { kind: \"static\", value: part };\n });\n}\n\nfunction collisionKey(pathname: string): string {\n return parts(pathname).map((part) => part.kind === \"static\" ? part.value : part.kind === \"param\" ? \"[]\" : \"[...]\").join(\"/\");\n}\n\nfunction clientKey(pathname: string): string {\n return parts(pathname).map((part) => part.kind === \"static\" ? part.value : part.kind === \"param\" ? `by${part.value[0]!.toUpperCase()}${part.value.slice(1)}` : `by${part.value[0]!.toUpperCase()}${part.value.slice(1)}`).join(\".\");\n}\n\nasync function files(directory: string): Promise<string[]> {\n let entries;\n try { entries = await readdir(directory, { withFileTypes: true }); }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return []; throw error; }\n const found: string[] = [];\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const file = join(directory, entry.name);\n if (entry.isDirectory()) found.push(...await files(file));\n else if (entry.isFile() && /\\.(?:ts|js|mts|mjs)$/.test(entry.name) && !/\\.(?:test|spec|d)\\.(?:ts|js|mts|mjs)$/.test(entry.name)) found.push(file);\n }\n return found.sort();\n}\n\nfunction rel(root: string, file: string): string {\n return relative(root, file).split(sep).join(\"/\").replace(/\\.(?:ts|js|mts|mjs)$/, \"\");\n}\n\nfunction apiEndpoint(directory: string, file: string): ApiEndpoint {\n const path = rel(directory, file);\n const match = /^(.*)\\.(get|post|put|patch|delete)$/.exec(path);\n if (!match) throw new Error(`API handler requires a method suffix: ${file}`);\n const route = match[1]!.split(\"/\");\n if (route.at(-1) === \"index\") route.pop();\n const pathname = `/api${route.length ? `/${route.join(\"/\")}` : \"\"}`;\n parts(pathname);\n return { kind: \"api\", file, pathname, method: match[2]!.toUpperCase() as ApiMethod, clientKey: clientKey(pathname.slice(4)) };\n}\n\nfunction rpcEndpoint(directory: string, file: string): RpcEndpoint {\n const path = rel(directory, file);\n const route = path.split(\"/\");\n if (route.some((part) => !/^[A-Za-z_$][\\w$]*$/.test(part))) throw new Error(`Invalid RPC procedure name: ${file}`);\n const id = route.join(\".\");\n return { kind: \"rpc\", file, id, pathname: `/_meeko/rpc/${route.join(\"/\")}` };\n}\n\n/** Static discovery is shared by development and production; no handler is executed here. */\nexport async function discoverServerManifest(projectRoot: string): Promise<ServerManifest> {\n const root = resolve(projectRoot);\n const apiRoot = join(root, \"server\", \"api\");\n const rpcRoot = join(root, \"server\", \"rpc\");\n const socketRoot = join(root, \"server\", \"socket\");\n const api = (await files(apiRoot)).map((file) => apiEndpoint(apiRoot, file));\n const rpc = (await files(rpcRoot)).map((file) => rpcEndpoint(rpcRoot, file));\n const socket = (await files(socketRoot)).map((file): SocketEndpoint => {\n const name = rel(socketRoot, file);\n if (!/^[A-Za-z_$][\\w$-]*$/.test(name)) throw new Error(`Invalid Socket channel name in ${file}; use a single named file`);\n return { kind: \"socket\", file, name, pathname: `/_meeko/socket/${name}` };\n });\n const socketNames = new Map<string, string>();\n for (const endpoint of socket) {\n const previous = socketNames.get(endpoint.name);\n if (previous) throw new Error(`Socket channel collision: ${previous} and ${endpoint.file} both resolve to ${endpoint.name}`);\n socketNames.set(endpoint.name, endpoint.file);\n }\n const paths = new Map<string, string>();\n const keys = new Map<string, string>();\n for (const endpoint of api) {\n const pathKey = `${endpoint.method} ${collisionKey(endpoint.pathname)}`;\n const previous = paths.get(pathKey);\n if (previous) throw new Error(`API route collision: ${previous} and ${endpoint.file} both resolve to ${pathKey}`);\n paths.set(pathKey, endpoint.file);\n const key = `${endpoint.method} ${endpoint.clientKey}`;\n const keyPrevious = keys.get(key);\n if (keyPrevious) throw new Error(`API client name collision: ${keyPrevious} and ${endpoint.file} both generate ${key}`);\n keys.set(key, endpoint.file);\n }\n const ids = new Map<string, string>();\n for (const endpoint of rpc) {\n const previous = ids.get(endpoint.id);\n if (previous) throw new Error(`RPC collision: ${previous} and ${endpoint.file} both resolve to ${endpoint.id}`);\n ids.set(endpoint.id, endpoint.file);\n }\n return Object.freeze({ api: Object.freeze(api), rpc: Object.freeze(rpc), socket: Object.freeze(socket) });\n}\n\n/** Loads server-only channel definitions; callers pass the result to createSocketHub. */\nexport async function loadSocketChannels(manifest: Pick<ServerManifest, \"socket\">, load: (file: string) => Promise<unknown> = async (file) => import(pathToFileURL(file).href) as Promise<unknown>): Promise<Readonly<Record<string, unknown>>> {\n const channels: Record<string, unknown> = Object.create(null);\n for (const endpoint of manifest.socket ?? []) {\n const module = await load(endpoint.file);\n if (!module || typeof module !== \"object\" || !(\"default\" in module)) throw new Error(`${endpoint.file}: Socket channel requires a default export`);\n channels[endpoint.name] = (module as { default: unknown }).default;\n }\n return channels;\n}\n\nfunction decode(part: string): string | undefined {\n try {\n const value = decodeURIComponent(part);\n return value && value !== \".\" && value !== \"..\" && !value.includes(\"/\") && !value.includes(\"\\\\\") ? value : undefined;\n } catch { return undefined; }\n}\n\nfunction match(pathname: string, pattern: string): Record<string, string> | undefined {\n const raw = pathname.split(\"/\").filter(Boolean);\n const path = raw.map(decode);\n if (path.some((part) => part === undefined)) return undefined;\n const patternParts = parts(pattern);\n const params: Record<string, string> = Object.create(null);\n let index = 0;\n for (const part of patternParts) {\n if (part.kind === \"rest\") {\n if (index >= path.length) return undefined;\n params[part.value] = path.slice(index).join(\"/\");\n index = path.length;\n break;\n }\n const value = path[index++];\n if (value === undefined || (part.kind === \"static\" && part.value !== value)) return undefined;\n if (part.kind === \"param\") params[part.value] = value;\n }\n return index === path.length ? params : undefined;\n}\n\nfunction rank(endpoint: ApiEndpoint): number[] {\n return parts(endpoint.pathname).map((part) => part.kind === \"static\" ? 3 : part.kind === \"param\" ? 2 : 1);\n}\n\nfunction compareApi(a: ApiEndpoint, b: ApiEndpoint): number {\n const left = rank(a);\n const right = rank(b);\n for (let index = 0; index < Math.max(left.length, right.length); index++) {\n const score = (right[index] ?? 0) - (left[index] ?? 0);\n if (score) return score;\n }\n return a.pathname.localeCompare(b.pathname);\n}\n\nexport interface ServerDispatcherOptions<S = unknown> {\n manifest: ServerManifest;\n sessions: SessionManager;\n services: S | ((request: Request) => S | Promise<S>);\n load?: (file: string) => Promise<unknown>;\n}\n\nfunction exportedDefinition(module: unknown): unknown {\n if (module && typeof module === \"object\" && \"default\" in module) return (module as { default: unknown }).default;\n throw new ApiError(\"INVALID_HANDLER\", 500);\n}\n\n/** Dispatches API and RPC through the same request context and security pipeline. */\nfunction requestDispatcher<S>(options: Pick<ServerDispatcherOptions<S>, \"manifest\" | \"sessions\" | \"load\">): (context: RequestContext<S>) => Promise<Response> {\n const api = [...options.manifest.api].sort(compareApi);\n const load = options.load ?? (async (file: string) => import(pathToFileURL(file).href) as Promise<unknown>);\n return async (context) => {\n const request = context.request;\n try {\n const pathname = new URL(request.url).pathname;\n if (pathname.startsWith(\"/_meeko/rpc/\")) {\n const endpoint = options.manifest.rpc.find((record) => record.pathname === pathname);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n if (request.method !== \"POST\") throw new ApiError(\"METHOD_NOT_ALLOWED\", 405);\n const definition = exportedDefinition(await load(endpoint.file)) as RpcDefinition<Schema, Schema, S>;\n return dispatchRpc(definition, context, options.sessions);\n }\n let allowed: ApiMethod[] = [];\n for (const endpoint of api) {\n const params = match(pathname, endpoint.pathname);\n if (!params) continue;\n if (request.method !== endpoint.method) { allowed.push(endpoint.method); continue; }\n const definition = exportedDefinition(await load(endpoint.file)) as ApiRouteDefinition<Schema | undefined, Schema | undefined, Schema | undefined, Schema | undefined, S>;\n return dispatchApiRoute(definition, context, options.sessions, params);\n }\n if (allowed.length) {\n const response = errorResponse(new ApiError(\"METHOD_NOT_ALLOWED\", 405), context.requestId);\n response.headers.set(\"allow\", [...new Set(allowed)].join(\", \"));\n return response;\n }\n throw new ApiError(\"NOT_FOUND\", 404);\n } catch (error) { return errorResponse(error, context.requestId); }\n };\n}\n\nexport function createServerDispatcher<S>(options: ServerDispatcherOptions<S>): (request: Request) => Promise<Response> {\n const dispatch = requestDispatcher(options);\n return async (request) => {\n let requestId: string = randomUUID();\n try {\n const session = await options.sessions.load(request);\n const services = typeof options.services === \"function\" ? await (options.services as (request: Request) => S | Promise<S>)(request) : options.services;\n const context = createRequestContext(request, services, session);\n requestId = context.requestId;\n return dispatch(context);\n } catch (error) { return errorResponse(error, requestId); }\n };\n}\n\n/** SSR dispatch reuses the original session, services, state and request ID. */\nexport function createLocalServerFetch<S>(options: Pick<ServerDispatcherOptions<S>, \"manifest\" | \"sessions\" | \"load\">): ServerFetch {\n const dispatch = requestDispatcher(options);\n return async (request, active) => {\n const source = active.request;\n if (new URL(request.url).origin !== new URL(source.url).origin) {\n return errorResponse(new ApiError(\"INVALID_ORIGIN\", 403), active.requestId);\n }\n for (const name of [\"cookie\", \"authorization\"]) {\n if (request.headers.get(name) !== source.headers.get(name)) {\n return errorResponse(new ApiError(\"INVALID_CREDENTIALS\", 403), active.requestId);\n }\n }\n const context: RequestContext<S> = { ...active, request, signal: request.signal } as RequestContext<S>;\n return dispatch(context);\n };\n}\n"]}
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/framework-server/discovery.ts"],"names":[],"mappings":"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","sourcesContent":["import { readdir } from \"node:fs/promises\";\nimport { randomUUID } from \"node:crypto\";\nimport { join, relative, resolve, sep } from \"node:path\";\nimport { pathToFileURL } from \"node:url\";\nimport { createRequestContext } from \"./context.js\";\nimport type { RequestContext, ServerFetch } from \"./context.js\";\nimport { ApiError, dispatchApiRoute, dispatchRpc, errorResponse, reportServerError } from \"./contracts.js\";\nimport type { ApiRouteDefinition, RpcDefinition, Schema, ServerErrorObserver } from \"./contracts.js\";\nimport type { SessionManager } from \"./sessions.js\";\n\nexport type ApiMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\nexport interface ApiEndpoint { readonly kind: \"api\"; readonly file: string; readonly pathname: string; readonly method: ApiMethod; readonly clientKey: string; }\nexport interface RpcEndpoint { readonly kind: \"rpc\"; readonly file: string; readonly pathname: string; readonly id: string; }\nexport interface SocketEndpoint { readonly kind: \"socket\"; readonly file: string; readonly name: string; readonly pathname: string; }\nexport interface ServerManifest { readonly api: readonly ApiEndpoint[]; readonly rpc: readonly RpcEndpoint[]; readonly socket?: readonly SocketEndpoint[]; }\ntype PatternPart = { kind: \"static\" | \"param\" | \"rest\"; value: string };\n\nfunction parts(pathname: string): PatternPart[] {\n return pathname.split(\"/\").filter(Boolean).map((part, index, all) => {\n if (/^\\[\\.\\.\\.[A-Za-z_$][\\w$]*\\]$/.test(part)) {\n if (index !== all.length - 1) throw new Error(`Catch-all must be last: ${pathname}`);\n return { kind: \"rest\", value: part.slice(4, -1) };\n }\n if (/^\\[[A-Za-z_$][\\w$]*\\]$/.test(part)) return { kind: \"param\", value: part.slice(1, -1) };\n if (!/^[A-Za-z0-9_-]+$/.test(part)) throw new Error(`Invalid server route segment: ${part}`);\n return { kind: \"static\", value: part };\n });\n}\n\nfunction collisionKey(pathname: string): string {\n return parts(pathname).map((part) => part.kind === \"static\" ? part.value : part.kind === \"param\" ? \"[]\" : \"[...]\").join(\"/\");\n}\n\nfunction clientKey(pathname: string): string {\n return parts(pathname).map((part) => part.kind === \"static\" ? part.value : part.kind === \"param\" ? `by${part.value[0]!.toUpperCase()}${part.value.slice(1)}` : `by${part.value[0]!.toUpperCase()}${part.value.slice(1)}`).join(\".\");\n}\n\n/** A callable cannot also be the parent object of another generated client member. */\nfunction assertCallablePaths(entries: readonly { readonly file: string; readonly path: string }[], label: string): void {\n const seen = new Map<string, string>();\n for (const entry of entries) {\n for (const [previousPath, previousFile] of seen) {\n if (entry.path !== previousPath && !entry.path.startsWith(`${previousPath}.`) && !previousPath.startsWith(`${entry.path}.`)) continue;\n throw new Error(`${label}: ${previousFile} (${previousPath}) and ${entry.file} (${entry.path}) cannot both be callable client paths`);\n }\n seen.set(entry.path, entry.file);\n }\n}\n\nasync function files(directory: string): Promise<string[]> {\n let entries;\n try { entries = await readdir(directory, { withFileTypes: true }); }\n catch (error) { if ((error as NodeJS.ErrnoException).code === \"ENOENT\") return []; throw error; }\n const found: string[] = [];\n for (const entry of entries) {\n if (entry.name.startsWith(\".\") || entry.name === \"node_modules\") continue;\n const file = join(directory, entry.name);\n if (entry.isDirectory()) found.push(...await files(file));\n else if (entry.isFile() && /\\.(?:ts|js|mts|mjs)$/.test(entry.name) && !/\\.(?:test|spec|d)\\.(?:ts|js|mts|mjs)$/.test(entry.name)) found.push(file);\n }\n return found.sort();\n}\n\nfunction rel(root: string, file: string): string {\n return relative(root, file).split(sep).join(\"/\").replace(/\\.(?:ts|js|mts|mjs)$/, \"\");\n}\n\nfunction apiEndpoint(directory: string, file: string): ApiEndpoint {\n const path = rel(directory, file);\n const match = /^(.*)\\.(get|post|put|patch|delete)$/.exec(path);\n if (!match) throw new Error(`API handler requires a method suffix: ${file}`);\n const route = match[1]!.split(\"/\");\n if (route.at(-1) === \"index\") route.pop();\n if (route.length === 0) throw new Error(`API handler cannot target /api because it has no generated client key: ${file}`);\n const pathname = `/api${route.length ? `/${route.join(\"/\")}` : \"\"}`;\n parts(pathname);\n return { kind: \"api\", file, pathname, method: match[2]!.toUpperCase() as ApiMethod, clientKey: clientKey(pathname.slice(4)) };\n}\n\nfunction rpcEndpoint(directory: string, file: string): RpcEndpoint {\n const path = rel(directory, file);\n const route = path.split(\"/\");\n if (route.some((part) => !/^[A-Za-z_$][\\w$]*$/.test(part))) throw new Error(`Invalid RPC procedure name: ${file}`);\n const id = route.join(\".\");\n return { kind: \"rpc\", file, id, pathname: `/_meeko/rpc/${route.join(\"/\")}` };\n}\n\n/** Static discovery is shared by development and production; no handler is executed here. */\nexport async function discoverServerManifest(projectRoot: string): Promise<ServerManifest> {\n const root = resolve(projectRoot);\n const apiRoot = join(root, \"server\", \"api\");\n const rpcRoot = join(root, \"server\", \"rpc\");\n const socketRoot = join(root, \"server\", \"socket\");\n const api = (await files(apiRoot)).map((file) => apiEndpoint(apiRoot, file));\n const rpc = (await files(rpcRoot)).map((file) => rpcEndpoint(rpcRoot, file));\n const socket = (await files(socketRoot)).map((file): SocketEndpoint => {\n const name = rel(socketRoot, file);\n if (!/^[A-Za-z_$][\\w$-]*$/.test(name)) throw new Error(`Invalid Socket channel name in ${file}; use a single named file`);\n return { kind: \"socket\", file, name, pathname: `/_meeko/socket/${name}` };\n });\n const socketNames = new Map<string, string>();\n for (const endpoint of socket) {\n const previous = socketNames.get(endpoint.name);\n if (previous) throw new Error(`Socket channel collision: ${previous} and ${endpoint.file} both resolve to ${endpoint.name}`);\n socketNames.set(endpoint.name, endpoint.file);\n }\n const paths = new Map<string, string>();\n for (const endpoint of api) {\n const pathKey = `${endpoint.method} ${collisionKey(endpoint.pathname)}`;\n const previous = paths.get(pathKey);\n if (previous) throw new Error(`API route collision: ${previous} and ${endpoint.file} both resolve to ${pathKey}`);\n paths.set(pathKey, endpoint.file);\n }\n assertCallablePaths(api.map((endpoint) => ({ file: endpoint.file, path: `${endpoint.clientKey}.${endpoint.method.toLowerCase()}` })), \"API client name collision\");\n assertCallablePaths(rpc.map((endpoint) => ({ file: endpoint.file, path: endpoint.id })), \"RPC collision\");\n return Object.freeze({ api: Object.freeze(api), rpc: Object.freeze(rpc), socket: Object.freeze(socket) });\n}\n\n/** Loads server-only channel definitions; callers pass the result to createSocketHub. */\nexport async function loadSocketChannels(manifest: Pick<ServerManifest, \"socket\">, load: (file: string) => Promise<unknown> = async (file) => import(pathToFileURL(file).href) as Promise<unknown>): Promise<Readonly<Record<string, unknown>>> {\n const channels: Record<string, unknown> = Object.create(null);\n for (const endpoint of manifest.socket ?? []) {\n const module = await load(endpoint.file);\n if (!module || typeof module !== \"object\" || !(\"default\" in module)) throw new Error(`${endpoint.file}: Socket channel requires a default export`);\n channels[endpoint.name] = (module as { default: unknown }).default;\n }\n return channels;\n}\n\nfunction decode(part: string): string | undefined {\n try {\n const value = decodeURIComponent(part);\n return value && value !== \".\" && value !== \"..\" && !value.includes(\"/\") && !value.includes(\"\\\\\") ? value : undefined;\n } catch { return undefined; }\n}\n\nfunction match(pathname: string, pattern: string): Record<string, string> | undefined {\n const raw = pathname.split(\"/\").filter(Boolean);\n const path = raw.map(decode);\n if (path.some((part) => part === undefined)) return undefined;\n const patternParts = parts(pattern);\n const params: Record<string, string> = Object.create(null);\n let index = 0;\n for (const part of patternParts) {\n if (part.kind === \"rest\") {\n if (index >= path.length) return undefined;\n params[part.value] = path.slice(index).join(\"/\");\n index = path.length;\n break;\n }\n const value = path[index++];\n if (value === undefined || (part.kind === \"static\" && part.value !== value)) return undefined;\n if (part.kind === \"param\") params[part.value] = value;\n }\n return index === path.length ? params : undefined;\n}\n\nfunction rank(endpoint: ApiEndpoint): number[] {\n return parts(endpoint.pathname).map((part) => part.kind === \"static\" ? 3 : part.kind === \"param\" ? 2 : 1);\n}\n\nfunction compareApi(a: ApiEndpoint, b: ApiEndpoint): number {\n const left = rank(a);\n const right = rank(b);\n for (let index = 0; index < Math.max(left.length, right.length); index++) {\n const score = (right[index] ?? 0) - (left[index] ?? 0);\n if (score) return score;\n }\n return a.pathname.localeCompare(b.pathname);\n}\n\nexport interface ServerDispatcherOptions<S = unknown> {\n manifest: ServerManifest;\n sessions: SessionManager;\n services: S | ((request: Request) => S | Promise<S>);\n load?: (file: string) => Promise<unknown>;\n /** Observes internal failures without exposing their details to clients. */\n onError?: ServerErrorObserver;\n}\n\nfunction exportedDefinition(module: unknown): unknown {\n if (module && typeof module === \"object\" && \"default\" in module) return (module as { default: unknown }).default;\n throw new ApiError(\"INVALID_HANDLER\", 500);\n}\n\n/** Dispatches API and RPC through the same request context and security pipeline. */\nfunction requestDispatcher<S>(options: Pick<ServerDispatcherOptions<S>, \"manifest\" | \"sessions\" | \"load\" | \"onError\">): (context: RequestContext<S>) => Promise<Response> {\n const api = [...options.manifest.api].sort(compareApi);\n const load = options.load ?? (async (file: string) => import(pathToFileURL(file).href) as Promise<unknown>);\n return async (context) => {\n const request = context.request;\n try {\n const pathname = new URL(request.url).pathname;\n if (pathname.startsWith(\"/_meeko/rpc/\")) {\n const endpoint = options.manifest.rpc.find((record) => record.pathname === pathname);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n if (request.method !== \"POST\") throw new ApiError(\"METHOD_NOT_ALLOWED\", 405);\n const definition = exportedDefinition(await load(endpoint.file)) as RpcDefinition<Schema, Schema, S>;\n return dispatchRpc(definition, context, options.sessions, options.onError);\n }\n let allowed: ApiMethod[] = [];\n for (const endpoint of api) {\n const params = match(pathname, endpoint.pathname);\n if (!params) continue;\n if (request.method !== endpoint.method) { allowed.push(endpoint.method); continue; }\n const definition = exportedDefinition(await load(endpoint.file)) as ApiRouteDefinition<Schema | undefined, Schema | undefined, Schema | undefined, Schema | undefined, S>;\n return dispatchApiRoute(definition, context, options.sessions, params, options.onError);\n }\n if (allowed.length) {\n const response = errorResponse(new ApiError(\"METHOD_NOT_ALLOWED\", 405), context.requestId);\n response.headers.set(\"allow\", [...new Set(allowed)].join(\", \"));\n return response;\n }\n throw new ApiError(\"NOT_FOUND\", 404);\n } catch (error) { reportServerError(error, context.requestId, options.onError); return errorResponse(error, context.requestId); }\n };\n}\n\nexport function createServerDispatcher<S>(options: ServerDispatcherOptions<S>): (request: Request) => Promise<Response> {\n const dispatch = requestDispatcher(options);\n return async (request) => {\n let requestId: string = randomUUID();\n try {\n const session = await options.sessions.load(request);\n const services = typeof options.services === \"function\" ? await (options.services as (request: Request) => S | Promise<S>)(request) : options.services;\n const context = createRequestContext(request, services, session);\n requestId = context.requestId;\n return dispatch(context);\n } catch (error) { reportServerError(error, requestId, options.onError); return errorResponse(error, requestId); }\n };\n}\n\n/** SSR dispatch reuses the original session, services, state and request ID. */\nexport function createLocalServerFetch<S>(options: Pick<ServerDispatcherOptions<S>, \"manifest\" | \"sessions\" | \"load\" | \"onError\">): ServerFetch {\n const dispatch = requestDispatcher(options);\n return async (request, active) => {\n const source = active.request;\n if (new URL(request.url).origin !== new URL(source.url).origin) {\n return errorResponse(new ApiError(\"INVALID_ORIGIN\", 403), active.requestId);\n }\n for (const name of [\"cookie\", \"authorization\"]) {\n if (request.headers.get(name) !== source.headers.get(name)) {\n return errorResponse(new ApiError(\"INVALID_CREDENTIALS\", 403), active.requestId);\n }\n }\n const context: RequestContext<S> = { ...active, request, signal: request.signal } as RequestContext<S>;\n return dispatch(context);\n };\n}\n"]}
@@ -1,3 +1,4 @@
1
+ import type { ServerErrorObserver } from "./contracts.js";
1
2
  import type { RequestContext } from "./context.js";
2
3
  import type { ApiMethod, ServerManifest } from "./discovery.js";
3
4
  import type { SessionManager } from "./sessions.js";
@@ -6,6 +7,7 @@ export interface LocalCallOptions<S> {
6
7
  context: RequestContext<S>;
7
8
  sessions: SessionManager;
8
9
  load?: (file: string) => Promise<unknown>;
10
+ onError?: ServerErrorObserver;
9
11
  }
10
12
  export interface LocalApiInput {
11
13
  params?: Readonly<Record<string, string>>;
@@ -1,5 +1,5 @@
1
1
  import { pathToFileURL } from "node:url";
2
- import { ApiError, dispatchApiRoute, dispatchRpc, errorResponse } from "./contracts.js";
2
+ import { ApiError, dispatchApiRoute, dispatchRpc, errorResponse, reportServerError } from "./contracts.js";
3
3
  import { serializeJson } from "../server.js";
4
4
  function publicHeaders(request) {
5
5
  const headers = new Headers();
@@ -70,9 +70,10 @@ export function createLocalCalls(options) {
70
70
  headers.set("content-type", "application/json");
71
71
  const request = new Request(url, { method, headers, signal: options.context.signal, ...(body === undefined ? {} : { body }) });
72
72
  const definition = routeModule(await load(endpoint.file));
73
- return dispatchApiRoute(definition, derived(request), options.sessions, input.params ?? {});
73
+ return dispatchApiRoute(definition, derived(request), options.sessions, input.params ?? {}, options.onError);
74
74
  }
75
75
  catch (error) {
76
+ reportServerError(error, options.context.requestId, options.onError);
76
77
  return errorResponse(error, options.context.requestId);
77
78
  }
78
79
  },
@@ -87,9 +88,10 @@ export function createLocalCalls(options) {
87
88
  method: "POST", headers, signal: options.context.signal, body: serializeJson(input),
88
89
  });
89
90
  const definition = routeModule(await load(endpoint.file));
90
- return dispatchRpc(definition, derived(request), options.sessions);
91
+ return dispatchRpc(definition, derived(request), options.sessions, options.onError);
91
92
  }
92
93
  catch (error) {
94
+ reportServerError(error, options.context.requestId, options.onError);
93
95
  return errorResponse(error, options.context.requestId);
94
96
  }
95
97
  },
@@ -1 +1 @@
1
- {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/framework-server/local.ts"],"names":[],"mappings":"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","sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { ApiError, dispatchApiRoute, dispatchRpc, errorResponse } from \"./contracts.js\";\nimport type { ApiRouteDefinition, RpcDefinition, Schema } from \"./contracts.js\";\nimport type { RequestContext } from \"./context.js\";\nimport type { ApiMethod, ServerManifest } from \"./discovery.js\";\nimport type { SessionManager } from \"./sessions.js\";\nimport { serializeJson } from \"../server.js\";\n\nexport interface LocalCallOptions<S> {\n manifest: ServerManifest;\n context: RequestContext<S>;\n sessions: SessionManager;\n load?: (file: string) => Promise<unknown>;\n}\n\nexport interface LocalApiInput {\n params?: Readonly<Record<string, string>>;\n query?: Readonly<Record<string, string | number | boolean | readonly string[] | null | undefined>>;\n body?: unknown;\n}\n\nfunction publicHeaders(request: Request): Headers {\n const headers = new Headers();\n for (const name of [\"cookie\", \"origin\", \"x-meeko-csrf\", \"authorization\"]) {\n const value = request.headers.get(name);\n if (value !== null) headers.set(name, value);\n }\n return headers;\n}\n\nfunction resolvePath(pattern: string, params: Readonly<Record<string, string>>): string {\n const used = new Set<string>();\n const path = pattern.split(\"/\").map((part) => {\n const match = /^\\[([A-Za-z_$][\\w$]*)\\]$/.exec(part);\n const rest = /^\\[\\.\\.\\.([A-Za-z_$][\\w$]*)\\]$/.exec(part);\n if (!match && !rest) return part;\n const key = (match ?? rest)![1]!;\n const value = params[key];\n if (!value) throw new ApiError(\"INVALID_PARAMS\", 400);\n used.add(key);\n if (rest) {\n const segments = value.split(\"/\");\n if (segments.some((segment) => !segment || segment === \".\" || segment === \"..\")) throw new ApiError(\"INVALID_PARAMS\", 400);\n return segments.map(encodeURIComponent).join(\"/\");\n }\n if (value.includes(\"/\") || value === \".\" || value === \"..\") throw new ApiError(\"INVALID_PARAMS\", 400);\n return encodeURIComponent(value);\n }).join(\"/\");\n for (const key of Object.keys(params)) if (!used.has(key)) throw new ApiError(\"INVALID_PARAMS\", 400);\n return path;\n}\n\nfunction routeModule(module: unknown): unknown {\n if (module && typeof module === \"object\" && \"default\" in module) return (module as { default: unknown }).default;\n throw new ApiError(\"INVALID_HANDLER\", 500);\n}\n\n/** Local calls use in-memory Request objects, never a network fetch or global context. */\nexport function createLocalCalls<S>(options: LocalCallOptions<S>) {\n const load = options.load ?? (async (file: string) => import(pathToFileURL(file).href) as Promise<unknown>);\n const derived = (request: Request): RequestContext<S> => ({ ...options.context, request });\n return {\n async api(clientKey: string, method: ApiMethod, input: LocalApiInput = {}): Promise<Response> {\n try {\n const endpoint = options.manifest.api.find((entry) => entry.clientKey === clientKey && entry.method === method);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n const url = new URL(resolvePath(endpoint.pathname, input.params ?? {}), options.context.request.url);\n for (const [key, value] of Object.entries(input.query ?? {})) {\n if (value === undefined || value === null) continue;\n if (Array.isArray(value)) for (const item of value) url.searchParams.append(key, item);\n else url.searchParams.set(key, String(value));\n }\n const headers = publicHeaders(options.context.request);\n if ((method === \"GET\") && Object.hasOwn(input, \"body\")) throw new ApiError(\"INVALID_BODY\", 400);\n const body = Object.hasOwn(input, \"body\") ? serializeJson(input.body) : undefined;\n if (body !== undefined) headers.set(\"content-type\", \"application/json\");\n const request = new Request(url, { method, headers, signal: options.context.signal, ...(body === undefined ? {} : { body }) });\n const definition = routeModule(await load(endpoint.file)) as ApiRouteDefinition<Schema | undefined, Schema | undefined, Schema | undefined, Schema | undefined, S>;\n return dispatchApiRoute(definition, derived(request), options.sessions, input.params ?? {});\n } catch (error) { return errorResponse(error, options.context.requestId); }\n },\n async rpc(id: string, input: unknown): Promise<Response> {\n try {\n const endpoint = options.manifest.rpc.find((entry) => entry.id === id);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n const headers = publicHeaders(options.context.request);\n headers.set(\"content-type\", \"application/json\");\n const request = new Request(new URL(endpoint.pathname, options.context.request.url), {\n method: \"POST\", headers, signal: options.context.signal, body: serializeJson(input),\n });\n const definition = routeModule(await load(endpoint.file)) as RpcDefinition<Schema, Schema, S>;\n return dispatchRpc(definition, derived(request), options.sessions);\n } catch (error) { return errorResponse(error, options.context.requestId); }\n },\n };\n}\n"]}
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/framework-server/local.ts"],"names":[],"mappings":"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","sourcesContent":["import { pathToFileURL } from \"node:url\";\nimport { ApiError, dispatchApiRoute, dispatchRpc, errorResponse, reportServerError } from \"./contracts.js\";\nimport type { ApiRouteDefinition, RpcDefinition, Schema, ServerErrorObserver } from \"./contracts.js\";\nimport type { RequestContext } from \"./context.js\";\nimport type { ApiMethod, ServerManifest } from \"./discovery.js\";\nimport type { SessionManager } from \"./sessions.js\";\nimport { serializeJson } from \"../server.js\";\n\nexport interface LocalCallOptions<S> {\n manifest: ServerManifest;\n context: RequestContext<S>;\n sessions: SessionManager;\n load?: (file: string) => Promise<unknown>;\n onError?: ServerErrorObserver;\n}\n\nexport interface LocalApiInput {\n params?: Readonly<Record<string, string>>;\n query?: Readonly<Record<string, string | number | boolean | readonly string[] | null | undefined>>;\n body?: unknown;\n}\n\nfunction publicHeaders(request: Request): Headers {\n const headers = new Headers();\n for (const name of [\"cookie\", \"origin\", \"x-meeko-csrf\", \"authorization\"]) {\n const value = request.headers.get(name);\n if (value !== null) headers.set(name, value);\n }\n return headers;\n}\n\nfunction resolvePath(pattern: string, params: Readonly<Record<string, string>>): string {\n const used = new Set<string>();\n const path = pattern.split(\"/\").map((part) => {\n const match = /^\\[([A-Za-z_$][\\w$]*)\\]$/.exec(part);\n const rest = /^\\[\\.\\.\\.([A-Za-z_$][\\w$]*)\\]$/.exec(part);\n if (!match && !rest) return part;\n const key = (match ?? rest)![1]!;\n const value = params[key];\n if (!value) throw new ApiError(\"INVALID_PARAMS\", 400);\n used.add(key);\n if (rest) {\n const segments = value.split(\"/\");\n if (segments.some((segment) => !segment || segment === \".\" || segment === \"..\")) throw new ApiError(\"INVALID_PARAMS\", 400);\n return segments.map(encodeURIComponent).join(\"/\");\n }\n if (value.includes(\"/\") || value === \".\" || value === \"..\") throw new ApiError(\"INVALID_PARAMS\", 400);\n return encodeURIComponent(value);\n }).join(\"/\");\n for (const key of Object.keys(params)) if (!used.has(key)) throw new ApiError(\"INVALID_PARAMS\", 400);\n return path;\n}\n\nfunction routeModule(module: unknown): unknown {\n if (module && typeof module === \"object\" && \"default\" in module) return (module as { default: unknown }).default;\n throw new ApiError(\"INVALID_HANDLER\", 500);\n}\n\n/** Local calls use in-memory Request objects, never a network fetch or global context. */\nexport function createLocalCalls<S>(options: LocalCallOptions<S>) {\n const load = options.load ?? (async (file: string) => import(pathToFileURL(file).href) as Promise<unknown>);\n const derived = (request: Request): RequestContext<S> => ({ ...options.context, request });\n return {\n async api(clientKey: string, method: ApiMethod, input: LocalApiInput = {}): Promise<Response> {\n try {\n const endpoint = options.manifest.api.find((entry) => entry.clientKey === clientKey && entry.method === method);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n const url = new URL(resolvePath(endpoint.pathname, input.params ?? {}), options.context.request.url);\n for (const [key, value] of Object.entries(input.query ?? {})) {\n if (value === undefined || value === null) continue;\n if (Array.isArray(value)) for (const item of value) url.searchParams.append(key, item);\n else url.searchParams.set(key, String(value));\n }\n const headers = publicHeaders(options.context.request);\n if ((method === \"GET\") && Object.hasOwn(input, \"body\")) throw new ApiError(\"INVALID_BODY\", 400);\n const body = Object.hasOwn(input, \"body\") ? serializeJson(input.body) : undefined;\n if (body !== undefined) headers.set(\"content-type\", \"application/json\");\n const request = new Request(url, { method, headers, signal: options.context.signal, ...(body === undefined ? {} : { body }) });\n const definition = routeModule(await load(endpoint.file)) as ApiRouteDefinition<Schema | undefined, Schema | undefined, Schema | undefined, Schema | undefined, S>;\n return dispatchApiRoute(definition, derived(request), options.sessions, input.params ?? {}, options.onError);\n } catch (error) { reportServerError(error, options.context.requestId, options.onError); return errorResponse(error, options.context.requestId); }\n },\n async rpc(id: string, input: unknown): Promise<Response> {\n try {\n const endpoint = options.manifest.rpc.find((entry) => entry.id === id);\n if (!endpoint) throw new ApiError(\"NOT_FOUND\", 404);\n const headers = publicHeaders(options.context.request);\n headers.set(\"content-type\", \"application/json\");\n const request = new Request(new URL(endpoint.pathname, options.context.request.url), {\n method: \"POST\", headers, signal: options.context.signal, body: serializeJson(input),\n });\n const definition = routeModule(await load(endpoint.file)) as RpcDefinition<Schema, Schema, S>;\n return dispatchRpc(definition, derived(request), options.sessions, options.onError);\n } catch (error) { reportServerError(error, options.context.requestId, options.onError); return errorResponse(error, options.context.requestId); }\n },\n };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ /** Wraps page and API/RPC HTTP requests before Meeko creates their context. */
2
+ export type ServerMiddleware = (request: Request, next: (request?: Request) => Promise<Response>) => Response | Promise<Response>;
3
+ export declare function defineServerMiddleware(middleware: ServerMiddleware): ServerMiddleware;
4
+ export declare function composeServerMiddleware(middlewares: readonly ServerMiddleware[], handler: (request: Request) => Promise<Response>): (request: Request) => Promise<Response>;
@@ -0,0 +1,56 @@
1
+ export function defineServerMiddleware(middleware) {
2
+ return middleware;
3
+ }
4
+ export function composeServerMiddleware(middlewares, handler) {
5
+ const run = async (index, request) => {
6
+ const middleware = middlewares[index];
7
+ if (!middleware)
8
+ return handler(request);
9
+ let called = false;
10
+ let downstream;
11
+ let result;
12
+ let middlewareError;
13
+ let middlewareFailed = false;
14
+ try {
15
+ result = await middleware(request, (nextRequest = request) => {
16
+ if (called)
17
+ throw new Error("Server middleware called next() more than once");
18
+ called = true;
19
+ if (!(nextRequest instanceof Request))
20
+ throw new TypeError("Server middleware next() requires a Request");
21
+ downstream = run(index + 1, nextRequest);
22
+ // A middleware may forget to await next(). Keep its failure observed
23
+ // until this frame can propagate it to the HTTP response path.
24
+ void downstream.catch(() => { });
25
+ return downstream;
26
+ });
27
+ }
28
+ catch (error) {
29
+ middlewareFailed = true;
30
+ middlewareError = error;
31
+ }
32
+ let downstreamError;
33
+ let downstreamFailed = false;
34
+ if (downstream) {
35
+ try {
36
+ await downstream;
37
+ }
38
+ catch (error) {
39
+ downstreamFailed = true;
40
+ downstreamError = error;
41
+ }
42
+ }
43
+ if (middlewareFailed && downstreamFailed && !Object.is(middlewareError, downstreamError)) {
44
+ throw new AggregateError([middlewareError, downstreamError], "Server middleware and downstream failed");
45
+ }
46
+ if (middlewareFailed)
47
+ throw middlewareError;
48
+ if (downstreamFailed)
49
+ throw downstreamError;
50
+ if (!(result instanceof Response))
51
+ throw new TypeError("Server middleware must return a Response");
52
+ return result;
53
+ };
54
+ return (request) => run(0, request);
55
+ }
56
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/framework-server/middleware.ts"],"names":[],"mappings":"AAMA,MAAM,UAAU,sBAAsB,CAAC,UAA4B;IACjE,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,uBAAuB,CACrC,WAAwC,EACxC,OAAgD;IAEhD,MAAM,GAAG,GAAG,KAAK,EAAE,KAAa,EAAE,OAAgB,EAAqB,EAAE;QACvE,MAAM,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC;QACtC,IAAI,CAAC,UAAU;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,MAAM,GAAG,KAAK,CAAC;QACnB,IAAI,UAAyC,CAAC;QAC9C,IAAI,MAA4B,CAAC;QACjC,IAAI,eAAwB,CAAC;QAC7B,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAC7B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,EAAE,CAAC,WAAW,GAAG,OAAO,EAAE,EAAE;gBAC3D,IAAI,MAAM;oBAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;gBAC9E,MAAM,GAAG,IAAI,CAAC;gBACd,IAAI,CAAC,CAAC,WAAW,YAAY,OAAO,CAAC;oBAAE,MAAM,IAAI,SAAS,CAAC,6CAA6C,CAAC,CAAC;gBAC1G,UAAU,GAAG,GAAG,CAAC,KAAK,GAAG,CAAC,EAAE,WAAW,CAAC,CAAC;gBACzC,qEAAqE;gBACrE,+DAA+D;gBAC/D,KAAK,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,GAAE,CAAC,CAAC,CAAC;gBAChC,OAAO,UAAU,CAAC;YACpB,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,gBAAgB,GAAG,IAAI,CAAC;YACxB,eAAe,GAAG,KAAK,CAAC;QAC1B,CAAC;QACD,IAAI,eAAwB,CAAC;QAC7B,IAAI,gBAAgB,GAAG,KAAK,CAAC;QAC7B,IAAI,UAAU,EAAE,CAAC;YACf,IAAI,CAAC;gBAAC,MAAM,UAAU,CAAC;YAAC,CAAC;YACzB,OAAO,KAAK,EAAE,CAAC;gBAAC,gBAAgB,GAAG,IAAI,CAAC;gBAAC,eAAe,GAAG,KAAK,CAAC;YAAC,CAAC;QACrE,CAAC;QACD,IAAI,gBAAgB,IAAI,gBAAgB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,eAAe,EAAE,eAAe,CAAC,EAAE,CAAC;YACzF,MAAM,IAAI,cAAc,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,EAAE,yCAAyC,CAAC,CAAC;QAC1G,CAAC;QACD,IAAI,gBAAgB;YAAE,MAAM,eAAe,CAAC;QAC5C,IAAI,gBAAgB;YAAE,MAAM,eAAe,CAAC;QAC5C,IAAI,CAAC,CAAC,MAAM,YAAY,QAAQ,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAC;QACnG,OAAO,MAAM,CAAC;IAChB,CAAC,CAAC;IACF,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACtC,CAAC","sourcesContent":["/** Wraps page and API/RPC HTTP requests before Meeko creates their context. */\nexport type ServerMiddleware = (\n request: Request,\n next: (request?: Request) => Promise<Response>,\n) => Response | Promise<Response>;\n\nexport function defineServerMiddleware(middleware: ServerMiddleware): ServerMiddleware {\n return middleware;\n}\n\nexport function composeServerMiddleware(\n middlewares: readonly ServerMiddleware[],\n handler: (request: Request) => Promise<Response>,\n): (request: Request) => Promise<Response> {\n const run = async (index: number, request: Request): Promise<Response> => {\n const middleware = middlewares[index];\n if (!middleware) return handler(request);\n let called = false;\n let downstream: Promise<Response> | undefined;\n let result: Response | undefined;\n let middlewareError: unknown;\n let middlewareFailed = false;\n try {\n result = await middleware(request, (nextRequest = request) => {\n if (called) throw new Error(\"Server middleware called next() more than once\");\n called = true;\n if (!(nextRequest instanceof Request)) throw new TypeError(\"Server middleware next() requires a Request\");\n downstream = run(index + 1, nextRequest);\n // A middleware may forget to await next(). Keep its failure observed\n // until this frame can propagate it to the HTTP response path.\n void downstream.catch(() => {});\n return downstream;\n });\n } catch (error) {\n middlewareFailed = true;\n middlewareError = error;\n }\n let downstreamError: unknown;\n let downstreamFailed = false;\n if (downstream) {\n try { await downstream; }\n catch (error) { downstreamFailed = true; downstreamError = error; }\n }\n if (middlewareFailed && downstreamFailed && !Object.is(middlewareError, downstreamError)) {\n throw new AggregateError([middlewareError, downstreamError], \"Server middleware and downstream failed\");\n }\n if (middlewareFailed) throw middlewareError;\n if (downstreamFailed) throw downstreamError;\n if (!(result instanceof Response)) throw new TypeError(\"Server middleware must return a Response\");\n return result;\n };\n return (request) => run(0, request);\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { ApiError } from "./contracts.js";
1
+ import { normalizeServerError, observeErrorCallback } from "./contracts.js";
2
2
  /**
3
3
  * Handles the Node `upgrade` event after policy preflight. The host supplies a
4
4
  * WebSocket implementation; this adapter does not implement wire framing.
@@ -10,6 +10,7 @@ export function createNodeSocketUpgradeHandler(options) {
10
10
  const prefix = options.pathnamePrefix ?? "/_meeko/socket";
11
11
  if (!prefix.startsWith("/") || prefix.endsWith("/"))
12
12
  throw new TypeError("Invalid socket pathname prefix");
13
+ const observeError = (error) => observeErrorCallback(error, options.onError);
13
14
  return async (incoming, socket, head) => {
14
15
  let url;
15
16
  try {
@@ -44,8 +45,8 @@ export function createNodeSocketUpgradeHandler(options) {
44
45
  await options.hub.preflight(name, request, roomId);
45
46
  }
46
47
  catch (error) {
47
- reject(error instanceof ApiError ? error.status : 500);
48
- options.onError?.(error);
48
+ reject(normalizeServerError(error).status);
49
+ observeError(error);
49
50
  return true;
50
51
  }
51
52
  let accepted;
@@ -54,7 +55,7 @@ export function createNodeSocketUpgradeHandler(options) {
54
55
  }
55
56
  catch (error) {
56
57
  socket.destroy();
57
- options.onError?.(error);
58
+ observeError(error);
58
59
  return true;
59
60
  }
60
61
  try {
@@ -62,15 +63,32 @@ export function createNodeSocketUpgradeHandler(options) {
62
63
  let delivery = Promise.resolve();
63
64
  accepted.onMessage((message) => {
64
65
  delivery = delivery.then(() => connection.receive(message)).catch((error) => {
65
- options.onError?.(error);
66
- connection.close(error instanceof ApiError && error.status < 500 ? 1008 : 1011);
66
+ observeError(error);
67
+ try {
68
+ connection.close(normalizeServerError(error).status < 500 ? 1008 : 1011);
69
+ }
70
+ catch (closeError) {
71
+ observeError(closeError);
72
+ }
67
73
  });
68
74
  });
69
- accepted.onClose(() => connection.close());
75
+ accepted.onClose(() => {
76
+ try {
77
+ connection.close();
78
+ }
79
+ catch (error) {
80
+ observeError(error);
81
+ }
82
+ });
70
83
  }
71
84
  catch (error) {
72
- accepted.peer.close(1008, "Unauthorized");
73
- options.onError?.(error);
85
+ try {
86
+ accepted.peer.close(1008, "Unauthorized");
87
+ }
88
+ catch (closeError) {
89
+ observeError(closeError);
90
+ }
91
+ observeError(error);
74
92
  }
75
93
  return true;
76
94
  };