@fresho/router 0.6.0 → 0.6.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/README.md CHANGED
@@ -105,6 +105,9 @@ Define query and body schemas using shorthand syntax:
105
105
  { tags: 'string[]' } // string array
106
106
  { scores: 'number[]' } // number array
107
107
 
108
+ // Field descriptions (for OpenAPI and MCP tools)
109
+ { folder: ['string?', 'Mailbox folder, INBOX by default'] }
110
+
108
111
  // Nested objects
109
112
  {
110
113
  address: {
@@ -410,8 +413,10 @@ const api = router({
410
413
 
411
414
  `mcp()` requires endpoint middleware (usually auth). Pass `public: true` instead when the endpoint is open, or already guarded by middleware on its parent routers.
412
415
 
416
+ Besides `name` and `version`, the options take `instructions` for agents and `title`, `icons` (`{ src, mimeType?, sizes? }`) and `websiteUrl`, which clients may show in their UI.
417
+
413
418
  - **Tools** — one per route, named from the method and path (`get_users`, `post_users`, `get_users_by_id`, ...) unless the route sets `operationId` (also used in OpenAPI). Descriptions come from `route.description`.
414
- - **Arguments** — flat: path params, query fields and body fields side by side (`{ id, text }`), as JSON Schema derived from the route's schemas. Names must be unique across the three; a clash throws when `mcp()` is called. `descriptions: { field: '...', 'address.city': '...' }` on a route documents fields for agents and OpenAPI. Array query params are left out, since the router can't parse them from query strings. Without a body schema, `post`/`put`/`patch` tools send any other arguments as the body.
419
+ - **Arguments** — flat: path params, query fields and body fields side by side (`{ id, text }`), as JSON Schema derived from the route's schemas. Names must be unique across the three; a clash throws when `mcp()` is called. Use `[type, description]` tuples (e.g. `{ folder: ['string?', 'Mailbox folder'] }`) in `query` and `body` schemas to document fields for agents and OpenAPI. Array query params are left out, since the router can't parse them from query strings. Without a body schema, `post`/`put`/`patch` tools send any other arguments as the body.
415
420
  - **Annotations** — `get` tools are marked `readOnlyHint`, `delete` tools `destructiveHint` and `idempotentHint`, and `put` tools `idempotentHint`, so clients can decide when to ask for confirmation. Override per route with `mcp: { annotations: { ... } }`.
416
421
  - **Calls** — each tool call is dispatched as an HTTP request through the given routers with the caller's headers forwarded. Middleware on the MCP endpoint (passed to `mcp()` or on its parent routers) runs once per MCP request, and what it adds to the context (e.g. `c.user`) reaches handlers; middleware on the given routers and below runs on every call. Middleware on the given routers' *own* parents elsewhere in your app does **not** run, so guard the endpoint or the routers themselves. Responses become text content, plus `structuredContent` when the body is a JSON object; a non-2xx status sets `isError`, and streaming (SSE, NDJSON) responses are rejected.
417
422
  - **Safety** — requests with an `Origin` other than the endpoint's get 403 (as the MCP spec requires against DNS rebinding), so browser-hosted clients on other origins can't connect. Path parameters can't be `.` or `..`, and handler exceptions become a generic `Internal error`.
@@ -210,7 +210,7 @@ interface RevokeTokenOptions {
210
210
  * // Use in OAuth authorization URL
211
211
  * ```
212
212
  */
213
- declare function encodeOAuthState(data: Record<string, unknown>, secret: string): Promise<string>;
213
+ declare function encodeOAuthState(data: Record<string, unknown>, secret: string, ttlMs?: number): Promise<string>;
214
214
  /**
215
215
  * Decodes and verifies an HMAC-signed state parameter.
216
216
  *
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/auth/basic.ts","../../src/auth/oauth.ts"],"sourcesContent":[],"mappings":";;;;;;;AA2BA;AA2BA;AAsCA;AAUA;;;;AClCA;AAgBA;AAYA;AA8CA;AAGA;AAcA;AAqCA;AAmDA;;;;;AAGU,UD/NO,gBAAA,CC+NP;EA6DY;EAEX,QAAA,EAAA,MAAA;EACA;EAAR,QAAA,EAAA,MAAA;;AAqDH;;;;;;AAqDA;AAkCA;AAuCA;;;;;;;;iBDvbgB,cAAA,6BAA2C;;;;;;;;;;;;;;;;iBAsC3C,eAAA;;;;;;;iBAUA,qBAAA;;;;;;AA3EhB;AA2BA;AAsCA;AAUA;;;;AClCA;AAgBA;AAYA;AA8CA;AAGA;AAcA;AAqCA;AAmDA;;;;;;AAgEA;;;;;AAwDA;;;;;;AAqDA;AAkCA;AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;;UAzaiB,kBAAA;;;;;;;;;;;;;;;UAgBA,aAAA;;;;;;;;;;;cAYJ,iBAAiB,eAAe;;KA8CjC,eAAA;;UAGK,mBAAA;;;;;;;;;;eAUF;;;UAIE,kBAAA;;;;;;;;;;;;eAYF;;;;;;;;;;;;;;;;;;;;iBAyBO,gBAAA,OACd,0CAEL;;;;;;;;;;;;;;;;iBAgDmB,2BAA2B,0BAA0B,yDAGxE,QAAQ;;;;;;;;;;;;;;;;;;;iBA6DW,YAAA,wBAEX,sBACR,QAAQ;;;;;;;;;;;;;;;;;;;iBAqDW,kBAAA,gCAEX,KAAK,sCACb,QAAQ;;;;;;;;;;;;;;;;;iBAkDW,WAAA,UAAqB,qBAAqB;;UAkC/C,uBAAA;;;;;;;;;;;;;;gBAcD;;;;;;;;;;;;;;;;;;;;;;;;iBAyBA,qBAAA,UAA+B"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/auth/basic.ts","../../src/auth/oauth.ts"],"sourcesContent":[],"mappings":";;;;;;;AA2BA;AA2BA;AAsCA;AAUA;;;;AClCA;AAgBA;AAYA;AA8CA;AAGA;AAcA;AAqCA;AAmDA;;;;;AAGU,UD/NO,gBAAA,CC+NP;EAkEY;EAEX,QAAA,EAAA,MAAA;EACA;EAAR,QAAA,EAAA,MAAA;;AAqDH;;;;;;AAqDA;AAkCA;AAuCA;;;;;;;;iBD5bgB,cAAA,6BAA2C;;;;;;;;;;;;;;;;iBAsC3C,eAAA;;;;;;;iBAUA,qBAAA;;;;;;AA3EhB;AA2BA;AAsCA;AAUA;;;;AClCA;AAgBA;AAYA;AA8CA;AAGA;AAcA;AAqCA;AAmDA;;;;;;AAqEA;;;;;AAwDA;;;;;;AAqDA;AAkCA;AAuCA;;;;;;;;;;;;;;;;;;;;;;;;;;;UA9aiB,kBAAA;;;;;;;;;;;;;;;UAgBA,aAAA;;;;;;;;;;;cAYJ,iBAAiB,eAAe;;KA8CjC,eAAA;;UAGK,mBAAA;;;;;;;;;;eAUF;;;UAIE,kBAAA;;;;;;;;;;;;eAYF;;;;;;;;;;;;;;;;;;;;iBAyBO,gBAAA,OACd,0DAGL;;;;;;;;;;;;;;;;iBA+CmB,2BAA2B,0BAA0B,yDAGxE,QAAQ;;;;;;;;;;;;;;;;;;;iBAkEW,YAAA,wBAEX,sBACR,QAAQ;;;;;;;;;;;;;;;;;;;iBAqDW,kBAAA,gCAEX,KAAK,sCACb,QAAQ;;;;;;;;;;;;;;;;;iBAkDW,WAAA,UAAqB,qBAAqB;;UAkC/C,uBAAA;;;;;;;;;;;;;;gBAcD;;;;;;;;;;;;;;;;;;;;;;;;iBAyBA,qBAAA,UAA+B"}
@@ -64,13 +64,15 @@ const OAUTH_PROVIDERS = {
64
64
  * // Use in OAuth authorization URL
65
65
  * ```
66
66
  */
67
- async function encodeOAuthState(data, secret) {
67
+ async function encodeOAuthState(data, secret, ttlMs = 6e5) {
68
68
  const nonceBytes = new Uint8Array(12);
69
69
  crypto.getRandomValues(nonceBytes);
70
70
  const nonce = btoa(String.fromCharCode(...nonceBytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
71
+ const exp = typeof data._exp === "number" ? data._exp : Date.now() + ttlMs;
71
72
  const payload = JSON.stringify({
72
73
  ...data,
73
- _nonce: nonce
74
+ _nonce: nonce,
75
+ _exp: exp
74
76
  });
75
77
  const encoder = new TextEncoder();
76
78
  const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
@@ -78,7 +80,7 @@ async function encodeOAuthState(data, secret) {
78
80
  hash: "SHA-256"
79
81
  }, false, ["sign"]);
80
82
  const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
81
- const signatureHex = Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16);
83
+ const signatureHex = Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
82
84
  const stateData = JSON.stringify({
83
85
  payload,
84
86
  sig: signatureHex
@@ -105,15 +107,19 @@ async function decodeOAuthState(state, secret) {
105
107
  const base64 = state.replace(/-/g, "+").replace(/_/g, "/");
106
108
  const padded = base64.padEnd(base64.length + (4 - base64.length % 4) % 4, "=");
107
109
  const { payload, sig } = JSON.parse(atob(padded));
110
+ if (typeof payload !== "string" || typeof sig !== "string" || !/^[0-9a-f]{64}$/i.test(sig)) return null;
111
+ const sigBytes = new Uint8Array(32);
112
+ for (let i = 0; i < 32; i++) sigBytes[i] = Number.parseInt(sig.slice(i * 2, i * 2 + 2), 16);
108
113
  const encoder = new TextEncoder();
109
114
  const key = await crypto.subtle.importKey("raw", encoder.encode(secret), {
110
115
  name: "HMAC",
111
116
  hash: "SHA-256"
112
- }, false, ["sign"]);
113
- const expectedSignature = await crypto.subtle.sign("HMAC", key, encoder.encode(payload));
114
- if (sig !== Array.from(new Uint8Array(expectedSignature)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 16)) return null;
117
+ }, false, ["verify"]);
118
+ if (!await crypto.subtle.verify("HMAC", key, sigBytes, encoder.encode(payload))) return null;
115
119
  const payloadData = JSON.parse(payload);
120
+ if (typeof payloadData._exp !== "number" || Date.now() >= payloadData._exp) return null;
116
121
  delete payloadData._nonce;
122
+ delete payloadData._exp;
117
123
  return payloadData;
118
124
  } catch {
119
125
  return null;
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["OAUTH_PROVIDERS: Record<string, OAuthProvider>","headers: Record<string, string>"],"sources":["../../src/auth/oauth.ts"],"sourcesContent":["/**\n * @fileoverview OAuth 2.0 utilities for @fresho/router.\n *\n * Provides reusable primitives for implementing OAuth 2.0 Authorization Code flows.\n * This implementation is designed as a confidential client suitable for server-side\n * applications that can securely store client secrets.\n *\n * ## Design Decisions\n *\n * ### Why Not PKCE?\n *\n * PKCE (Proof Key for Code Exchange, RFC 7636) is a security extension designed to\n * protect against authorization code interception attacks. However:\n *\n * - PKCE is **required** only for public clients (mobile apps, SPAs without backend)\n * - PKCE is **optional** for confidential clients that can securely store secrets\n * - These utilities assume a confidential client with a `client_secret`\n * - The `client_secret` provides equivalent protection during token exchange\n *\n * ### HMAC-Signed State Parameter\n *\n * Instead of PKCE, we provide HMAC-signed state utilities that:\n *\n * 1. **Prevent CSRF attacks** - The signature is verified on callback\n * 2. **Carry custom data** - Embed arbitrary data (e.g., user ID) in the state\n * 3. **Include a nonce** - Random bytes prevent replay attacks\n * 4. **Use Web Crypto API** - Works in Cloudflare Workers, Deno, and browsers\n *\n * ## Provider Compatibility\n *\n * This implementation pattern works with ~60-70% of OAuth 2.0 providers:\n *\n * | Provider | PKCE | Auth Method | Compatible |\n * |------------|----------|-------------|------------|\n * | Google | Optional | Body | ✅ Yes |\n * | GitHub | None | Basic Auth | ✅ Minor tweak |\n * | Slack | None | Body | ✅ Yes |\n * | LinkedIn | None | Body | ✅ Yes |\n * | Spotify | Optional | Basic Auth | ✅ Yes |\n * | Discord | Optional | Body | ✅ Yes |\n * | Dropbox | None | Basic Auth | ✅ Minor tweak |\n * | Twitter | Required | - | ❌ Needs PKCE |\n * | TikTok | Required | - | ❌ Needs PKCE |\n *\n * @see https://tools.ietf.org/html/rfc6749 - OAuth 2.0 Authorization Framework\n * @see https://tools.ietf.org/html/rfc7636 - PKCE Extension\n *\n * @example\n * ```typescript\n * import { encodeOAuthState, decodeOAuthState, exchangeCode } from '@fresho/router/middleware';\n *\n * // In your authorize route:\n * const state = await encodeOAuthState({ uid: 'user-123' }, SECRET);\n * const authUrl = `https://provider.com/oauth/authorize?state=${state}&...`;\n *\n * // In your callback route:\n * const data = await decodeOAuthState(state, SECRET);\n * if (data) {\n * const tokens = await exchangeCode(code, { ... });\n * }\n * ```\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** OAuth 2.0 token response as per RFC 6749. */\nexport interface OAuthTokenResponse {\n /** The access token issued by the authorization server. */\n access_token: string;\n /** The refresh token (optional, returned with offline access). */\n refresh_token?: string;\n /** The type of token (typically \"Bearer\"). */\n token_type: string;\n /** The lifetime in seconds of the access token. */\n expires_in: number;\n /** The scopes granted by the authorization server. */\n scope?: string;\n /** OpenID Connect ID token (if openid scope was requested). */\n id_token?: string;\n}\n\n/** OAuth 2.0 provider configuration. */\nexport interface OAuthProvider {\n /** Authorization endpoint URL. */\n authorizationUrl: string;\n /** Token endpoint URL. */\n tokenUrl: string;\n /** Token revocation endpoint URL (optional). */\n revokeUrl?: string;\n /** User info endpoint URL (optional). */\n userInfoUrl?: string;\n}\n\n/** Common OAuth 2.0 providers with their endpoints. */\nexport const OAUTH_PROVIDERS: Record<string, OAuthProvider> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n revokeUrl: 'https://oauth2.googleapis.com/revoke',\n userInfoUrl: 'https://www.googleapis.com/oauth2/v3/userinfo',\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.github.com/user',\n },\n discord: {\n authorizationUrl: 'https://discord.com/oauth2/authorize',\n tokenUrl: 'https://discord.com/api/oauth2/token',\n revokeUrl: 'https://discord.com/api/oauth2/token/revoke',\n userInfoUrl: 'https://discord.com/api/users/@me',\n },\n slack: {\n authorizationUrl: 'https://slack.com/openid/connect/authorize',\n tokenUrl: 'https://slack.com/api/openid.connect.token',\n revokeUrl: undefined,\n userInfoUrl: undefined,\n },\n linkedin: {\n authorizationUrl: 'https://www.linkedin.com/oauth/v2/authorization',\n tokenUrl: 'https://www.linkedin.com/oauth/v2/accessToken',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.linkedin.com/v2/userinfo',\n },\n spotify: {\n authorizationUrl: 'https://accounts.spotify.com/authorize',\n tokenUrl: 'https://accounts.spotify.com/api/token',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.spotify.com/v1/me',\n },\n dropbox: {\n authorizationUrl: 'https://www.dropbox.com/oauth2/authorize',\n tokenUrl: 'https://api.dropboxapi.com/oauth2/token',\n revokeUrl: 'https://api.dropboxapi.com/2/auth/token/revoke',\n userInfoUrl: undefined,\n },\n};\n\n/** Token endpoint authentication method. */\nexport type TokenAuthMethod = 'body' | 'basic';\n\n/** Configuration for token exchange. */\nexport interface ExchangeCodeOptions {\n /** Token endpoint URL. */\n tokenUrl: string;\n /** OAuth client ID. */\n clientId: string;\n /** OAuth client secret. */\n clientSecret: string;\n /** Redirect URI used in authorization request. */\n redirectUri: string;\n /** Authentication method (default: 'body'). */\n authMethod?: TokenAuthMethod;\n}\n\n/** Configuration for token revocation. */\nexport interface RevokeTokenOptions {\n /** Revocation endpoint URL. */\n revokeUrl: string;\n /** Token to revoke. */\n token: string;\n /** Token type hint (optional, e.g., 'refresh_token' or 'access_token'). */\n tokenTypeHint?: string;\n /** OAuth client ID (for providers that require it). */\n clientId?: string;\n /** OAuth client secret (for providers that require it). */\n clientSecret?: string;\n /** Authentication method (default: 'body'). */\n authMethod?: TokenAuthMethod;\n}\n\n// =============================================================================\n// State Encoding/Decoding (HMAC-signed)\n// =============================================================================\n\n/**\n * Encodes arbitrary data into an HMAC-signed state parameter.\n *\n * The state is base64url-encoded and includes:\n * - The JSON-serialized payload\n * - A random nonce (12 bytes) for replay protection\n * - An HMAC-SHA256 signature (truncated to 16 hex chars)\n *\n * @param data - Arbitrary data to encode in the state\n * @param secret - Secret key for HMAC signing\n * @returns Base64url-encoded state string\n *\n * @example\n * ```typescript\n * const state = await encodeOAuthState({ uid: 'user-123', returnTo: '/dashboard' }, SECRET);\n * // Use in OAuth authorization URL\n * ```\n */\nexport async function encodeOAuthState(\n data: Record<string, unknown>,\n secret: string,\n): Promise<string> {\n // Generate random nonce.\n const nonceBytes = new Uint8Array(12);\n crypto.getRandomValues(nonceBytes);\n const nonce = btoa(String.fromCharCode(...nonceBytes))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n // Create payload with nonce.\n const payload = JSON.stringify({ ...data, _nonce: nonce });\n\n // Generate HMAC signature.\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));\n const signatureHex = Array.from(new Uint8Array(signature))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n .slice(0, 16);\n\n // Encode the full state.\n const stateData = JSON.stringify({ payload, sig: signatureHex });\n return btoa(stateData).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\n/**\n * Decodes and verifies an HMAC-signed state parameter.\n *\n * @param state - Base64url-encoded state string\n * @param secret - Secret key for HMAC verification\n * @returns The decoded data, or null if verification fails\n *\n * @example\n * ```typescript\n * const data = await decodeOAuthState(state, SECRET);\n * if (data) {\n * console.log(data.uid); // 'user-123'\n * }\n * ```\n */\nexport async function decodeOAuthState<T extends Record<string, unknown> = Record<string, unknown>>(\n state: string,\n secret: string,\n): Promise<T | null> {\n try {\n // Decode base64url.\n const base64 = state.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');\n const stateData = JSON.parse(atob(padded));\n\n const { payload, sig } = stateData;\n\n // Verify HMAC signature.\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const expectedSignature = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));\n const expectedSigHex = Array.from(new Uint8Array(expectedSignature))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n .slice(0, 16);\n\n // Constant-time comparison (simple version).\n if (sig !== expectedSigHex) {\n return null;\n }\n\n // Extract data from payload (remove internal _nonce field).\n const payloadData = JSON.parse(payload);\n delete payloadData._nonce;\n return payloadData as T;\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// Token Exchange\n// =============================================================================\n\n/**\n * Exchanges an authorization code for tokens.\n *\n * @param code - Authorization code from OAuth callback\n * @param options - Token exchange configuration\n * @returns Token response from the OAuth provider\n * @throws Error if token exchange fails\n *\n * @example\n * ```typescript\n * const tokens = await exchangeCode(code, {\n * tokenUrl: OAUTH_PROVIDERS.google.tokenUrl,\n * clientId: env.CLIENT_ID,\n * clientSecret: env.CLIENT_SECRET,\n * redirectUri: 'https://example.com/callback',\n * });\n * ```\n */\nexport async function exchangeCode(\n code: string,\n options: ExchangeCodeOptions,\n): Promise<OAuthTokenResponse> {\n const { tokenUrl, clientId, clientSecret, redirectUri, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n });\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n\n if (authMethod === 'basic') {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.status} ${errorText}`);\n }\n\n return response.json();\n}\n\n/**\n * Refreshes an access token using a refresh token.\n *\n * @param refreshToken - The refresh token\n * @param options - Token exchange configuration (same as exchangeCode)\n * @returns New token response from the OAuth provider\n * @throws Error if token refresh fails\n *\n * @example\n * ```typescript\n * const tokens = await refreshAccessToken(refreshToken, {\n * tokenUrl: OAUTH_PROVIDERS.google.tokenUrl,\n * clientId: env.CLIENT_ID,\n * clientSecret: env.CLIENT_SECRET,\n * redirectUri: 'https://example.com/callback',\n * });\n * ```\n */\nexport async function refreshAccessToken(\n refreshToken: string,\n options: Omit<ExchangeCodeOptions, 'redirectUri'>,\n): Promise<OAuthTokenResponse> {\n const { tokenUrl, clientId, clientSecret, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n });\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n\n if (authMethod === 'basic') {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.status} ${errorText}`);\n }\n\n return response.json();\n}\n\n/**\n * Revokes an OAuth token.\n *\n * @param options - Token revocation configuration\n * @returns True if revocation succeeded\n * @throws Error if revocation fails\n *\n * @example\n * ```typescript\n * await revokeToken({\n * revokeUrl: OAUTH_PROVIDERS.google.revokeUrl!,\n * token: refreshToken,\n * tokenTypeHint: 'refresh_token',\n * });\n * ```\n */\nexport async function revokeToken(options: RevokeTokenOptions): Promise<boolean> {\n const { revokeUrl, token, tokenTypeHint, clientId, clientSecret, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({ token });\n if (tokenTypeHint) {\n body.set('token_type_hint', tokenTypeHint);\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (authMethod === 'basic' && clientId && clientSecret) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else if (clientId && clientSecret) {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(revokeUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n // Some providers return 200, others return 204 for successful revocation.\n return response.ok;\n}\n\n// =============================================================================\n// Authorization URL Builder\n// =============================================================================\n\n/** Options for building an authorization URL. */\nexport interface AuthorizationUrlOptions {\n /** Authorization endpoint URL. */\n authorizationUrl: string;\n /** OAuth client ID. */\n clientId: string;\n /** Redirect URI for OAuth callback. */\n redirectUri: string;\n /** Requested scopes. */\n scopes: string[];\n /** State parameter (use encodeOAuthState to generate). */\n state: string;\n /** Response type (default: 'code'). */\n responseType?: string;\n /** Additional provider-specific parameters. */\n extraParams?: Record<string, string>;\n}\n\n/**\n * Builds an OAuth authorization URL.\n *\n * @param options - Authorization URL configuration\n * @returns The complete authorization URL\n *\n * @example\n * ```typescript\n * const state = await encodeOAuthState({ uid: 'user-123' }, SECRET);\n * const authUrl = buildAuthorizationUrl({\n * authorizationUrl: OAUTH_PROVIDERS.google.authorizationUrl,\n * clientId: env.CLIENT_ID,\n * redirectUri: 'https://example.com/callback',\n * scopes: ['openid', 'email', 'profile'],\n * state,\n * extraParams: {\n * access_type: 'offline',\n * prompt: 'consent',\n * },\n * });\n * ```\n */\nexport function buildAuthorizationUrl(options: AuthorizationUrlOptions): string {\n const {\n authorizationUrl,\n clientId,\n redirectUri,\n scopes,\n state,\n responseType = 'code',\n extraParams = {},\n } = options;\n\n const params = new URLSearchParams({\n response_type: responseType,\n client_id: clientId,\n redirect_uri: redirectUri,\n scope: scopes.join(' '),\n state,\n ...extraParams,\n });\n\n return `${authorizationUrl}?${params.toString()}`;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["OAUTH_PROVIDERS: Record<string, OAuthProvider>","headers: Record<string, string>"],"sources":["../../src/auth/oauth.ts"],"sourcesContent":["/**\n * @fileoverview OAuth 2.0 utilities for @fresho/router.\n *\n * Provides reusable primitives for implementing OAuth 2.0 Authorization Code flows.\n * This implementation is designed as a confidential client suitable for server-side\n * applications that can securely store client secrets.\n *\n * ## Design Decisions\n *\n * ### Why Not PKCE?\n *\n * PKCE (Proof Key for Code Exchange, RFC 7636) is a security extension designed to\n * protect against authorization code interception attacks. However:\n *\n * - PKCE is **required** only for public clients (mobile apps, SPAs without backend)\n * - PKCE is **optional** for confidential clients that can securely store secrets\n * - These utilities assume a confidential client with a `client_secret`\n * - The `client_secret` provides equivalent protection during token exchange\n *\n * ### HMAC-Signed State Parameter\n *\n * Instead of PKCE, we provide HMAC-signed state utilities that:\n *\n * 1. **Prevent CSRF attacks** - The signature is verified on callback\n * 2. **Carry custom data** - Embed arbitrary data (e.g., user ID) in the state\n * 3. **Include a nonce** - Random bytes prevent replay attacks\n * 4. **Use Web Crypto API** - Works in Cloudflare Workers, Deno, and browsers\n *\n * ## Provider Compatibility\n *\n * This implementation pattern works with ~60-70% of OAuth 2.0 providers:\n *\n * | Provider | PKCE | Auth Method | Compatible |\n * |------------|----------|-------------|------------|\n * | Google | Optional | Body | ✅ Yes |\n * | GitHub | None | Basic Auth | ✅ Minor tweak |\n * | Slack | None | Body | ✅ Yes |\n * | LinkedIn | None | Body | ✅ Yes |\n * | Spotify | Optional | Basic Auth | ✅ Yes |\n * | Discord | Optional | Body | ✅ Yes |\n * | Dropbox | None | Basic Auth | ✅ Minor tweak |\n * | Twitter | Required | - | ❌ Needs PKCE |\n * | TikTok | Required | - | ❌ Needs PKCE |\n *\n * @see https://tools.ietf.org/html/rfc6749 - OAuth 2.0 Authorization Framework\n * @see https://tools.ietf.org/html/rfc7636 - PKCE Extension\n *\n * @example\n * ```typescript\n * import { encodeOAuthState, decodeOAuthState, exchangeCode } from '@fresho/router/middleware';\n *\n * // In your authorize route:\n * const state = await encodeOAuthState({ uid: 'user-123' }, SECRET);\n * const authUrl = `https://provider.com/oauth/authorize?state=${state}&...`;\n *\n * // In your callback route:\n * const data = await decodeOAuthState(state, SECRET);\n * if (data) {\n * const tokens = await exchangeCode(code, { ... });\n * }\n * ```\n */\n\n// =============================================================================\n// Types\n// =============================================================================\n\n/** OAuth 2.0 token response as per RFC 6749. */\nexport interface OAuthTokenResponse {\n /** The access token issued by the authorization server. */\n access_token: string;\n /** The refresh token (optional, returned with offline access). */\n refresh_token?: string;\n /** The type of token (typically \"Bearer\"). */\n token_type: string;\n /** The lifetime in seconds of the access token. */\n expires_in: number;\n /** The scopes granted by the authorization server. */\n scope?: string;\n /** OpenID Connect ID token (if openid scope was requested). */\n id_token?: string;\n}\n\n/** OAuth 2.0 provider configuration. */\nexport interface OAuthProvider {\n /** Authorization endpoint URL. */\n authorizationUrl: string;\n /** Token endpoint URL. */\n tokenUrl: string;\n /** Token revocation endpoint URL (optional). */\n revokeUrl?: string;\n /** User info endpoint URL (optional). */\n userInfoUrl?: string;\n}\n\n/** Common OAuth 2.0 providers with their endpoints. */\nexport const OAUTH_PROVIDERS: Record<string, OAuthProvider> = {\n google: {\n authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth',\n tokenUrl: 'https://oauth2.googleapis.com/token',\n revokeUrl: 'https://oauth2.googleapis.com/revoke',\n userInfoUrl: 'https://www.googleapis.com/oauth2/v3/userinfo',\n },\n github: {\n authorizationUrl: 'https://github.com/login/oauth/authorize',\n tokenUrl: 'https://github.com/login/oauth/access_token',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.github.com/user',\n },\n discord: {\n authorizationUrl: 'https://discord.com/oauth2/authorize',\n tokenUrl: 'https://discord.com/api/oauth2/token',\n revokeUrl: 'https://discord.com/api/oauth2/token/revoke',\n userInfoUrl: 'https://discord.com/api/users/@me',\n },\n slack: {\n authorizationUrl: 'https://slack.com/openid/connect/authorize',\n tokenUrl: 'https://slack.com/api/openid.connect.token',\n revokeUrl: undefined,\n userInfoUrl: undefined,\n },\n linkedin: {\n authorizationUrl: 'https://www.linkedin.com/oauth/v2/authorization',\n tokenUrl: 'https://www.linkedin.com/oauth/v2/accessToken',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.linkedin.com/v2/userinfo',\n },\n spotify: {\n authorizationUrl: 'https://accounts.spotify.com/authorize',\n tokenUrl: 'https://accounts.spotify.com/api/token',\n revokeUrl: undefined,\n userInfoUrl: 'https://api.spotify.com/v1/me',\n },\n dropbox: {\n authorizationUrl: 'https://www.dropbox.com/oauth2/authorize',\n tokenUrl: 'https://api.dropboxapi.com/oauth2/token',\n revokeUrl: 'https://api.dropboxapi.com/2/auth/token/revoke',\n userInfoUrl: undefined,\n },\n};\n\n/** Token endpoint authentication method. */\nexport type TokenAuthMethod = 'body' | 'basic';\n\n/** Configuration for token exchange. */\nexport interface ExchangeCodeOptions {\n /** Token endpoint URL. */\n tokenUrl: string;\n /** OAuth client ID. */\n clientId: string;\n /** OAuth client secret. */\n clientSecret: string;\n /** Redirect URI used in authorization request. */\n redirectUri: string;\n /** Authentication method (default: 'body'). */\n authMethod?: TokenAuthMethod;\n}\n\n/** Configuration for token revocation. */\nexport interface RevokeTokenOptions {\n /** Revocation endpoint URL. */\n revokeUrl: string;\n /** Token to revoke. */\n token: string;\n /** Token type hint (optional, e.g., 'refresh_token' or 'access_token'). */\n tokenTypeHint?: string;\n /** OAuth client ID (for providers that require it). */\n clientId?: string;\n /** OAuth client secret (for providers that require it). */\n clientSecret?: string;\n /** Authentication method (default: 'body'). */\n authMethod?: TokenAuthMethod;\n}\n\n// =============================================================================\n// State Encoding/Decoding (HMAC-signed)\n// =============================================================================\n\n/**\n * Encodes arbitrary data into an HMAC-signed state parameter.\n *\n * The state is base64url-encoded and includes:\n * - The JSON-serialized payload\n * - A random nonce (12 bytes) for replay protection\n * - An HMAC-SHA256 signature (truncated to 16 hex chars)\n *\n * @param data - Arbitrary data to encode in the state\n * @param secret - Secret key for HMAC signing\n * @returns Base64url-encoded state string\n *\n * @example\n * ```typescript\n * const state = await encodeOAuthState({ uid: 'user-123', returnTo: '/dashboard' }, SECRET);\n * // Use in OAuth authorization URL\n * ```\n */\nexport async function encodeOAuthState(\n data: Record<string, unknown>,\n secret: string,\n ttlMs = 600_000,\n): Promise<string> {\n // Generate random nonce.\n const nonceBytes = new Uint8Array(12);\n crypto.getRandomValues(nonceBytes);\n const nonce = btoa(String.fromCharCode(...nonceBytes))\n .replace(/\\+/g, '-')\n .replace(/\\//g, '_')\n .replace(/=/g, '');\n\n const exp = typeof data._exp === 'number' ? data._exp : Date.now() + ttlMs;\n const payload = JSON.stringify({ ...data, _nonce: nonce, _exp: exp });\n\n // Generate HMAC signature.\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(payload));\n const signatureHex = Array.from(new Uint8Array(signature))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n // Encode the full state.\n const stateData = JSON.stringify({ payload, sig: signatureHex });\n return btoa(stateData).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=/g, '');\n}\n\n/**\n * Decodes and verifies an HMAC-signed state parameter.\n *\n * @param state - Base64url-encoded state string\n * @param secret - Secret key for HMAC verification\n * @returns The decoded data, or null if verification fails\n *\n * @example\n * ```typescript\n * const data = await decodeOAuthState(state, SECRET);\n * if (data) {\n * console.log(data.uid); // 'user-123'\n * }\n * ```\n */\nexport async function decodeOAuthState<T extends Record<string, unknown> = Record<string, unknown>>(\n state: string,\n secret: string,\n): Promise<T | null> {\n try {\n // Decode base64url.\n const base64 = state.replace(/-/g, '+').replace(/_/g, '/');\n const padded = base64.padEnd(base64.length + ((4 - (base64.length % 4)) % 4), '=');\n const stateData = JSON.parse(atob(padded));\n\n const { payload, sig } = stateData;\n if (typeof payload !== 'string' || typeof sig !== 'string' || !/^[0-9a-f]{64}$/i.test(sig)) {\n return null;\n }\n\n const sigBytes = new Uint8Array(32);\n for (let i = 0; i < 32; i++) {\n sigBytes[i] = Number.parseInt(sig.slice(i * 2, i * 2 + 2), 16);\n }\n\n // Verify HMAC signature.\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n 'raw',\n encoder.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['verify'],\n );\n\n const valid = await crypto.subtle.verify('HMAC', key, sigBytes, encoder.encode(payload));\n if (!valid) {\n return null;\n }\n\n const payloadData = JSON.parse(payload);\n if (typeof payloadData._exp !== 'number' || Date.now() >= payloadData._exp) {\n return null;\n }\n delete payloadData._nonce;\n delete payloadData._exp;\n return payloadData as T;\n } catch {\n return null;\n }\n}\n\n// =============================================================================\n// Token Exchange\n// =============================================================================\n\n/**\n * Exchanges an authorization code for tokens.\n *\n * @param code - Authorization code from OAuth callback\n * @param options - Token exchange configuration\n * @returns Token response from the OAuth provider\n * @throws Error if token exchange fails\n *\n * @example\n * ```typescript\n * const tokens = await exchangeCode(code, {\n * tokenUrl: OAUTH_PROVIDERS.google.tokenUrl,\n * clientId: env.CLIENT_ID,\n * clientSecret: env.CLIENT_SECRET,\n * redirectUri: 'https://example.com/callback',\n * });\n * ```\n */\nexport async function exchangeCode(\n code: string,\n options: ExchangeCodeOptions,\n): Promise<OAuthTokenResponse> {\n const { tokenUrl, clientId, clientSecret, redirectUri, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n code,\n redirect_uri: redirectUri,\n });\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n\n if (authMethod === 'basic') {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token exchange failed: ${response.status} ${errorText}`);\n }\n\n return response.json();\n}\n\n/**\n * Refreshes an access token using a refresh token.\n *\n * @param refreshToken - The refresh token\n * @param options - Token exchange configuration (same as exchangeCode)\n * @returns New token response from the OAuth provider\n * @throws Error if token refresh fails\n *\n * @example\n * ```typescript\n * const tokens = await refreshAccessToken(refreshToken, {\n * tokenUrl: OAUTH_PROVIDERS.google.tokenUrl,\n * clientId: env.CLIENT_ID,\n * clientSecret: env.CLIENT_SECRET,\n * redirectUri: 'https://example.com/callback',\n * });\n * ```\n */\nexport async function refreshAccessToken(\n refreshToken: string,\n options: Omit<ExchangeCodeOptions, 'redirectUri'>,\n): Promise<OAuthTokenResponse> {\n const { tokenUrl, clientId, clientSecret, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n });\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n Accept: 'application/json',\n };\n\n if (authMethod === 'basic') {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(tokenUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new Error(`Token refresh failed: ${response.status} ${errorText}`);\n }\n\n return response.json();\n}\n\n/**\n * Revokes an OAuth token.\n *\n * @param options - Token revocation configuration\n * @returns True if revocation succeeded\n * @throws Error if revocation fails\n *\n * @example\n * ```typescript\n * await revokeToken({\n * revokeUrl: OAUTH_PROVIDERS.google.revokeUrl!,\n * token: refreshToken,\n * tokenTypeHint: 'refresh_token',\n * });\n * ```\n */\nexport async function revokeToken(options: RevokeTokenOptions): Promise<boolean> {\n const { revokeUrl, token, tokenTypeHint, clientId, clientSecret, authMethod = 'body' } = options;\n\n const body = new URLSearchParams({ token });\n if (tokenTypeHint) {\n body.set('token_type_hint', tokenTypeHint);\n }\n\n const headers: Record<string, string> = {\n 'Content-Type': 'application/x-www-form-urlencoded',\n };\n\n if (authMethod === 'basic' && clientId && clientSecret) {\n headers.Authorization = `Basic ${btoa(`${clientId}:${clientSecret}`)}`;\n } else if (clientId && clientSecret) {\n body.set('client_id', clientId);\n body.set('client_secret', clientSecret);\n }\n\n const response = await fetch(revokeUrl, {\n method: 'POST',\n headers,\n body: body.toString(),\n });\n\n // Some providers return 200, others return 204 for successful revocation.\n return response.ok;\n}\n\n// =============================================================================\n// Authorization URL Builder\n// =============================================================================\n\n/** Options for building an authorization URL. */\nexport interface AuthorizationUrlOptions {\n /** Authorization endpoint URL. */\n authorizationUrl: string;\n /** OAuth client ID. */\n clientId: string;\n /** Redirect URI for OAuth callback. */\n redirectUri: string;\n /** Requested scopes. */\n scopes: string[];\n /** State parameter (use encodeOAuthState to generate). */\n state: string;\n /** Response type (default: 'code'). */\n responseType?: string;\n /** Additional provider-specific parameters. */\n extraParams?: Record<string, string>;\n}\n\n/**\n * Builds an OAuth authorization URL.\n *\n * @param options - Authorization URL configuration\n * @returns The complete authorization URL\n *\n * @example\n * ```typescript\n * const state = await encodeOAuthState({ uid: 'user-123' }, SECRET);\n * const authUrl = buildAuthorizationUrl({\n * authorizationUrl: OAUTH_PROVIDERS.google.authorizationUrl,\n * clientId: env.CLIENT_ID,\n * redirectUri: 'https://example.com/callback',\n * scopes: ['openid', 'email', 'profile'],\n * state,\n * extraParams: {\n * access_type: 'offline',\n * prompt: 'consent',\n * },\n * });\n * ```\n */\nexport function buildAuthorizationUrl(options: AuthorizationUrlOptions): string {\n const {\n authorizationUrl,\n clientId,\n redirectUri,\n scopes,\n state,\n responseType = 'code',\n extraParams = {},\n } = options;\n\n const params = new URLSearchParams({\n response_type: responseType,\n client_id: clientId,\n redirect_uri: redirectUri,\n scope: scopes.join(' '),\n state,\n ...extraParams,\n });\n\n return `${authorizationUrl}?${params.toString()}`;\n}\n"],"mappings":";;;;AAgGA,MAAaA,kBAAiD;CAC5D,QAAQ;EACN,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,QAAQ;EACN,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,SAAS;EACP,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,OAAO;EACL,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,UAAU;EACR,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,SAAS;EACP,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACD,SAAS;EACP,kBAAkB;EAClB,UAAU;EACV,WAAW;EACX,aAAa;EACd;CACF;;;;;;;;;;;;;;;;;;;AAyDD,eAAsB,iBACpB,MACA,QACA,QAAQ,KACS;CAEjB,MAAM,aAAa,IAAI,WAAW,GAAG;AACrC,QAAO,gBAAgB,WAAW;CAClC,MAAM,QAAQ,KAAK,OAAO,aAAa,GAAG,WAAW,CAAC,CACnD,QAAQ,OAAO,IAAI,CACnB,QAAQ,OAAO,IAAI,CACnB,QAAQ,MAAM,GAAG;CAEpB,MAAM,MAAM,OAAO,KAAK,SAAS,WAAW,KAAK,OAAO,KAAK,KAAK,GAAG;CACrE,MAAM,UAAU,KAAK,UAAU;EAAE,GAAG;EAAM,QAAQ;EAAO,MAAM;EAAK,CAAC;CAGrE,MAAM,UAAU,IAAI,aAAa;CACjC,MAAM,MAAM,MAAM,OAAO,OAAO,UAC9B,OACA,QAAQ,OAAO,OAAO,EACtB;EAAE,MAAM;EAAQ,MAAM;EAAW,EACjC,OACA,CAAC,OAAO,CACT;CAED,MAAM,YAAY,MAAM,OAAO,OAAO,KAAK,QAAQ,KAAK,QAAQ,OAAO,QAAQ,CAAC;CAChF,MAAM,eAAe,MAAM,KAAK,IAAI,WAAW,UAAU,CAAC,CACvD,KAAK,MAAM,EAAE,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC,CAC3C,KAAK,GAAG;CAGX,MAAM,YAAY,KAAK,UAAU;EAAE;EAAS,KAAK;EAAc,CAAC;AAChE,QAAO,KAAK,UAAU,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,OAAO,IAAI,CAAC,QAAQ,MAAM,GAAG;;;;;;;;;;;;;;;;;AAkBlF,eAAsB,iBACpB,OACA,QACmB;AACnB,KAAI;EAEF,MAAM,SAAS,MAAM,QAAQ,MAAM,IAAI,CAAC,QAAQ,MAAM,IAAI;EAC1D,MAAM,SAAS,OAAO,OAAO,OAAO,UAAW,IAAK,OAAO,SAAS,KAAM,GAAI,IAAI;EAGlF,MAAM,EAAE,SAAS,QAFC,KAAK,MAAM,KAAK,OAAO,CAAC;AAG1C,MAAI,OAAO,YAAY,YAAY,OAAO,QAAQ,YAAY,CAAC,kBAAkB,KAAK,IAAI,CACxF,QAAO;EAGT,MAAM,WAAW,IAAI,WAAW,GAAG;AACnC,OAAK,IAAI,IAAI,GAAG,IAAI,IAAI,IACtB,UAAS,KAAK,OAAO,SAAS,IAAI,MAAM,IAAI,GAAG,IAAI,IAAI,EAAE,EAAE,GAAG;EAIhE,MAAM,UAAU,IAAI,aAAa;EACjC,MAAM,MAAM,MAAM,OAAO,OAAO,UAC9B,OACA,QAAQ,OAAO,OAAO,EACtB;GAAE,MAAM;GAAQ,MAAM;GAAW,EACjC,OACA,CAAC,SAAS,CACX;AAGD,MAAI,CADU,MAAM,OAAO,OAAO,OAAO,QAAQ,KAAK,UAAU,QAAQ,OAAO,QAAQ,CAAC,CAEtF,QAAO;EAGT,MAAM,cAAc,KAAK,MAAM,QAAQ;AACvC,MAAI,OAAO,YAAY,SAAS,YAAY,KAAK,KAAK,IAAI,YAAY,KACpE,QAAO;AAET,SAAO,YAAY;AACnB,SAAO,YAAY;AACnB,SAAO;SACD;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;AA0BX,eAAsB,aACpB,MACA,SAC6B;CAC7B,MAAM,EAAE,UAAU,UAAU,cAAc,aAAa,aAAa,WAAW;CAE/E,MAAM,OAAO,IAAI,gBAAgB;EAC/B,YAAY;EACZ;EACA,cAAc;EACf,CAAC;CAEF,MAAMC,UAAkC;EACtC,gBAAgB;EAChB,QAAQ;EACT;AAED,KAAI,eAAe,QACjB,SAAQ,gBAAgB,SAAS,KAAK,GAAG,SAAS,GAAG,eAAe;MAC/D;AACL,OAAK,IAAI,aAAa,SAAS;AAC/B,OAAK,IAAI,iBAAiB,aAAa;;CAGzC,MAAM,WAAW,MAAM,MAAM,UAAU;EACrC,QAAQ;EACR;EACA,MAAM,KAAK,UAAU;EACtB,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,QAAM,IAAI,MAAM,0BAA0B,SAAS,OAAO,GAAG,YAAY;;AAG3E,QAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;;;AAqBxB,eAAsB,mBACpB,cACA,SAC6B;CAC7B,MAAM,EAAE,UAAU,UAAU,cAAc,aAAa,WAAW;CAElE,MAAM,OAAO,IAAI,gBAAgB;EAC/B,YAAY;EACZ,eAAe;EAChB,CAAC;CAEF,MAAMA,UAAkC;EACtC,gBAAgB;EAChB,QAAQ;EACT;AAED,KAAI,eAAe,QACjB,SAAQ,gBAAgB,SAAS,KAAK,GAAG,SAAS,GAAG,eAAe;MAC/D;AACL,OAAK,IAAI,aAAa,SAAS;AAC/B,OAAK,IAAI,iBAAiB,aAAa;;CAGzC,MAAM,WAAW,MAAM,MAAM,UAAU;EACrC,QAAQ;EACR;EACA,MAAM,KAAK,UAAU;EACtB,CAAC;AAEF,KAAI,CAAC,SAAS,IAAI;EAChB,MAAM,YAAY,MAAM,SAAS,MAAM;AACvC,QAAM,IAAI,MAAM,yBAAyB,SAAS,OAAO,GAAG,YAAY;;AAG1E,QAAO,SAAS,MAAM;;;;;;;;;;;;;;;;;;AAmBxB,eAAsB,YAAY,SAA+C;CAC/E,MAAM,EAAE,WAAW,OAAO,eAAe,UAAU,cAAc,aAAa,WAAW;CAEzF,MAAM,OAAO,IAAI,gBAAgB,EAAE,OAAO,CAAC;AAC3C,KAAI,cACF,MAAK,IAAI,mBAAmB,cAAc;CAG5C,MAAMA,UAAkC,EACtC,gBAAgB,qCACjB;AAED,KAAI,eAAe,WAAW,YAAY,aACxC,SAAQ,gBAAgB,SAAS,KAAK,GAAG,SAAS,GAAG,eAAe;UAC3D,YAAY,cAAc;AACnC,OAAK,IAAI,aAAa,SAAS;AAC/B,OAAK,IAAI,iBAAiB,aAAa;;AAUzC,SAPiB,MAAM,MAAM,WAAW;EACtC,QAAQ;EACR;EACA,MAAM,KAAK,UAAU;EACtB,CAAC,EAGc;;;;;;;;;;;;;;;;;;;;;;;;AA+ClB,SAAgB,sBAAsB,SAA0C;CAC9E,MAAM,EACJ,kBACA,UACA,aACA,QACA,OACA,eAAe,QACf,cAAc,EAAE,KACd;AAWJ,QAAO,GAAG,iBAAiB,GATZ,IAAI,gBAAgB;EACjC,eAAe;EACf,WAAW;EACX,cAAc;EACd,OAAO,OAAO,KAAK,IAAI;EACvB;EACA,GAAG;EACJ,CAAC,CAEmC,UAAU"}
@@ -8,9 +8,13 @@ const PRIMITIVE_TYPES = [
8
8
  "boolean",
9
9
  "unknown"
10
10
  ];
11
- /** Checks if a schema field is a nested object (not a type string). */
11
+ /** Checks if a schema field is a nested object (not a type string or [type, description] tuple). */
12
12
  function isNestedSchema(field) {
13
- return typeof field === "object" && field !== null;
13
+ return typeof field === "object" && field !== null && !Array.isArray(field);
14
+ }
15
+ /** Unpacks a schema field into its type string and optional description. */
16
+ function unpackField(field) {
17
+ return Array.isArray(field) ? [field[0], field[1]] : [field, void 0];
14
18
  }
15
19
  /**
16
20
  * Validates and coerces a single primitive value.
@@ -18,14 +22,25 @@ function isNestedSchema(field) {
18
22
  */
19
23
  function validatePrimitive(value, baseType) {
20
24
  switch (baseType) {
21
- case "string": return [
22
- true,
23
- String(value),
24
- null
25
- ];
25
+ case "string":
26
+ if (typeof value !== "string") return [
27
+ false,
28
+ void 0,
29
+ "Expected string"
30
+ ];
31
+ return [
32
+ true,
33
+ value,
34
+ null
35
+ ];
26
36
  case "number": {
37
+ if (typeof value !== "number" && typeof value !== "string" || typeof value === "string" && value.trim() === "") return [
38
+ false,
39
+ void 0,
40
+ "Expected number"
41
+ ];
27
42
  const num = Number(value);
28
- if (Number.isNaN(num)) return [
43
+ if (!Number.isFinite(num)) return [
29
44
  false,
30
45
  void 0,
31
46
  "Expected number"
@@ -87,12 +102,12 @@ function validateField(key, field, value, parentPath = "") {
87
102
  nestedResult.errors
88
103
  ];
89
104
  }
90
- const typeStr = field;
105
+ const [typeStr] = unpackField(field);
91
106
  const isOptional = typeStr.endsWith("?");
92
107
  const isArray = typeStr.includes("[]");
93
108
  let baseType = isOptional ? typeStr.slice(0, -1) : typeStr;
94
109
  if (isArray) baseType = baseType.replace("[]", "");
95
- if (value === void 0 || value === "") {
110
+ if (value === void 0 || value === null || value === "") {
96
111
  if (!isOptional) {
97
112
  errors[fieldPath] = ["Required"];
98
113
  return [
@@ -157,9 +172,9 @@ function validateField(key, field, value, parentPath = "") {
157
172
  function validateSchema(schema, data, parentPath = "") {
158
173
  const result = {};
159
174
  const allErrors = {};
175
+ const source = typeof data === "object" && data !== null && !Array.isArray(data) ? data : {};
160
176
  for (const [key, field] of Object.entries(schema)) {
161
- const value = data[key];
162
- const [success, coerced, fieldErrors] = validateField(key, field, value, parentPath);
177
+ const [success, coerced, fieldErrors] = validateField(key, field, Object.hasOwn(source, key) ? source[key] : void 0, parentPath);
163
178
  if (!success) Object.assign(allErrors, fieldErrors);
164
179
  else if (coerced !== void 0) result[key] = coerced;
165
180
  }
@@ -175,7 +190,9 @@ function validateSchemaDefinition(schema, path = "") {
175
190
  const fieldPath = path ? `${path}.${key}` : key;
176
191
  if (isNestedSchema(field)) validateSchemaDefinition(field, fieldPath);
177
192
  else {
178
- const typeStr = field;
193
+ if (Array.isArray(field) && (field.length !== 2 || typeof field[0] !== "string" || typeof field[1] !== "string")) throw new Error(`Invalid field definition at '${fieldPath}'`);
194
+ const [typeStr] = unpackField(field);
195
+ if (typeof typeStr !== "string") throw new Error(`Unknown type '${String(typeStr)}' at '${fieldPath}'`);
179
196
  let baseType = typeStr.endsWith("?") ? typeStr.slice(0, -1) : typeStr;
180
197
  baseType = baseType.replace("[]", "");
181
198
  if (!PRIMITIVE_TYPES.includes(baseType)) throw new Error(`Unknown type '${typeStr}' at '${fieldPath}'`);
@@ -223,26 +240,20 @@ function compileSchema(schema) {
223
240
  }
224
241
  /**
225
242
  * Converts a schema definition to JSON Schema, recursing into nested objects.
226
- *
227
- * @param descriptions - Field descriptions keyed by name, dotted for nested fields
228
- * @param prefix - Dotted path of `schema` within the root, for nested lookups
229
243
  */
230
- function toJsonSchema(schema, descriptions = {}, prefix = "") {
244
+ function toJsonSchema(schema) {
231
245
  const properties = {};
232
246
  const required = [];
233
247
  for (const [key, field] of Object.entries(schema)) {
234
- const description = descriptions[`${prefix}${key}`];
235
- const described = description === void 0 ? {} : { description };
236
248
  if (isNestedSchema(field)) {
237
- properties[key] = {
238
- ...toJsonSchema(field, descriptions, `${prefix}${key}.`),
239
- ...described
240
- };
249
+ properties[key] = toJsonSchema(field);
241
250
  required.push(key);
242
251
  continue;
243
252
  }
244
- const optional = field.endsWith("?");
245
- const base = optional ? field.slice(0, -1) : field;
253
+ const [typeStr, description] = unpackField(field);
254
+ const described = description === void 0 ? {} : { description };
255
+ const optional = typeStr.endsWith("?");
256
+ const base = optional ? typeStr.slice(0, -1) : typeStr;
246
257
  const primitive = base.replace("[]", "");
247
258
  const item = primitive === "unknown" ? {} : { type: primitive };
248
259
  properties[key] = base.endsWith("[]") ? {
@@ -400,7 +411,13 @@ function createHandler(routerDef) {
400
411
  const match = compiled.pattern.exec(url.pathname);
401
412
  if (!match) continue;
402
413
  const path = {};
403
- for (let i = 0; i < compiled.paramNames.length; i++) path[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);
414
+ let invalidPath = false;
415
+ for (let i = 0; i < compiled.paramNames.length; i++) try {
416
+ path[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);
417
+ } catch {
418
+ invalidPath = true;
419
+ break;
420
+ }
404
421
  const context = {
405
422
  request,
406
423
  path,
@@ -409,8 +426,12 @@ function createHandler(routerDef) {
409
426
  env,
410
427
  executionCtx: ctx
411
428
  };
412
- if (compiled.middleware.length > 0 || compiled.handler || compiled.querySchema || compiled.bodySchema) return stripBodyForHead(await runMiddleware(compiled.middleware, context, async () => {
429
+ if (invalidPath || compiled.middleware.length > 0 || compiled.handler || compiled.querySchema || compiled.bodySchema) return stripBodyForHead(await runMiddleware(compiled.middleware, context, async () => {
413
430
  const routeId = `${compiled.method} ${url.pathname}`;
431
+ if (invalidPath) return Response.json({
432
+ error: "Invalid path parameters",
433
+ route: routeId
434
+ }, { status: 400 });
414
435
  let query = {};
415
436
  if (compiled.querySchema) {
416
437
  const raw = Object.fromEntries(url.searchParams);
@@ -690,13 +711,16 @@ function generateDocs(config) {
690
711
  };
691
712
  if (route$1?.query) {
692
713
  const querySchema = route$1.query;
693
- operation.parameters = Object.entries(querySchema).filter(([, type]) => typeof type === "string").map(([name, type]) => ({
694
- name,
695
- in: "query",
696
- required: !type.endsWith("?"),
697
- description: route$1.descriptions?.[name],
698
- schema: { type: type.replace("?", "").replace("[]", "") }
699
- }));
714
+ operation.parameters = Object.entries(querySchema).filter(([, field]) => !isNestedSchema(field)).map(([name, field]) => {
715
+ const [type, description] = unpackField(field);
716
+ return {
717
+ name,
718
+ in: "query",
719
+ required: !type.endsWith("?"),
720
+ description,
721
+ schema: { type: type.replace("?", "").replace("[]", "") }
722
+ };
723
+ });
700
724
  }
701
725
  if (route$1?.body && [
702
726
  "post",
@@ -704,7 +728,7 @@ function generateDocs(config) {
704
728
  "patch"
705
729
  ].includes(method)) operation.requestBody = {
706
730
  required: true,
707
- content: { "application/json": { schema: toJsonSchema(route$1.body, route$1.descriptions) } }
731
+ content: { "application/json": { schema: toJsonSchema(route$1.body) } }
708
732
  };
709
733
  paths[path][method] = operation;
710
734
  }
@@ -720,5 +744,5 @@ function generateDocs(config) {
720
744
  }
721
745
 
722
746
  //#endregion
723
- export { isFunction as a, compileSchema as c, router as i, toJsonSchema as l, generateDocs as n, isRoute as o, route as r, isRouter as s, collectRoutes as t };
724
- //# sourceMappingURL=docs-B1IFBS_w.mjs.map
747
+ export { isFunction as a, compileSchema as c, unpackField as d, router as i, isNestedSchema as l, generateDocs as n, isRoute as o, route as r, isRouter as s, collectRoutes as t, toJsonSchema as u };
748
+ //# sourceMappingURL=docs-BLjbxLe-.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docs-BLjbxLe-.mjs","names":["errors: Record<string, string[]>","resultArray: unknown[]","success","coerced","errorMsg","result: Record<string, unknown>","allErrors: Record<string, string[]>","properties: Record<string, unknown>","required: string[]","paramNames: string[]","propertyToSegment","compiled: CompiledRoute[]","path: Record<string, string>","context: MiddlewareContext","query: unknown","body: unknown","collectedRoutes: CollectedRoute[]","paths: Record<string, Record<string, object>>","operation: Record<string, unknown>","route"],"sources":["../src/schema.ts","../src/types.ts","../src/handler.ts","../src/core.ts","../src/docs.ts"],"sourcesContent":["/**\n * @fileoverview Schema types and validation utilities.\n *\n * Provides shorthand schema definitions for validating query parameters and request bodies.\n * No external dependencies - uses simple string-based type definitions.\n *\n * Supported types:\n * - Primitives: `'string'`, `'number'`, `'boolean'`\n * - Optional: `'string?'`, `'number?'`, `'boolean?'`\n * - Arrays: `'string[]'`, `'number[]'`, `'boolean[]'`\n * - Optional arrays: `'string[]?'`, `'number[]?'`, `'boolean[]?'`\n * - Described fields: `['string', 'Description']`, `['number?', 'Optional count']`\n * - Nested objects: `{ field: { nested: 'string' } }`\n *\n * @example\n * ```typescript\n * // In route definitions\n * const api = router({\n * users: router({\n * post: route({\n * query: { page: 'number?', limit: ['number?', 'Max results'] },\n * body: {\n * name: ['string', 'Full name'],\n * age: 'number',\n * tags: 'string[]?',\n * address: { city: 'string', zip: 'string?' },\n * },\n * handler: async (c) => {\n * c.query.page; // number | undefined\n * c.body.name; // string\n * c.body.address.city // string\n * },\n * }),\n * }),\n * });\n * ```\n */\n\n/** Primitive type strings. */\nexport type PrimitiveType = 'string' | 'number' | 'boolean' | 'unknown';\n\n/** Optional primitive type strings. */\nexport type OptionalPrimitiveType = 'string?' | 'number?' | 'boolean?' | 'unknown?';\n\n/** Array type strings. */\nexport type ArrayType = 'string[]' | 'number[]' | 'boolean[]' | 'unknown[]';\n\n/** Optional array type strings. */\nexport type OptionalArrayType = 'string[]?' | 'number[]?' | 'boolean[]?' | 'unknown[]?';\n\n/** All supported type strings. */\nexport type SchemaType = PrimitiveType | OptionalPrimitiveType | ArrayType | OptionalArrayType;\n\n/** A schema field: a type string, or a `[type, description]` tuple. */\nexport type SchemaField = SchemaType | readonly [type: SchemaType, description: string];\n\n/** Schema definition using shorthand syntax. Supports nested objects. */\nexport interface SchemaDefinition {\n [key: string]: SchemaField | SchemaDefinition;\n}\n\n/** Maps primitive type strings to TypeScript types. */\nexport type SchemaTypeMap = {\n string: string;\n 'string?': string | undefined;\n number: number;\n 'number?': number | undefined;\n boolean: boolean;\n 'boolean?': boolean | undefined;\n unknown: unknown;\n 'unknown?': unknown | undefined;\n 'string[]': string[];\n 'string[]?': string[] | undefined;\n 'number[]': number[];\n 'number[]?': number[] | undefined;\n 'boolean[]': boolean[];\n 'boolean[]?': boolean[] | undefined;\n 'unknown[]': unknown[];\n 'unknown[]?': unknown[] | undefined;\n};\n\n/** Checks if a schema field type is optional (ends with ?). */\ntype IsOptionalField<T> = T extends `${string}?`\n ? true\n : T extends readonly [`${string}?`, string]\n ? true\n : false;\n\n/** Infers TypeScript type from a schema field (type string, tuple, or nested object). */\nexport type InferSchemaField<T> = T extends SchemaType\n ? SchemaTypeMap[T]\n : T extends readonly [infer S extends SchemaType, string]\n ? SchemaTypeMap[S]\n : T extends SchemaDefinition\n ? InferSchema<T>\n : never;\n\n/** Gets keys of required fields (non-optional types). */\ntype RequiredKeys<T extends SchemaDefinition> = {\n [K in keyof T]: IsOptionalField<T[K]> extends true ? never : K;\n}[keyof T];\n\n/** Gets keys of optional fields (types ending with ?). */\ntype OptionalKeys<T extends SchemaDefinition> = {\n [K in keyof T]: IsOptionalField<T[K]> extends true ? K : never;\n}[keyof T];\n\n/**\n * Infers TypeScript type from schema definition.\n *\n * Required fields become required properties, optional fields (ending with ?)\n * become optional properties with `| undefined`.\n */\nexport type InferSchema<T extends SchemaDefinition> = {\n [K in RequiredKeys<T>]: InferSchemaField<T[K]>;\n} & {\n [K in OptionalKeys<T>]?: InferSchemaField<T[K]>;\n};\n\n/** Error object returned when validation fails. */\nexport interface ValidationError {\n flatten: () => { fieldErrors: Record<string, string[]> };\n}\n\n/** Validation result matching Zod's safeParse API for compatibility. */\nexport type ValidationResult<T> =\n | { success: true; data: T; error?: undefined }\n | { success: false; data?: undefined; error: ValidationError };\n\n/** Compiled schema with validate method. */\nexport interface CompiledSchema<T> {\n safeParse: (data: object) => ValidationResult<T>;\n}\n\n/** Valid base types for primitives and arrays. */\nconst PRIMITIVE_TYPES = ['string', 'number', 'boolean', 'unknown'];\n\n/** Checks if a schema field is a nested object (not a type string or [type, description] tuple). */\nexport function isNestedSchema(field: SchemaField | SchemaDefinition): field is SchemaDefinition {\n return typeof field === 'object' && field !== null && !Array.isArray(field);\n}\n\n/** Unpacks a schema field into its type string and optional description. */\nexport function unpackField(field: SchemaField): [type: SchemaType, description?: string] {\n return Array.isArray(field) ? [field[0], field[1]] : [field as SchemaType, undefined];\n}\n\n/**\n * Validates and coerces a single primitive value.\n * Returns [success, result, errorMessage].\n */\nfunction validatePrimitive(value: unknown, baseType: string): [boolean, unknown, string | null] {\n switch (baseType) {\n case 'string':\n if (typeof value !== 'string') {\n return [false, undefined, 'Expected string'];\n }\n return [true, value, null];\n\n case 'number': {\n if (\n (typeof value !== 'number' && typeof value !== 'string') ||\n (typeof value === 'string' && value.trim() === '')\n ) {\n return [false, undefined, 'Expected number'];\n }\n const num = Number(value);\n if (!Number.isFinite(num)) {\n return [false, undefined, 'Expected number'];\n }\n return [true, num, null];\n }\n\n case 'boolean': {\n if (value === 'true' || value === '1' || value === true) {\n return [true, true, null];\n } else if (value === 'false' || value === '0' || value === false) {\n return [true, false, null];\n }\n return [false, undefined, 'Expected boolean (true/false)'];\n }\n\n case 'unknown':\n // Pass through any value without validation.\n return [true, value, null];\n\n default:\n return [false, undefined, `Unknown type: ${baseType}`];\n }\n}\n\n/**\n * Validates a schema field value (primitive, array, or nested object).\n * Returns [success, result, errors].\n */\nfunction validateField(\n key: string,\n field: SchemaField | SchemaDefinition,\n value: unknown,\n parentPath: string = '',\n): [boolean, unknown, Record<string, string[]>] {\n const fieldPath = parentPath ? `${parentPath}.${key}` : key;\n const errors: Record<string, string[]> = {};\n\n // Handle nested object schemas.\n if (isNestedSchema(field)) {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n errors[fieldPath] = ['Expected object'];\n return [false, undefined, errors];\n }\n // Recursively validate nested schema.\n const nestedResult = validateSchema(field, value as Record<string, unknown>, fieldPath);\n return [nestedResult.success, nestedResult.data, nestedResult.errors];\n }\n\n // Extract type string from field or [type, description] tuple.\n const [typeStr] = unpackField(field);\n const isOptional = typeStr.endsWith('?');\n const isArray = typeStr.includes('[]');\n\n // Strip optional marker for base type extraction.\n let baseType = isOptional ? typeStr.slice(0, -1) : typeStr;\n\n // Strip array marker.\n if (isArray) {\n baseType = baseType.replace('[]', '');\n }\n\n // Handle missing/empty values.\n if (value === undefined || value === null || value === '') {\n if (!isOptional) {\n errors[fieldPath] = ['Required'];\n return [false, undefined, errors];\n }\n return [true, undefined, {}];\n }\n\n // Handle array types.\n if (isArray) {\n if (!Array.isArray(value)) {\n errors[fieldPath] = ['Expected array'];\n return [false, undefined, errors];\n }\n\n const resultArray: unknown[] = [];\n for (let i = 0; i < value.length; i++) {\n const [success, coerced, errorMsg] = validatePrimitive(value[i], baseType);\n if (!success) {\n errors[`${fieldPath}[${i}]`] = [errorMsg!];\n return [false, undefined, errors];\n }\n resultArray.push(coerced);\n }\n return [true, resultArray, {}];\n }\n\n // Handle primitive types.\n const [success, coerced, errorMsg] = validatePrimitive(value, baseType);\n if (!success) {\n errors[fieldPath] = [errorMsg!];\n return [false, undefined, errors];\n }\n return [true, coerced, {}];\n}\n\n/**\n * Validates a full schema against data.\n * Returns { success, data, errors }.\n */\nfunction validateSchema(\n schema: SchemaDefinition,\n data: Record<string, unknown>,\n parentPath: string = '',\n): { success: boolean; data: Record<string, unknown>; errors: Record<string, string[]> } {\n const result: Record<string, unknown> = {};\n const allErrors: Record<string, string[]> = {};\n const source = typeof data === 'object' && data !== null && !Array.isArray(data) ? data : {};\n\n for (const [key, field] of Object.entries(schema)) {\n const value = Object.hasOwn(source, key) ? source[key] : undefined;\n const [success, coerced, fieldErrors] = validateField(key, field, value, parentPath);\n\n if (!success) {\n Object.assign(allErrors, fieldErrors);\n } else if (coerced !== undefined) {\n result[key] = coerced;\n }\n }\n\n return {\n success: Object.keys(allErrors).length === 0,\n data: result,\n errors: allErrors,\n };\n}\n\n/** Validates schema definition at compile time. */\nfunction validateSchemaDefinition(schema: SchemaDefinition, path: string = ''): void {\n for (const [key, field] of Object.entries(schema)) {\n const fieldPath = path ? `${path}.${key}` : key;\n\n if (isNestedSchema(field)) {\n validateSchemaDefinition(field, fieldPath);\n } else {\n if (\n Array.isArray(field) &&\n (field.length !== 2 || typeof field[0] !== 'string' || typeof field[1] !== 'string')\n ) {\n throw new Error(`Invalid field definition at '${fieldPath}'`);\n }\n const [typeStr] = unpackField(field);\n if (typeof typeStr !== 'string') {\n throw new Error(`Unknown type '${String(typeStr)}' at '${fieldPath}'`);\n }\n const isOptional = typeStr.endsWith('?');\n let baseType = isOptional ? typeStr.slice(0, -1) : typeStr;\n baseType = baseType.replace('[]', '');\n\n if (!PRIMITIVE_TYPES.includes(baseType)) {\n throw new Error(`Unknown type '${typeStr}' at '${fieldPath}'`);\n }\n }\n }\n}\n\n/**\n * Compiles a schema definition into a validator.\n *\n * Used internally by the router to validate query parameters and request bodies.\n * Provides a Zod-compatible `safeParse` API for consistency.\n *\n * @param schema - The schema definition object\n * @returns A compiled schema with `safeParse` method\n *\n * @example\n * ```typescript\n * const userSchema = compileSchema({\n * name: 'string',\n * age: 'number',\n * email: 'string?',\n * });\n *\n * const result = userSchema.safeParse({ name: 'Alice', age: 30 });\n * if (result.success) {\n * console.log(result.data.name); // 'Alice'\n * } else {\n * console.log(result.error.flatten().fieldErrors);\n * }\n * ```\n */\nexport function compileSchema<const T extends SchemaDefinition>(\n schema: T,\n): CompiledSchema<InferSchema<T>> {\n // Validate schema structure at compile time.\n validateSchemaDefinition(schema);\n\n return {\n safeParse(data: object): ValidationResult<InferSchema<T>> {\n const {\n success,\n data: result,\n errors,\n } = validateSchema(schema, data as Record<string, unknown>);\n\n if (!success) {\n return {\n success: false,\n error: { flatten: () => ({ fieldErrors: errors }) },\n };\n }\n\n return { success: true, data: result as InferSchema<T> };\n },\n };\n}\n\n/** JSON Schema object produced by {@link toJsonSchema}. */\nexport interface JsonSchemaObject {\n type: 'object';\n properties: Record<string, unknown>;\n /** Omitted when empty, as OpenAPI 3.0 requires. */\n required?: string[];\n}\n\n/**\n * Converts a schema definition to JSON Schema, recursing into nested objects.\n */\nexport function toJsonSchema(schema: SchemaDefinition): JsonSchemaObject {\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n for (const [key, field] of Object.entries(schema)) {\n if (isNestedSchema(field)) {\n properties[key] = toJsonSchema(field);\n required.push(key);\n continue;\n }\n const [typeStr, description] = unpackField(field);\n const described = description === undefined ? {} : { description };\n const optional = typeStr.endsWith('?');\n const base = optional ? typeStr.slice(0, -1) : typeStr;\n const primitive = base.replace('[]', '');\n const item = primitive === 'unknown' ? {} : { type: primitive };\n properties[key] = base.endsWith('[]')\n ? { type: 'array', items: item, ...described }\n : { ...item, ...described };\n if (!optional) required.push(key);\n }\n return { type: 'object', properties, ...(required.length > 0 && { required }) };\n}\n","/**\n * @fileoverview Core type definitions for the routing library.\n *\n * **Path Convention:**\n * - Property names = URL path segments\n * - `$param` prefix = dynamic segment (`:param`)\n * - `get`, `post`, `put`, `patch`, `delete` = HTTP method handlers\n *\n * **Structure:**\n * - `router({ ... })` - groups paths, can have middleware\n * - `route({ query?, body?, handler })` - single method with schemas\n * - Bare functions as shorthand for handlers without schemas\n */\n\nimport type { Middleware } from './middleware.js';\nimport type { InferSchema, SchemaDefinition } from './schema.js';\n\n/** Standard HTTP methods. */\nexport type Method = 'get' | 'post' | 'put' | 'patch' | 'delete' | 'options' | 'head';\n\n/** HTTP method property names. */\nexport const HTTP_METHODS = new Set<string>([\n 'get',\n 'post',\n 'put',\n 'patch',\n 'delete',\n 'options',\n 'head',\n]);\n\n/** Symbol to mark an object as a route definition. */\nexport const ROUTE_MARKER = Symbol.for('@fresho/router:route');\n\n/** Symbol to mark an object as a router. */\nexport const ROUTER_MARKER = Symbol.for('@fresho/router:router');\n\n/**\n * Brand symbol for Router type identification across module boundaries.\n * This enables TypeScript to recognize Router types even when generic\n * type information is lost during cross-package imports.\n */\ndeclare const ROUTER_BRAND: unique symbol;\n\n/** Brand type for Router identification in conditional types. */\nexport type RouterBrand = { readonly [ROUTER_BRAND]: true };\n\n/**\n * Extracts the parameter name from a `$param` property name.\n */\nexport type ExtractParamFromProperty<T extends string> = T extends `$${infer Param}`\n ? Param\n : never;\n\n/**\n * Checks if a property name is a dynamic parameter (starts with $).\n */\nexport type IsParamProperty<T extends string> = T extends `$${string}` ? true : false;\n\n/**\n * Collects path params from a property path array.\n */\nexport type CollectPathParams<Path extends string[]> = Path extends [\n infer Head extends string,\n ...infer Rest extends string[],\n]\n ? (Head extends `$${infer Param}` ? { [K in Param]: string } : {}) & CollectPathParams<Rest>\n : {};\n\n/** Execution context for background tasks (Cloudflare Workers compatible). */\nexport interface ExecutionContext {\n waitUntil(promise: Promise<unknown>): void;\n passThroughOnException(): void;\n}\n\n/**\n * Unified context object passed to handlers.\n */\nexport type Context<\n Q = unknown,\n B = unknown,\n P extends Record<string, string> = Record<string, string>,\n Ctx = {},\n> = {\n /** The original Request. */\n request: Request;\n /** URL path parameters from `$param` segments. */\n path: P;\n /** Query string parameters. */\n query: Q;\n /** Request body. */\n body: B;\n /** Execution context for background tasks. */\n executionCtx?: ExecutionContext;\n /** Environment bindings. */\n env: Ctx extends { env: infer E } ? E : unknown;\n} & Omit<Ctx, 'env'>;\n\n/**\n * Typed response wrapper that carries the response body type.\n */\nexport type TypedResponse<T> = Response & { __responseType?: T };\n\n/**\n * Handler function type.\n */\nexport type TypedHandler<\n Q = unknown,\n B = unknown,\n P extends Record<string, string> = Record<string, string>,\n R = unknown,\n Ctx = {},\n> = (\n context: Context<Q, B, P, Ctx>,\n) => R | Response | TypedResponse<R> | Promise<R | Response | TypedResponse<R>>;\n\n/** MCP tool behavior hints; defaults come from the HTTP method. */\nexport interface ToolAnnotations {\n /** Human-readable tool title. */\n title?: string;\n /** The tool does not modify its environment. */\n readOnlyHint?: boolean;\n /** The tool may perform destructive updates. */\n destructiveHint?: boolean;\n /** Repeating the call with the same arguments has no additional effect. */\n idempotentHint?: boolean;\n /** The tool interacts with external entities. */\n openWorldHint?: boolean;\n}\n\n/**\n * Route definition - a single HTTP method handler with optional schemas.\n *\n * Use `route()` when you need query or body validation schemas.\n * For simple handlers without schemas, use bare functions in the router.\n *\n * @example\n * ```typescript\n * // With schemas\n * get: route({\n * query: { limit: 'number?' },\n * handler: async (c) => ({ items: [], limit: c.query.limit }),\n * })\n *\n * // Without schemas (bare function shorthand)\n * get: async (c) => ({ items: [] })\n * ```\n */\nexport interface RouteDefinition<\n Q extends SchemaDefinition = {},\n B extends SchemaDefinition = {},\n R = unknown,\n P extends Record<string, string> = Record<string, string>,\n Ctx = {},\n> {\n /** Query parameter schema for validation. */\n query?: Q;\n /** Request body schema for validation. */\n body?: B;\n /** Optional description for documentation. */\n description?: string;\n /** Operation name, used as the OpenAPI `operationId` and the MCP tool name. */\n operationId?: string;\n /** MCP tool settings. */\n mcp?: { annotations?: ToolAnnotations };\n /** The request handler function. */\n handler: TypedHandler<InferSchema<Q>, InferSchema<B>, P, R, Ctx>;\n}\n\n/** A bare handler function (shorthand for route without schemas). */\nexport type BareHandler = (\n context: Context<unknown, unknown, Record<string, string>, unknown>,\n) => unknown;\n\n/** Checks if a value is a function. */\nexport function isFunction(value: unknown): value is BareHandler {\n return typeof value === 'function';\n}\n\n/** Checks if entry is a Route (marked with ROUTE_MARKER). */\nexport function isRoute(entry: unknown): entry is RouteDefinition {\n return typeof entry === 'object' && entry !== null && ROUTE_MARKER in entry;\n}\n\n/** Checks if entry is a Router (marked with ROUTER_MARKER). */\nexport function isRouter(entry: unknown): entry is Router<RouterRoutes> {\n return typeof entry === 'object' && entry !== null && ROUTER_MARKER in entry;\n}\n\n/**\n * A method handler - either a route with schemas or a bare function.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport type MethodEntry = RouteDefinition<any, any, any, any, any> | BareHandler;\n\n/**\n * Router routes record.\n *\n * Can contain:\n * - `get`, `post`, `put`, `patch`, `delete` - method handlers (route or function)\n * - Other property names - nested routers (path segments)\n * - `$param` properties - dynamic path segments\n */\nexport type RouterRoutes = {\n get?: MethodEntry;\n post?: MethodEntry;\n put?: MethodEntry;\n patch?: MethodEntry;\n delete?: MethodEntry;\n options?: MethodEntry;\n head?: MethodEntry;\n} & {\n [key: string]: MethodEntry | Router<RouterRoutes>;\n};\n\n/** Handler function signature for the standalone router. */\nexport type FetchHandler = (\n request: Request,\n env?: unknown,\n ctx?: ExecutionContext,\n) => Response | Promise<Response>;\n\n/**\n * Router - groups paths and can have middleware.\n *\n * @example\n * ```typescript\n * const api = router({\n * // Method handlers for this path\n * get: async (c) => [...],\n * post: route({ body: { name: 'string' }, handler: async (c) => c.body }),\n *\n * // Nested path segments\n * users: router({\n * get: async (c) => [...],\n * $id: router({\n * get: async (c) => ({ id: c.path.id }),\n * }),\n * }),\n * });\n * ```\n */\nexport interface Router<T extends RouterRoutes> extends RouterBrand {\n /** Route definitions and nested routers. */\n readonly routes: T;\n /** Middleware applied to all routes in this router. */\n readonly middleware?: Middleware[];\n /**\n * Creates a fetch handler for use with Cloudflare Workers, Deno, Bun, etc.\n */\n handler(): FetchHandler;\n}\n","/**\n * @fileoverview HTTP request handler for @fresho/router.\n *\n * Builds paths from property names:\n * - Regular properties = path segments\n * - `$param` properties = dynamic segments (`:param`)\n * - `get`, `post`, etc. = method handlers\n */\n\nimport type { Middleware, MiddlewareContext } from './middleware.js';\nimport { runMiddleware } from './middleware.js';\nimport type { CompiledSchema } from './schema.js';\nimport { compileSchema } from './schema.js';\nimport type {\n ExecutionContext,\n FetchHandler,\n RouteDefinition,\n Router,\n RouterRoutes,\n} from './types.js';\nimport { HTTP_METHODS, isFunction, isRoute, isRouter } from './types.js';\n\n/** Compiled route with pattern matcher and handler. */\ninterface CompiledRoute {\n method: string;\n pattern: RegExp;\n paramNames: string[];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n handler: (context: any) => unknown;\n middleware: Middleware[];\n querySchema?: CompiledSchema<unknown>;\n bodySchema?: CompiledSchema<unknown>;\n}\n\n/**\n * Escapes special regex characters in a string.\n */\nfunction escapeRegex(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Converts a path with :param segments to a regex pattern.\n */\nfunction pathToRegex(path: string): { pattern: RegExp; paramNames: string[] } {\n const paramNames: string[] = [];\n const parts = path.split(/:(\\w+)/g);\n let regexStr = '';\n\n for (let i = 0; i < parts.length; i++) {\n if (i % 2 === 0) {\n regexStr += escapeRegex(parts[i]);\n } else {\n paramNames.push(parts[i]);\n regexStr += '([^/]+)';\n }\n }\n\n return {\n pattern: new RegExp(`^${regexStr}$`),\n paramNames,\n };\n}\n\n/**\n * Converts a property name to a path segment.\n * - `$param` becomes `:param`\n * - Other names become literal segments\n */\nfunction propertyToSegment(prop: string): string {\n if (prop.startsWith('$')) {\n return `:${prop.slice(1)}`;\n }\n return prop;\n}\n\n/** Collects and compiles all routes from a router tree. */\nfunction compileRoutes(\n routerDef: Router<RouterRoutes>,\n parentPath = '',\n parentMiddleware: Middleware[] = [],\n): CompiledRoute[] {\n const currentMiddleware = [...parentMiddleware, ...(routerDef.middleware || [])];\n const compiled: CompiledRoute[] = [];\n\n for (const [prop, entry] of Object.entries(routerDef.routes)) {\n // Check if entry is a nested router first (takes precedence over method name check).\n // This allows path segments named 'get', 'post', etc. when they contain routers.\n if (isRouter(entry)) {\n // Nested router - recurse with updated path.\n const segment = propertyToSegment(prop);\n const newPath = parentPath ? `${parentPath}/${segment}` : `/${segment}`;\n compiled.push(...compileRoutes(entry, newPath, currentMiddleware));\n } else if (HTTP_METHODS.has(prop)) {\n // Method handler (get, post, etc.) - only when entry is a route or function.\n const method = prop.toUpperCase();\n const path = parentPath || '/';\n const { pattern, paramNames } = pathToRegex(path);\n\n if (isFunction(entry)) {\n // Bare function handler.\n compiled.push({\n method,\n pattern,\n paramNames,\n handler: entry,\n middleware: currentMiddleware,\n });\n } else if (isRoute(entry)) {\n // Route with schemas.\n const routeDef = entry as RouteDefinition;\n compiled.push({\n method,\n pattern,\n paramNames,\n handler: routeDef.handler,\n middleware: currentMiddleware,\n querySchema: routeDef.query ? compileSchema(routeDef.query) : undefined,\n bodySchema: routeDef.body ? compileSchema(routeDef.body) : undefined,\n });\n }\n }\n }\n\n return compiled;\n}\n\n/**\n * Strips the body from a response for HEAD requests.\n */\nfunction stripBodyForHead(response: Response, isHead: boolean): Response {\n if (!isHead) return response;\n return new Response(null, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n });\n}\n\n/**\n * Creates a fetch handler from a router definition.\n *\n * @example\n * ```typescript\n * const api = router({\n * health: router({\n * get: async () => ({ status: 'ok' }),\n * }),\n * users: router({\n * get: async () => [...],\n * $id: router({\n * get: async (c) => ({ id: c.path.id }),\n * }),\n * }),\n * });\n *\n * export default { fetch: api.handler() };\n * ```\n */\nexport function createHandler<T extends RouterRoutes>(routerDef: Router<T>): FetchHandler {\n const compiledRoutes = compileRoutes(routerDef);\n\n return async (request: Request, env?: unknown, ctx?: ExecutionContext): Promise<Response> => {\n const url = new URL(request.url);\n const method = request.method.toUpperCase();\n const isHead = method === 'HEAD';\n\n // Find matching route.\n for (const compiled of compiledRoutes) {\n const methodMatches =\n compiled.method === method ||\n method === 'OPTIONS' ||\n (method === 'HEAD' && compiled.method === 'GET');\n if (!methodMatches) continue;\n\n const match = compiled.pattern.exec(url.pathname);\n if (!match) continue;\n\n // Extract path parameters.\n const path: Record<string, string> = {};\n let invalidPath = false;\n for (let i = 0; i < compiled.paramNames.length; i++) {\n try {\n path[compiled.paramNames[i]] = decodeURIComponent(match[i + 1]);\n } catch {\n invalidPath = true;\n break;\n }\n }\n\n // Create middleware context.\n const context: MiddlewareContext = {\n request,\n path,\n query: {},\n body: {},\n env,\n executionCtx: ctx,\n };\n\n // Run middleware and handler.\n if (\n invalidPath ||\n compiled.middleware.length > 0 ||\n compiled.handler ||\n compiled.querySchema ||\n compiled.bodySchema\n ) {\n const response = await runMiddleware(compiled.middleware, context, async () => {\n const routeId = `${compiled.method} ${url.pathname}`;\n if (invalidPath) {\n return Response.json(\n { error: 'Invalid path parameters', route: routeId },\n { status: 400 },\n );\n }\n\n // Validate query params.\n let query: unknown = {};\n if (compiled.querySchema) {\n const raw = Object.fromEntries(url.searchParams);\n const result = compiled.querySchema.safeParse(raw);\n if (!result.success) {\n return Response.json(\n {\n error: 'Invalid query parameters',\n route: routeId,\n details: result.error.flatten(),\n },\n { status: 400 },\n );\n }\n query = result.data;\n }\n\n // Validate body.\n let body: unknown = {};\n if (compiled.bodySchema && ['POST', 'PUT', 'PATCH'].includes(method)) {\n const raw = await request.json().catch(() => ({}));\n const result = compiled.bodySchema.safeParse(raw);\n if (!result.success) {\n return Response.json(\n { error: 'Invalid request body', route: routeId, details: result.error.flatten() },\n { status: 400 },\n );\n }\n body = result.data;\n }\n\n context.query = query;\n context.body = body;\n\n if (compiled.handler) {\n // Build handler context with middleware extensions.\n const handlerContext = {\n request,\n path,\n query,\n body,\n env,\n executionCtx: ctx,\n };\n\n // Copy middleware extensions.\n for (const key of Object.keys(context)) {\n if (!['request', 'path', 'query', 'body', 'env', 'executionCtx'].includes(key)) {\n (handlerContext as Record<string, unknown>)[key] = (\n context as Record<string, unknown>\n )[key];\n }\n }\n\n const result = await compiled.handler(handlerContext);\n if (result instanceof Response) {\n return result;\n }\n return Response.json(result);\n }\n\n return Response.json({});\n });\n return stripBodyForHead(response, isHead);\n }\n\n return stripBodyForHead(Response.json({}), isHead);\n }\n\n return Response.json({ error: 'Not Found' }, { status: 404 });\n };\n}\n","/**\n * @fileoverview Core route and router creation functions.\n *\n * ## Path Convention\n * - Property names = URL path segments\n * - `$param` prefix = dynamic segment (`:param`)\n * - `get`, `post`, `put`, `patch`, `delete` = HTTP method handlers\n *\n * ## Typing Best Practices\n *\n * **Schemas** (`query`/`body`) provide runtime validation AND type inference.\n * Use them for any input that needs validation:\n * ```typescript\n * get: route({\n * query: { limit: 'number?' },\n * handler: async (c) => c.query.limit, // limit: number | undefined\n * })\n * ```\n *\n * **Context** (`route.ctx<T>()`) provides types only (no validation).\n * Use it for path params, env bindings, and middleware-injected values:\n * ```typescript\n * interface MyContext {\n * path: { id: string };\n * env: { DB: Database };\n * user: { name: string }; // from auth middleware\n * }\n * get: route.ctx<MyContext>()({\n * handler: async (c) => ({ id: c.path.id, user: c.user.name }),\n * })\n * ```\n *\n * **Important:** Don't add explicit type annotations to handler parameters.\n * Let types flow from schemas and context:\n * ```typescript\n * // GOOD: types inferred from schema\n * handler: async (c) => c.query.limit\n *\n * // BAD: redundant type annotation\n * handler: async (c: { query: { limit?: number } }) => c.query.limit\n * ```\n */\n\nimport { createHandler } from './handler.js';\nimport type { Middleware } from './middleware.js';\nimport type { SchemaDefinition } from './schema.js';\nimport type { RouteDefinition, Router, RouterRoutes } from './types.js';\nimport { ROUTE_MARKER, ROUTER_MARKER } from './types.js';\n\n/**\n * Creates a route with query/body validation schemas.\n *\n * Use `route()` when you need request validation. For simple handlers\n * without validation, you can use bare functions directly in the router.\n *\n * @example\n * ```typescript\n * // Route with query validation\n * get: route({\n * query: { limit: 'number?', offset: 'number?' },\n * handler: async (c) => {\n * const items = await db.list(c.query.limit, c.query.offset);\n * return { items };\n * },\n * })\n *\n * // Route with body validation\n * post: route({\n * body: { name: 'string', email: 'string' },\n * handler: async (c) => {\n * const user = await db.create(c.body);\n * return user;\n * },\n * })\n *\n * // Simple handler without validation (bare function)\n * get: async () => ({ status: 'ok' })\n * ```\n */\nexport function route<\n const Q extends SchemaDefinition = {},\n const B extends SchemaDefinition = {},\n R = unknown,\n>(definition: RouteDefinition<Q, B, R, {}, {}>): RouteDefinition<Q, B, R, {}, {}> {\n return { ...definition, [ROUTE_MARKER]: true } as RouteDefinition<Q, B, R, {}, {}>;\n}\n\n/** Return type of route.ctx<T>() - callable and chainable. */\ninterface CtxBuilder<Ctx> {\n <const Q extends SchemaDefinition = {}, const B extends SchemaDefinition = {}, R = unknown>(\n definition: RouteDefinition<Q, B, R, {}, Ctx>,\n ): RouteDefinition<Q, B, R, {}, Ctx>;\n\n ctx<AdditionalCtx>(): CtxBuilder<Ctx & AdditionalCtx>;\n}\n\n/** Creates a chainable context builder. */\nfunction createCtxBuilder<Ctx>(): CtxBuilder<Ctx> {\n const builder = <\n const Q extends SchemaDefinition = {},\n const B extends SchemaDefinition = {},\n R = unknown,\n >(\n definition: RouteDefinition<Q, B, R, {}, Ctx>,\n ): RouteDefinition<Q, B, R, {}, Ctx> =>\n ({ ...definition, [ROUTE_MARKER]: true }) as RouteDefinition<Q, B, R, {}, Ctx>;\n\n builder.ctx = <AdditionalCtx>() => createCtxBuilder<Ctx & AdditionalCtx>();\n\n return builder as CtxBuilder<Ctx>;\n}\n\n/**\n * Creates a route with typed context for values not covered by schemas.\n *\n * Use `route.ctx<T>()` to type:\n * - **Path params**: `{ path: { id: string } }` for `$id` segments\n * - **Env bindings**: `{ env: { DB: Database } }` for runtime environment\n * - **Middleware values**: `{ user: User }` for auth middleware, etc.\n *\n * Context provides types only, not runtime validation. For validated inputs,\n * use `query` and `body` schemas instead.\n *\n * @example\n * ```typescript\n * interface AppContext {\n * path: { id: string };\n * env: { DB: D1Database };\n * user: { id: string }; // injected by auth middleware\n * }\n *\n * $id: router({\n * get: route.ctx<AppContext>()({\n * query: { include: 'string?' }, // schema for validation\n * handler: async (c) => {\n * // c.path.id, c.env.DB, c.user.id - from context\n * // c.query.include - from schema\n * return c.env.DB.get(c.path.id);\n * },\n * }),\n * })\n * ```\n */\nroute.ctx = <Ctx>(): CtxBuilder<Ctx> => createCtxBuilder<Ctx>();\n\n/**\n * Creates a router that groups paths and applies middleware.\n *\n * @example\n * ```typescript\n * const api = router({\n * health: router({\n * get: async () => ({ status: 'ok' }),\n * }),\n *\n * users: router({\n * // GET /users - list users\n * get: route({\n * query: { limit: 'number?' },\n * handler: async (c) => db.users.list(c.query.limit),\n * }),\n *\n * // POST /users - create user\n * post: route({\n * body: { name: 'string', email: 'string' },\n * handler: async (c) => db.users.create(c.body),\n * }),\n *\n * // /users/:id\n * $id: router({\n * get: async (c) => db.users.get(c.path.id),\n * delete: async (c) => db.users.delete(c.path.id),\n * }),\n * }),\n * });\n *\n * export default { fetch: api.handler() };\n * ```\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport function router<T extends RouterRoutes, M extends Middleware<any>[]>(\n routes: T,\n ...middleware: M\n): Router<T> {\n // Cast needed because RouterBrand uses a type-only symbol declaration.\n const self = {\n routes,\n middleware: middleware.length > 0 ? middleware : undefined,\n handler() {\n return createHandler(self);\n },\n } as unknown as Router<T>;\n // Add marker for runtime type checking.\n (self as unknown as Record<symbol, boolean>)[ROUTER_MARKER] = true;\n return self;\n}\n","/**\n * @fileoverview OpenAPI documentation generation.\n *\n * Generates OpenAPI 3.0 documentation from router definitions.\n *\n * **Path Convention:**\n * - Property names = URL path segments\n * - `$param` prefix = dynamic segment (`{param}` in OpenAPI)\n * - `get`, `post`, `put`, `patch`, `delete` = HTTP method handlers\n */\n\nimport {\n isNestedSchema,\n type SchemaDefinition,\n type SchemaField,\n toJsonSchema,\n unpackField,\n} from './schema.js';\nimport type { RouteDefinition, Router, RouterRoutes } from './types.js';\nimport { HTTP_METHODS, isFunction, isRoute, isRouter } from './types.js';\n\n/** Collected route info for documentation. */\nexport interface CollectedRoute {\n path: string;\n method: string;\n route: RouteDefinition | null;\n}\n\n/** Converts property name to path segment, handling $param convention. */\nfunction propertyToSegment(prop: string): string {\n if (prop.startsWith('$')) {\n return `{${prop.slice(1)}}`;\n }\n return prop;\n}\n\n/** Collects all routes from a router tree, with `{param}` path segments. */\nexport function collectRoutes(routerDef: Router<RouterRoutes>, parentPath = ''): CollectedRoute[] {\n const collectedRoutes: CollectedRoute[] = [];\n\n for (const [prop, entry] of Object.entries(routerDef.routes)) {\n // Check if this is a method handler.\n if (HTTP_METHODS.has(prop)) {\n const path = parentPath || '/';\n if (isFunction(entry)) {\n collectedRoutes.push({ path, method: prop, route: null });\n } else if (isRoute(entry)) {\n collectedRoutes.push({ path, method: prop, route: entry });\n }\n } else if (isRouter(entry)) {\n // Nested router - recurse with updated path.\n const segment = propertyToSegment(prop);\n const newPath = parentPath ? `${parentPath}/${segment}` : `/${segment}`;\n collectedRoutes.push(...collectRoutes(entry, newPath));\n }\n }\n\n return collectedRoutes;\n}\n\n/** Generates OpenAPI documentation from a router. */\nexport function generateDocs(config: {\n title: string;\n version: string;\n description?: string;\n router: Router<RouterRoutes>;\n}): object {\n const paths: Record<string, Record<string, object>> = {};\n const allRoutes = collectRoutes(config.router);\n\n for (const { path, method, route } of allRoutes) {\n if (!paths[path]) {\n paths[path] = {};\n }\n\n const operation: Record<string, unknown> = {\n operationId: route?.operationId,\n description: route?.description,\n responses: {\n 200: { description: 'Successful response' },\n 400: { description: 'Validation error' },\n },\n };\n\n // Add query parameters (only primitive types supported in query strings).\n if (route?.query) {\n const querySchema = route.query as SchemaDefinition;\n operation.parameters = Object.entries(querySchema)\n .filter(([, field]) => !isNestedSchema(field))\n .map(([name, field]) => {\n const [type, description] = unpackField(field as SchemaField);\n return {\n name,\n in: 'query',\n required: !type.endsWith('?'),\n description,\n schema: { type: type.replace('?', '').replace('[]', '') },\n };\n });\n }\n\n // Add request body.\n if (route?.body && ['post', 'put', 'patch'].includes(method)) {\n operation.requestBody = {\n required: true,\n content: {\n 'application/json': {\n schema: toJsonSchema(route.body as SchemaDefinition),\n },\n },\n };\n }\n\n paths[path][method] = operation;\n }\n\n return {\n openapi: '3.0.0',\n info: {\n title: config.title,\n version: config.version,\n description: config.description,\n },\n paths,\n };\n}\n"],"mappings":"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"}
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as InferSchema, D as ValidationResult, E as SchemaTypeMap, O as compileSchema, S as CompiledSchema, T as SchemaType, _ as TypedHandler, a as runMiddleware, b as isRoute, c as ExecutionContext, d as MethodEntry, f as RouteDefinition, g as ToolAnnotations, h as RouterRoutes, l as FetchHandler, m as RouterBrand, n as MiddlewareContext, o as CollectPathParams, p as Router, r as MiddlewareNext, s as Context, t as Middleware, u as Method, v as TypedResponse, w as SchemaDefinition, x as isRouter, y as isFunction } from "./middleware-zRMBpTLe.mjs";
1
+ import { C as InferSchema, D as SchemaTypeMap, E as SchemaType, O as ValidationResult, S as CompiledSchema, T as SchemaField, _ as TypedHandler, a as runMiddleware, b as isRoute, c as ExecutionContext, d as MethodEntry, f as RouteDefinition, g as ToolAnnotations, h as RouterRoutes, k as compileSchema, l as FetchHandler, m as RouterBrand, n as MiddlewareContext, o as CollectPathParams, p as Router, r as MiddlewareNext, s as Context, t as Middleware, u as Method, v as TypedResponse, w as SchemaDefinition, x as isRouter, y as isFunction } from "./middleware-Cj1yHSJF.mjs";
2
2
 
3
3
  //#region src/core.d.ts
4
4
 
@@ -411,5 +411,5 @@ declare function streamJsonLines(handler: (send: (data: object) => void, close:
411
411
  headers?: HeadersInit;
412
412
  }): Response;
413
413
  //#endregion
414
- export { type CollectPathParams, type CompiledSchema, type Context, type ExecutionContext, type FetchHandler, type HttpClient, type HttpClientConfig, type HttpRequestOptions, type InferSchema, type LocalClient, type LocalClientConfig, type LocalRequestOptions, type Method, type MethodEntry, type Middleware, type MiddlewareContext, type MiddlewareNext, type RouteDefinition, type Router, type RouterBrand, type RouterRoutes, type SSEData, type SSEEventMap, type SSEEventMessage, type SSEEventsOf, type SSEMessage, type SSEOptions, type SSEResponse, type SchemaDefinition, type SchemaType, type SchemaTypeMap, type ToolAnnotations, type TypedHandler, type TypedResponse, type ValidationResult, compileSchema, createHttpClient, createLocalClient, generateDocs, isFunction, isRoute, isRouter, route, router, runMiddleware, sseResponse, streamJsonLines };
414
+ export { type CollectPathParams, type CompiledSchema, type Context, type ExecutionContext, type FetchHandler, type HttpClient, type HttpClientConfig, type HttpRequestOptions, type InferSchema, type LocalClient, type LocalClientConfig, type LocalRequestOptions, type Method, type MethodEntry, type Middleware, type MiddlewareContext, type MiddlewareNext, type RouteDefinition, type Router, type RouterBrand, type RouterRoutes, type SSEData, type SSEEventMap, type SSEEventMessage, type SSEEventsOf, type SSEMessage, type SSEOptions, type SSEResponse, type SchemaDefinition, type SchemaField, type SchemaType, type SchemaTypeMap, type ToolAnnotations, type TypedHandler, type TypedResponse, type ValidationResult, compileSchema, createHttpClient, createLocalClient, generateDocs, isFunction, isRoute, isRouter, route, router, runMiddleware, sseResponse, streamJsonLines };
415
415
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/core.ts","../src/docs.ts","../src/client-types.ts","../src/http-client.ts","../src/local-client.ts","../src/streaming.ts"],"sourcesContent":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/core.ts","../src/docs.ts","../src/client-types.ts","../src/http-client.ts","../src/local-client.ts","../src/streaming.ts"],"sourcesContent":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as runMiddleware } from "./middleware-B-_0PLA6.mjs";
2
- import { a as isFunction, c as compileSchema, i as router, n as generateDocs, o as isRoute, r as route, s as isRouter } from "./docs-B1IFBS_w.mjs";
2
+ import { a as isFunction, c as compileSchema, i as router, n as generateDocs, o as isRoute, r as route, s as isRouter } from "./docs-BLjbxLe-.mjs";
3
3
 
4
4
  //#region src/client-proxy.ts
5
5
  const PREFIXED_HTTP_METHODS = new Set([
@@ -384,8 +384,8 @@ async function invokeHandler(sharedConfig, routerDef, segments, method, options)
384
384
  */
385
385
  function formatSSEMessage(message) {
386
386
  const lines = [];
387
- if (message.event) lines.push(`event: ${message.event}`);
388
- if (message.id) lines.push(`id: ${message.id}`);
387
+ if (message.event) lines.push(`event: ${message.event.replace(/[\r\n]/g, "")}`);
388
+ if (message.id) lines.push(`id: ${message.id.replace(/[\r\n]/g, "")}`);
389
389
  if (message.retry !== void 0) lines.push(`retry: ${message.retry}`);
390
390
  const data = typeof message.data === "string" ? message.data : JSON.stringify(message.data);
391
391
  for (const line of data.split("\n")) lines.push(`data: ${line}`);