orpc-fn 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/README.md +48 -32
  2. package/dist/assemble-procedure.d.ts +13 -0
  3. package/dist/assemble-procedure.d.ts.map +1 -0
  4. package/dist/assemble-procedure.js +29 -0
  5. package/dist/assemble-procedure.js.map +1 -0
  6. package/dist/bound-call.d.ts +1 -1
  7. package/dist/bound-call.d.ts.map +1 -1
  8. package/dist/bound-call.js.map +1 -1
  9. package/dist/client.d.ts +4 -2
  10. package/dist/client.d.ts.map +1 -1
  11. package/dist/client.js +4 -2
  12. package/dist/client.js.map +1 -1
  13. package/dist/compatibility.d.ts +16 -0
  14. package/dist/compatibility.d.ts.map +1 -0
  15. package/dist/compatibility.js +4 -0
  16. package/dist/compatibility.js.map +1 -0
  17. package/dist/create-fn.d.ts +30 -34
  18. package/dist/create-fn.d.ts.map +1 -1
  19. package/dist/create-fn.js +177 -121
  20. package/dist/create-fn.js.map +1 -1
  21. package/dist/expo.d.ts +11 -25
  22. package/dist/expo.d.ts.map +1 -1
  23. package/dist/expo.js +25 -30
  24. package/dist/expo.js.map +1 -1
  25. package/dist/hono.d.ts +12 -4
  26. package/dist/hono.d.ts.map +1 -1
  27. package/dist/hono.js +29 -12
  28. package/dist/hono.js.map +1 -1
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.d.ts.map +1 -1
  31. package/dist/index.js +2 -2
  32. package/dist/index.js.map +1 -1
  33. package/dist/json-schema.d.ts +2 -0
  34. package/dist/json-schema.d.ts.map +1 -1
  35. package/dist/json-schema.js +11 -0
  36. package/dist/json-schema.js.map +1 -1
  37. package/dist/live/codec.d.ts +6 -1
  38. package/dist/live/codec.d.ts.map +1 -1
  39. package/dist/live/codec.js +14 -3
  40. package/dist/live/codec.js.map +1 -1
  41. package/dist/live/fn-live.d.ts +63 -22
  42. package/dist/live/fn-live.d.ts.map +1 -1
  43. package/dist/live/fn-live.js +98 -16
  44. package/dist/live/fn-live.js.map +1 -1
  45. package/dist/live/index.d.ts +1 -1
  46. package/dist/live/index.d.ts.map +1 -1
  47. package/dist/live/index.js.map +1 -1
  48. package/dist/live/ioredis.d.ts +4 -1
  49. package/dist/live/ioredis.d.ts.map +1 -1
  50. package/dist/live/ioredis.js +21 -2
  51. package/dist/live/ioredis.js.map +1 -1
  52. package/dist/live/lifecycle.d.ts +7 -0
  53. package/dist/live/lifecycle.d.ts.map +1 -0
  54. package/dist/live/lifecycle.js +36 -0
  55. package/dist/live/lifecycle.js.map +1 -0
  56. package/dist/live/memory.d.ts.map +1 -1
  57. package/dist/live/memory.js +4 -0
  58. package/dist/live/memory.js.map +1 -1
  59. package/dist/live/pub-sub.d.ts +76 -12
  60. package/dist/live/pub-sub.d.ts.map +1 -1
  61. package/dist/live/pub-sub.js +429 -125
  62. package/dist/live/pub-sub.js.map +1 -1
  63. package/dist/live/redis-bun.d.ts +1 -1
  64. package/dist/live/redis-bun.d.ts.map +1 -1
  65. package/dist/live/redis-bun.js +3 -5
  66. package/dist/live/redis-bun.js.map +1 -1
  67. package/dist/live/redis.d.ts +2 -2
  68. package/dist/live/redis.d.ts.map +1 -1
  69. package/dist/live/redis.js +36 -9
  70. package/dist/live/redis.js.map +1 -1
  71. package/dist/live/transport.d.ts +5 -1
  72. package/dist/live/transport.d.ts.map +1 -1
  73. package/dist/live/transport.js.map +1 -1
  74. package/dist/logger.d.ts +2 -0
  75. package/dist/logger.d.ts.map +1 -1
  76. package/dist/logger.js +21 -0
  77. package/dist/logger.js.map +1 -1
  78. package/dist/mastra.d.ts.map +1 -1
  79. package/dist/mastra.js +16 -7
  80. package/dist/mastra.js.map +1 -1
  81. package/dist/mcp/sdk.d.ts +20 -0
  82. package/dist/mcp/sdk.d.ts.map +1 -0
  83. package/dist/mcp/sdk.js +82 -0
  84. package/dist/mcp/sdk.js.map +1 -0
  85. package/dist/mcp.d.ts +3 -2
  86. package/dist/mcp.d.ts.map +1 -1
  87. package/dist/mcp.js +22 -7
  88. package/dist/mcp.js.map +1 -1
  89. package/dist/meta.d.ts +15 -7
  90. package/dist/meta.d.ts.map +1 -1
  91. package/dist/meta.js +9 -2
  92. package/dist/meta.js.map +1 -1
  93. package/dist/otel.d.ts.map +1 -1
  94. package/dist/otel.js +77 -6
  95. package/dist/otel.js.map +1 -1
  96. package/dist/route-options.d.ts +22 -0
  97. package/dist/route-options.d.ts.map +1 -0
  98. package/dist/route-options.js +67 -0
  99. package/dist/route-options.js.map +1 -0
  100. package/dist/router.d.ts +5 -1
  101. package/dist/router.d.ts.map +1 -1
  102. package/dist/router.js +22 -0
  103. package/dist/router.js.map +1 -1
  104. package/dist/timing.d.ts +8 -0
  105. package/dist/timing.d.ts.map +1 -0
  106. package/dist/timing.js +4 -0
  107. package/dist/timing.js.map +1 -0
  108. package/dist/types.d.ts +86 -41
  109. package/dist/types.d.ts.map +1 -1
  110. package/dist/types.js +6 -2
  111. package/dist/types.js.map +1 -1
  112. package/package.json +15 -3
  113. package/src/assemble-procedure.ts +42 -0
  114. package/src/bound-call.ts +4 -3
  115. package/src/client.ts +9 -2
  116. package/src/compatibility.ts +39 -0
  117. package/src/create-fn.ts +297 -183
  118. package/src/expo.ts +49 -44
  119. package/src/hono.ts +36 -17
  120. package/src/index.ts +6 -2
  121. package/src/json-schema.ts +16 -0
  122. package/src/live/codec.ts +22 -3
  123. package/src/live/fn-live.ts +244 -69
  124. package/src/live/index.ts +2 -0
  125. package/src/live/ioredis.ts +22 -2
  126. package/src/live/lifecycle.ts +44 -0
  127. package/src/live/memory.ts +4 -0
  128. package/src/live/pub-sub.ts +608 -166
  129. package/src/live/redis-bun.ts +7 -5
  130. package/src/live/redis.ts +37 -11
  131. package/src/live/transport.ts +4 -1
  132. package/src/logger.ts +20 -0
  133. package/src/mastra.ts +15 -7
  134. package/src/mcp/sdk.ts +118 -0
  135. package/src/mcp.ts +48 -20
  136. package/src/meta.ts +40 -24
  137. package/src/otel.ts +77 -10
  138. package/src/route-options.ts +100 -0
  139. package/src/router.ts +39 -1
  140. package/src/timing.ts +5 -0
  141. package/src/types.ts +204 -62
package/dist/expo.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"expo.js","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,aAAa,EAAE,MAAM,aAAa,CAAA;AAwBtE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,OAI/B;IACA,OAAO,KAAK,EACX,OAAgB,EAChB,IAA0D,EACtC,EAAE;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,UAAU,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAA;QACtE,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAA;QACrE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACtD,GAAG,IAAI;YACP,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YACvC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,MAAM;SACnB,CAAC,CAAA;QACF,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,QAAoB,CAAA;IAC5B,CAAC,CAAA;AACF,CAAC;AAgBD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,cAAc,CAC7B,OAAiC;IAEjC,MAAM,EACL,KAAK,EACL,MAAM,EACN,SAAS,EACT,aAAa,EACb,OAAO,EAAE,YAAY,EACrB,GAAG,IAAI,EACP,GAAG,OAAO,CAAA;IACX,OAAO,aAAa,CAAI;QACvB,GAAG,IAAI;QACP,KAAK,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QACzC,OAAO,EAAE,GAAG,EAAE;YACb,MAAM,OAAO,GAA2B,EAAE,GAAG,YAAY,EAAE,EAAE,EAAE,CAAA;YAC/D,MAAM,MAAM,GAAG,SAAS,EAAE,EAAE,CAAA;YAC5B,IAAI,MAAM;gBAAE,OAAO,CAAC,MAAM,GAAG,MAAM,CAAA;YACnC,IAAI,MAAM,EAAE,CAAC;gBACZ,yEAAyE;gBACzE,OAAO,CAAC,oBAAoB,CAAC,GAAG,MAAM,CAAA;gBACtC,MAAM,MAAM,GAAG,aAAa,EAAE,EAAE,CAAA;gBAChC,IAAI,MAAM;oBAAE,OAAO,CAAC,aAAa,CAAC,GAAG,MAAM,CAAA;YAC5C,CAAC;YACD,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { ClientContext } from '@orpc/client'\nimport type { RPCLink } from '@orpc/client/fetch'\nimport { type CreateRpcLinkOptions, createRpcLink } from './client.js'\n\n/** What `fetch` from `expo/fetch` accepts from this bridge. */\nexport type ExpoFetchInit = {\n\tmethod: string\n\theaders: Record<string, string>\n\tbody?: ArrayBuffer\n\tsignal: AbortSignal\n\tcredentials: 'omit'\n\tredirect?: NonNullable<RequestInit['redirect']>\n}\n\n/** The response members oRPC reads; `expo/fetch`'s `FetchResponse` has them. */\nexport type ExpoResponse = Pick<\n\tResponse,\n\t'status' | 'headers' | 'body' | 'text' | 'blob' | 'formData'\n>\n\n/** `fetch` from `expo/fetch` (the only fetch that streams on native). */\nexport type ExpoFetch = (\n\turl: string,\n\tinit: ExpoFetchInit\n) => Promise<ExpoResponse>\n\n/**\n * oRPC's link `fetch` for React Native, built on `expo/fetch`.\n *\n * oRPC carries the input and the abort signal on the `Request`, not in\n * `init`, and the call is rebuilt for `expo/fetch`, so both are forwarded\n * explicitly: the body so the server receives the input, and the signal so a\n * cancelled subscription closes its socket. Without the signal, connections\n * leak and exhaust the device's HTTP pool after a few navigations, and every\n * later request hangs.\n *\n * Native sends cookies by header (see `createExpoLink`), so it omits the\n * credentialed cookie jar. On web it uses the platform `fetch` with cookies.\n */\nexport function createExpoFetch(options: {\n\tfetch: ExpoFetch\n\t/** `Platform.OS !== 'web'`. */\n\tnative: boolean\n}) {\n\treturn async (\n\t\trequest: Request,\n\t\tinit?: { redirect?: NonNullable<RequestInit['redirect']> }\n\t): Promise<Response> => {\n\t\tif (!options.native) {\n\t\t\treturn globalThis.fetch(request, { ...init, credentials: 'include' })\n\t\t}\n\t\tconst hasBody = request.method !== 'GET' && request.method !== 'HEAD'\n\t\tconst body = hasBody ? await request.arrayBuffer() : undefined\n\t\tconst response = await options.fetch(request.url, {\n\t\t\tmethod: request.method,\n\t\t\theaders: Object.fromEntries(request.headers.entries()),\n\t\t\t...init,\n\t\t\t...(body === undefined ? {} : { body }),\n\t\t\tsignal: request.signal,\n\t\t\tcredentials: 'omit'\n\t\t})\n\t\t// Not rebuilt with `new Response(...)`: React Native's Response polyfill\n\t\t// cannot stream a body. oRPC reads only the `ExpoResponse` members.\n\t\treturn response as Response\n\t}\n}\n\nexport type CreateExpoLinkOptions<T extends ClientContext> = Omit<\n\tCreateRpcLinkOptions<T>,\n\t'fetch' | 'headers'\n> & {\n\tfetch: ExpoFetch\n\tnative: boolean\n\t/** Session cookie, e.g. Better Auth's `authClient.getCookie()`. */\n\tgetCookie?: () => string | null | undefined\n\t/** `expo-origin` header; the server copies it to `origin` (`normalizeExpoOrigin`). */\n\tgetExpoOrigin?: () => string | null | undefined\n\t/** Extra headers on every request. */\n\theaders?: () => Record<string, string>\n}\n\n/**\n * `createRpcLink` for Expo: batching, the `expo/fetch` bridge and the headers\n * a Better Auth Expo client sends, so the API sees the same session and\n * origin as `/api/auth` requests.\n *\n * ```ts\n * import { fetch } from 'expo/fetch'\n * import { Platform } from 'react-native'\n *\n * const link = createExpoLink({\n * url: `${baseUrl}/api/rpc`,\n * fetch,\n * native: Platform.OS !== 'web',\n * getCookie: () => authClient.getCookie(),\n * getExpoOrigin\n * })\n * ```\n */\nexport function createExpoLink<T extends ClientContext = ClientContext>(\n\toptions: CreateExpoLinkOptions<T>\n): RPCLink<T> {\n\tconst {\n\t\tfetch,\n\t\tnative,\n\t\tgetCookie,\n\t\tgetExpoOrigin,\n\t\theaders: extraHeaders,\n\t\t...rest\n\t} = options\n\treturn createRpcLink<T>({\n\t\t...rest,\n\t\tfetch: createExpoFetch({ fetch, native }),\n\t\theaders: () => {\n\t\t\tconst headers: Record<string, string> = { ...extraHeaders?.() }\n\t\t\tconst cookie = getCookie?.()\n\t\t\tif (cookie) headers.Cookie = cookie\n\t\t\tif (native) {\n\t\t\t\t// What @better-auth/expo sends from native, for session and CORS parity.\n\t\t\t\theaders['x-skip-oauth-proxy'] = 'true'\n\t\t\t\tconst origin = getExpoOrigin?.()\n\t\t\t\tif (origin) headers['expo-origin'] = origin\n\t\t\t}\n\t\t\treturn headers\n\t\t}\n\t})\n}\n"]}
1
+ {"version":3,"file":"expo.js","sourceRoot":"","sources":["../src/expo.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6B,aAAa,EAAE,MAAM,aAAa,CAAA;AAwBtE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,eAAe,CAAC,OAK/B;IACA,OAAO,KAAK,EACX,OAAgB,EAChB,IAA0D,EACtC,EAAE;QACtB,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrB,OAAO,CAAC,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE;gBACtD,GAAG,IAAI;gBACP,WAAW,EAAE,SAAS;aACtB,CAAC,CAAA;QACH,CAAC;QACD,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,KAAK,KAAK,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM,CAAA;QACrE,MAAM,IAAI,GAAG,OAAO,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;QAC9D,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE;YACjD,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACtD,GAAG,IAAI;YACP,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;YACvC,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,WAAW,EAAE,MAAM;SACnB,CAAC,CAAA;QACF,yEAAyE;QACzE,oEAAoE;QACpE,OAAO,QAAoB,CAAA;IAC5B,CAAC,CAAA;AACF,CAAC;AAYD,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAC7B,OAAiC;IAEjC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IACpD,OAAO,aAAa,CAAI;QACvB,GAAG,IAAI;QACP,KAAK,EAAE,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;KAC5E,CAAC,CAAA;AACH,CAAC;AAgBD,kFAAkF;AAClF,MAAM,UAAU,wBAAwB,CAEtC,OAA2C;IAC5C,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAA;IAC5E,OAAO,cAAc,CAAI;QACxB,GAAG,IAAI;QACP,OAAO,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;YAC1B,MAAM,QAAQ,GACb,OAAO,YAAY,KAAK,UAAU;gBACjC,CAAC,CAAC,MAAM,YAAY,CAAC,GAAG,IAAI,CAAC;gBAC7B,CAAC,CAAC,MAAM,YAAY,CAAA;YACtB,MAAM,OAAO,GAAG,IAAI,OAAO,CAC1B,QAAoD,CACpD,CAAA;YACD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,EAAE,CAAA;YAClC,IAAI,MAAM;gBAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAA;YACzC,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACpB,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAA;gBACzC,MAAM,MAAM,GAAG,MAAM,aAAa,EAAE,EAAE,CAAA;gBACtC,IAAI,MAAM;oBAAE,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,CAAA;YAC/C,CAAC;YACD,OAAO,OAAO,CAAA;QACf,CAAC;KACD,CAAC,CAAA;AACH,CAAC","sourcesContent":["import type { ClientContext } from '@orpc/client'\nimport type { RPCLink } from '@orpc/client/fetch'\nimport { type CreateRpcLinkOptions, createRpcLink } from './client.js'\n\n/** What `fetch` from `expo/fetch` accepts from this bridge. */\nexport type ExpoFetchInit = {\n\tmethod: string\n\theaders: Record<string, string>\n\tbody?: ArrayBuffer\n\tsignal: AbortSignal\n\tcredentials: 'omit'\n\tredirect?: NonNullable<RequestInit['redirect']>\n}\n\n/** The response members oRPC reads; `expo/fetch`'s `FetchResponse` has them. */\nexport type ExpoResponse = Pick<\n\tResponse,\n\t'status' | 'headers' | 'body' | 'text' | 'blob' | 'formData'\n>\n\n/** `fetch` from `expo/fetch` (the only fetch that streams on native). */\nexport type ExpoFetch = (\n\turl: string,\n\tinit: ExpoFetchInit\n) => Promise<ExpoResponse>\n\n/**\n * oRPC's link `fetch` for React Native, built on `expo/fetch`.\n *\n * oRPC carries the input and the abort signal on the `Request`, not in\n * `init`, and the call is rebuilt for `expo/fetch`, so both are forwarded\n * explicitly: the body so the server receives the input, and the signal so a\n * cancelled subscription closes its socket. Without the signal, connections\n * leak and exhaust the device's HTTP pool after a few navigations, and every\n * later request hangs.\n *\n * Native sends cookies by header (see `createExpoLink`), so it omits the\n * credentialed cookie jar. On web it uses the platform `fetch` with cookies.\n */\nexport function createExpoFetch(options: {\n\tfetch: ExpoFetch\n\t/** `Platform.OS !== 'web'`. */\n\tnative: boolean\n\twebFetch?: (request: Request, init?: RequestInit) => Promise<Response>\n}) {\n\treturn async (\n\t\trequest: Request,\n\t\tinit?: { redirect?: NonNullable<RequestInit['redirect']> }\n\t): Promise<Response> => {\n\t\tif (!options.native) {\n\t\t\treturn (options.webFetch ?? globalThis.fetch)(request, {\n\t\t\t\t...init,\n\t\t\t\tcredentials: 'include'\n\t\t\t})\n\t\t}\n\t\tconst hasBody = request.method !== 'GET' && request.method !== 'HEAD'\n\t\tconst body = hasBody ? await request.arrayBuffer() : undefined\n\t\tconst response = await options.fetch(request.url, {\n\t\t\tmethod: request.method,\n\t\t\theaders: Object.fromEntries(request.headers.entries()),\n\t\t\t...init,\n\t\t\t...(body === undefined ? {} : { body }),\n\t\t\tsignal: request.signal,\n\t\t\tcredentials: 'omit'\n\t\t})\n\t\t// Not rebuilt with `new Response(...)`: React Native's Response polyfill\n\t\t// cannot stream a body. oRPC reads only the `ExpoResponse` members.\n\t\treturn response as Response\n\t}\n}\n\nexport type CreateExpoLinkOptions<T extends ClientContext> = Omit<\n\tCreateRpcLinkOptions<T>,\n\t'fetch'\n> & {\n\tfetch: ExpoFetch\n\tnative: boolean\n\t/** Explicit browser fetch override; native always uses expo/fetch. */\n\twebFetch?: (request: Request, init?: RequestInit) => Promise<Response>\n}\n\n/** Generic streaming bridge with upstream async/context-aware headers. */\nexport function createExpoLink<T extends ClientContext = ClientContext>(\n\toptions: CreateExpoLinkOptions<T>\n): RPCLink<T> {\n\tconst { fetch, native, webFetch, ...rest } = options\n\treturn createRpcLink<T>({\n\t\t...rest,\n\t\tfetch: createExpoFetch({ fetch, native, ...(webFetch ? { webFetch } : {}) })\n\t})\n}\n\nexport type CreateBetterAuthExpoLinkOptions<T extends ClientContext> =\n\tCreateExpoLinkOptions<T> & {\n\t\tgetCookie?: () =>\n\t\t\t| string\n\t\t\t| null\n\t\t\t| undefined\n\t\t\t| Promise<string | null | undefined>\n\t\tgetExpoOrigin?: () =>\n\t\t\t| string\n\t\t\t| null\n\t\t\t| undefined\n\t\t\t| Promise<string | null | undefined>\n\t}\n\n/** Better Auth's native cookie/origin headers, kept behind an explicit preset. */\nexport function createBetterAuthExpoLink<\n\tT extends ClientContext = ClientContext\n>(options: CreateBetterAuthExpoLinkOptions<T>): RPCLink<T> {\n\tconst { getCookie, getExpoOrigin, headers: extraHeaders, ...rest } = options\n\treturn createExpoLink<T>({\n\t\t...rest,\n\t\theaders: async (...args) => {\n\t\t\tconst supplied =\n\t\t\t\ttypeof extraHeaders === 'function'\n\t\t\t\t\t? await extraHeaders(...args)\n\t\t\t\t\t: await extraHeaders\n\t\t\tconst headers = new Headers(\n\t\t\t\tsupplied as ConstructorParameters<typeof Headers>[0]\n\t\t\t)\n\t\t\tconst cookie = await getCookie?.()\n\t\t\tif (cookie) headers.set('Cookie', cookie)\n\t\t\tif (options.native) {\n\t\t\t\theaders.set('x-skip-oauth-proxy', 'true')\n\t\t\t\tconst origin = await getExpoOrigin?.()\n\t\t\t\tif (origin) headers.set('expo-origin', origin)\n\t\t\t}\n\t\t\treturn headers\n\t\t}\n\t})\n}\n"]}
package/dist/hono.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { OpenAPIGeneratorGenerateOptions } from '@orpc/openapi';
1
2
  import { type AnyRouter, type InferRouterInitialContext } from '@orpc/server';
2
3
  import type { StandardHandlerPlugin } from '@orpc/server/standard';
3
4
  import type { Context as HonoContext, Env, Hono } from 'hono';
@@ -21,7 +22,7 @@ type ContextOption<E extends Env, R extends AnyRouter> = BaseContext extends Inf
21
22
  context: ContextFactory<E, R>;
22
23
  };
23
24
  type Path = `/${string}`;
24
- type Plugin = StandardHandlerPlugin<any>;
25
+ type Plugin<T extends object> = StandardHandlerPlugin<T>;
25
26
  export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption<E, R> & {
26
27
  router: R;
27
28
  /** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */
@@ -41,8 +42,8 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
41
42
  /** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */
42
43
  smartCoercion?: boolean;
43
44
  /** Extra spec fields, e.g. `components.securitySchemes` and `security`. */
44
- spec?: Record<string, unknown>;
45
- plugins?: Plugin[];
45
+ spec?: Omit<OpenAPIGeneratorGenerateOptions, 'filter'>;
46
+ plugins?: Plugin<InferRouterInitialContext<R>>[];
46
47
  };
47
48
  /** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */
48
49
  batch?: boolean | {
@@ -53,7 +54,7 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
53
54
  /** SSE keep-alive comments every N ms (default 15000), or false. */
54
55
  sseKeepAlive?: boolean | number;
55
56
  /** Extra RPC plugins (e.g. `CORSPlugin`). */
56
- plugins?: Plugin[];
57
+ plugins?: Plugin<InferRouterInitialContext<R>>[];
57
58
  /** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */
58
59
  normalizeHeaders?: (headers: Headers) => Headers;
59
60
  /** Time spent before the handler ran, reported as `queue`. */
@@ -75,6 +76,13 @@ export type MountOrpcOptions<E extends Env, R extends AnyRouter> = ContextOption
75
76
  */
76
77
  export declare function normalizeExpoOrigin(raw: Headers): Headers;
77
78
  export declare function formatServerTiming(totalMs: number, timing: Record<string, number | undefined>): string;
79
+ /**
80
+ * Response headers plus Server-Timing. For SSE, also disable proxy buffering
81
+ * so keep-alive comments reach the edge (empty `:` lines are otherwise easy
82
+ * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.
83
+ * redirects) have immutable headers.
84
+ */
85
+ export declare function finishOrpcHeaders(response: Response, serverTiming: string | undefined): Headers;
78
86
  /** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */
79
87
  export declare function mountOrpc<E extends Env, R extends AnyRouter>(app: Hono<E>, options: MountOrpcOptions<E, R>): void;
80
88
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"hono.d.ts","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,+BAA+B,EAAE,MAAM,eAAe,CAAA;AAGpE,OAAO,EACN,KAAK,SAAS,EACd,KAAK,yBAAyB,EAE9B,MAAM,cAAc,CAAA;AAGrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAElE,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAI7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAE/C,kFAAkF;AAClF,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAElD,qFAAqF;AACrF,MAAM,MAAM,WAAW,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,aAAa,CAAA;CAAE,CAAA;AAErE;;;GAGG;AACH,MAAM,MAAM,cAAc,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,SAAS,IAAI,CAChE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACjB,IAAI,EAAE,WAAW,KAEf,yBAAyB,CAAC,CAAC,CAAC,GAC5B,QAAQ,GACR,OAAO,CAAC,yBAAyB,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAA;AAEnD,qFAAqF;AACrF,KAAK,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,SAAS,IACpD,WAAW,SAAS,yBAAyB,CAAC,CAAC,CAAC,GAC7C;IAAE,OAAO,CAAC,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,GAClC;IAAE,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,CAAA;AAErC,KAAK,IAAI,GAAG,IAAI,MAAM,EAAE,CAAA;AACxB,KAAK,MAAM,CAAC,CAAC,SAAS,MAAM,IAAI,qBAAqB,CAAC,CAAC,CAAC,CAAA;AAExD,MAAM,MAAM,gBAAgB,CAC3B,CAAC,SAAS,GAAG,EACb,CAAC,SAAS,SAAS,IAChB,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;IACzB,MAAM,EAAE,CAAC,CAAA;IACT,sEAAsE;IACtE,SAAS,CAAC,EAAE,IAAI,CAAA;IAChB,iEAAiE;IACjE,OAAO,CAAC,EAAE;QACT,MAAM,EAAE,IAAI,CAAA;QACZ,IAAI,CAAC,EAAE;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,OAAO,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC/D,kFAAkF;QAClF,QAAQ,CAAC,EAAE,IAAI,CAAA;QACf,+DAA+D;QAC/D,MAAM,CAAC,EAAE,eAAe,CAAA;QACxB,sEAAsE;QACtE,aAAa,CAAC,EAAE,OAAO,CAAA;QACvB,2EAA2E;QAC3E,IAAI,CAAC,EAAE,IAAI,CAAC,+BAA+B,EAAE,QAAQ,CAAC,CAAA;QACtD,OAAO,CAAC,EAAE,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;KAChD,CAAA;IACD,mFAAmF;IACnF,KAAK,CAAC,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;IACrC,wEAAwE;IACxE,YAAY,CAAC,EAAE,OAAO,CAAA;IACtB,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,GAAG,MAAM,CAAA;IAC/B,6CAA6C;IAC7C,OAAO,CAAC,EAAE,MAAM,CAAC,yBAAyB,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IAChD,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;IAChD,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,GAAG,SAAS,CAAA;IAClD;;;OAGG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAA;IAC5E,gDAAgD;IAChD,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;CAC7C,CAAA;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAMzD;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GACxC,MAAM,CAQR;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,QAAQ,EAAE,QAAQ,EAClB,YAAY,EAAE,MAAM,GAAG,SAAS,GAC9B,OAAO,CAWT;AAED,2DAA2D;AAC3D,wBAAgB,SAAS,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,SAAS,SAAS,EAC3D,GAAG,EAAE,IAAI,CAAC,CAAC,CAAC,EACZ,OAAO,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,GAC7B,IAAI,CA8HN"}
package/dist/hono.js CHANGED
@@ -5,6 +5,7 @@ import { onError as orpcOnError } from '@orpc/server';
5
5
  import { RPCHandler } from '@orpc/server/fetch';
6
6
  import { BatchHandlerPlugin } from '@orpc/server/plugins';
7
7
  import { ZodToJsonSchemaConverter } from '@orpc/zod/zod4';
8
+ import { REQUEST_TIMING } from './timing.js';
8
9
  import { isExpectedClientError } from './expected-client-error.js';
9
10
  /**
10
11
  * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based
@@ -33,7 +34,7 @@ export function formatServerTiming(totalMs, timing) {
33
34
  * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.
34
35
  * redirects) have immutable headers.
35
36
  */
36
- function finishHeaders(response, serverTiming) {
37
+ export function finishOrpcHeaders(response, serverTiming) {
37
38
  const headers = new Headers(response.headers);
38
39
  if (serverTiming) {
39
40
  headers.set('Server-Timing', serverTiming);
@@ -57,12 +58,17 @@ export function mountOrpc(app, options) {
57
58
  eventIteratorKeepAliveInterval: sseKeepAlive === true ? 15_000 : sseKeepAlive
58
59
  };
59
60
  const report = (error, { request }) => {
60
- if (isExpectedError(error))
61
- return;
62
- options.onError?.(error, {
63
- url: request.url.pathname,
64
- method: request.method
65
- });
61
+ try {
62
+ if (isExpectedError(error))
63
+ return;
64
+ options.onError?.(error, {
65
+ url: request.url.pathname,
66
+ method: request.method
67
+ });
68
+ }
69
+ catch {
70
+ /* Error reporting cannot replace transport outcomes. */
71
+ }
66
72
  };
67
73
  const mount = (prefix, handler) => {
68
74
  app.use(`${prefix}/*`, async (c, next) => {
@@ -79,24 +85,33 @@ export function mountOrpc(app, options) {
79
85
  : { headers, timing };
80
86
  if (context instanceof Response)
81
87
  return context;
88
+ const invocationTiming = { procedureMs: 0, calls: 0 };
82
89
  const { matched, response } = await handler.handle(c.req.raw, {
83
90
  prefix,
84
- context: context
91
+ context: {
92
+ ...context,
93
+ [REQUEST_TIMING]: invocationTiming
94
+ }
85
95
  });
86
96
  if (!matched)
87
97
  return next();
88
98
  const timed = serverTiming
89
- ? formatServerTiming(performance.now() - started, timing)
99
+ ? formatServerTiming(performance.now() - started, {
100
+ ...timing,
101
+ handler_ms: invocationTiming.procedureMs
102
+ })
90
103
  : undefined;
91
104
  return c.newResponse(response.body, {
92
105
  // oRPC only produces valid HTTP status codes.
93
106
  status: response.status,
94
- headers: finishHeaders(response, timed)
107
+ headers: finishOrpcHeaders(response, timed)
95
108
  });
96
109
  });
97
110
  };
98
111
  if (options.rpcPrefix) {
99
- const plugins = [...(options.plugins ?? [])];
112
+ const plugins = [
113
+ ...(options.plugins ?? [])
114
+ ];
100
115
  if (batch) {
101
116
  plugins.push(new BatchHandlerPlugin({
102
117
  maxSize: batch === true ? 25 : batch.maxSize
@@ -112,7 +127,9 @@ export function mountOrpc(app, options) {
112
127
  const { openapi } = options;
113
128
  const filter = openapi.filter ? { filter: openapi.filter } : {};
114
129
  const converters = [new ZodToJsonSchemaConverter()];
115
- const plugins = [...(openapi.plugins ?? [])];
130
+ const plugins = [
131
+ ...(openapi.plugins ?? [])
132
+ ];
116
133
  if (openapi.smartCoercion) {
117
134
  plugins.push(new SmartCoercionPlugin({ schemaConverters: converters }));
118
135
  }
package/dist/hono.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema'\nimport { OpenAPIHandler } from '@orpc/openapi/fetch'\nimport { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'\nimport {\n\ttype AnyRouter,\n\ttype InferRouterInitialContext,\n\tonError as orpcOnError\n} from '@orpc/server'\nimport { RPCHandler } from '@orpc/server/fetch'\nimport { BatchHandlerPlugin } from '@orpc/server/plugins'\nimport type { StandardHandlerPlugin } from '@orpc/server/standard'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\nimport type { Context as HonoContext, Env, Hono } from 'hono'\nimport type { StatusCode } from 'hono/utils/http-status'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport type { ProcedureFilter } from './mcp.js'\n\n/** Per-request timings in ms; `fn()` adds `handler_ms`. Sent as Server-Timing. */\nexport type RequestTiming = Record<string, number>\n\n/** What every request starts with; the default context when `context` is omitted. */\nexport type BaseContext = { headers: Headers; timing: RequestTiming }\n\n/**\n * Builds the router's initial context from the request. Return a `Response`\n * to answer (e.g. 401) instead.\n */\nexport type ContextFactory<E extends Env, R extends AnyRouter> = (\n\tc: HonoContext<E>,\n\tbase: BaseContext\n) =>\n\t| InferRouterInitialContext<R>\n\t| Response\n\t| Promise<InferRouterInitialContext<R> | Response>\n\n/** `context` is optional only when the base context already satisfies the router. */\ntype ContextOption<E extends Env, R extends AnyRouter> =\n\tBaseContext extends InferRouterInitialContext<R>\n\t\t? { context?: ContextFactory<E, R> }\n\t\t: { context: ContextFactory<E, R> }\n\ntype Path = `/${string}`\n// biome-ignore lint/suspicious/noExplicitAny: plugins are context-agnostic here\ntype Plugin = StandardHandlerPlugin<any>\n\nexport type MountOrpcOptions<\n\tE extends Env,\n\tR extends AnyRouter\n> = ContextOption<E, R> & {\n\trouter: R\n\t/** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */\n\trpcPrefix?: Path\n\t/** Mount the OpenAPI (REST) handler and its Scalar docs here. */\n\topenapi?: {\n\t\tprefix: Path\n\t\tinfo?: { title: string; version: string; description?: string }\n\t\t/** Docs page, relative to `prefix` (default '/'); the spec is at `/spec.json`. */\n\t\tdocsPath?: Path\n\t\t/** Only expose matching procedures (also filters the spec). */\n\t\tfilter?: ProcedureFilter\n\t\t/** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */\n\t\tsmartCoercion?: boolean\n\t\t/** Extra spec fields, e.g. `components.securitySchemes` and `security`. */\n\t\tspec?: Record<string, unknown>\n\t\tplugins?: Plugin[]\n\t}\n\t/** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */\n\tbatch?: boolean | { maxSize: number }\n\t/** Add a Server-Timing header from the request timing. Default: true */\n\tserverTiming?: boolean\n\t/** SSE keep-alive comments every N ms (default 15000), or false. */\n\tsseKeepAlive?: boolean | number\n\t/** Extra RPC plugins (e.g. `CORSPlugin`). */\n\tplugins?: Plugin[]\n\t/** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */\n\tnormalizeHeaders?: (headers: Headers) => Headers\n\t/** Time spent before the handler ran, reported as `queue`. */\n\tqueueMs?: (request: Request) => number | undefined\n\t/**\n\t * Unexpected procedure errors (oRPC turns thrown errors into responses, so\n\t * Hono's `onError` never sees them). Expected client errors are skipped.\n\t */\n\tonError?: (error: unknown, request: { url: string; method: string }) => void\n\t/** Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n}\n\n/**\n * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based\n * auth (e.g. Better Auth) sees the origin.\n */\nexport function normalizeExpoOrigin(raw: Headers): Headers {\n\tconst expo = raw.get('expo-origin')\n\tif (!expo || raw.get('origin')) return raw\n\tconst headers = new Headers(raw)\n\theaders.set('origin', expo)\n\treturn headers\n}\n\nexport function formatServerTiming(\n\ttotalMs: number,\n\ttiming: Record<string, number | undefined>\n): string {\n\tconst parts = [`total;dur=${totalMs.toFixed(2)}`]\n\tfor (const [key, value] of Object.entries(timing)) {\n\t\tif (value !== undefined) {\n\t\t\tparts.push(`${key.replace(/_ms$/, '')};dur=${value.toFixed(2)}`)\n\t\t}\n\t}\n\treturn parts.join(', ')\n}\n\n/**\n * Response headers plus Server-Timing. For SSE, also disable proxy buffering\n * so keep-alive comments reach the edge (empty `:` lines are otherwise easy\n * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.\n * redirects) have immutable headers.\n */\nfunction finishHeaders(\n\tresponse: Response,\n\tserverTiming: string | undefined\n): Headers {\n\tconst headers = new Headers(response.headers)\n\tif (serverTiming) {\n\t\theaders.set('Server-Timing', serverTiming)\n\t\theaders.append('Access-Control-Expose-Headers', 'Server-Timing')\n\t}\n\tif ((headers.get('content-type') ?? '').includes('text/event-stream')) {\n\t\theaders.set('Cache-Control', 'no-cache')\n\t\theaders.set('X-Accel-Buffering', 'no')\n\t}\n\treturn headers\n}\n\n/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */\nexport function mountOrpc<E extends Env, R extends AnyRouter>(\n\tapp: Hono<E>,\n\toptions: MountOrpcOptions<E, R>\n): void {\n\tconst {\n\t\trouter,\n\t\tbatch = true,\n\t\tserverTiming = true,\n\t\tsseKeepAlive = true\n\t} = options\n\tconst isExpectedError = options.isExpectedError ?? isExpectedClientError\n\tconst keepAlive =\n\t\tsseKeepAlive === false\n\t\t\t? { eventIteratorKeepAliveEnabled: false }\n\t\t\t: {\n\t\t\t\t\teventIteratorKeepAliveEnabled: true,\n\t\t\t\t\t// Explicit keep-alive under proxy idle timers (~30s); oRPC's default is 5s.\n\t\t\t\t\teventIteratorKeepAliveInterval:\n\t\t\t\t\t\tsseKeepAlive === true ? 15_000 : sseKeepAlive\n\t\t\t\t}\n\tconst report = (\n\t\terror: unknown,\n\t\t{ request }: { request: { url: URL; method: string } }\n\t) => {\n\t\tif (isExpectedError(error)) return\n\t\toptions.onError?.(error, {\n\t\t\turl: request.url.pathname,\n\t\t\tmethod: request.method\n\t\t})\n\t}\n\n\tconst mount = (prefix: Path, handler: Pick<RPCHandler<object>, 'handle'>) => {\n\t\tapp.use(`${prefix}/*`, async (c, next) => {\n\t\t\tconst timing: RequestTiming = {}\n\t\t\tconst queueMs = options.queueMs?.(c.req.raw)\n\t\t\tif (queueMs !== undefined)\n\t\t\t\ttiming.queue_ms = Math.round(queueMs * 100) / 100\n\t\t\tconst started = performance.now()\n\t\t\tconst headers = options.normalizeHeaders\n\t\t\t\t? options.normalizeHeaders(c.req.raw.headers)\n\t\t\t\t: c.req.raw.headers\n\t\t\tconst context = options.context\n\t\t\t\t? await options.context(c, { headers, timing })\n\t\t\t\t: { headers, timing }\n\t\t\tif (context instanceof Response) return context\n\t\t\tconst { matched, response } = await handler.handle(c.req.raw, {\n\t\t\t\tprefix,\n\t\t\t\tcontext: context as object\n\t\t\t})\n\t\t\tif (!matched) return next()\n\t\t\tconst timed = serverTiming\n\t\t\t\t? formatServerTiming(performance.now() - started, timing)\n\t\t\t\t: undefined\n\t\t\treturn c.newResponse(response.body, {\n\t\t\t\t// oRPC only produces valid HTTP status codes.\n\t\t\t\tstatus: response.status as StatusCode,\n\t\t\t\theaders: finishHeaders(response, timed)\n\t\t\t})\n\t\t})\n\t}\n\n\tif (options.rpcPrefix) {\n\t\tconst plugins: Plugin[] = [...(options.plugins ?? [])]\n\t\tif (batch) {\n\t\t\tplugins.push(\n\t\t\t\tnew BatchHandlerPlugin({\n\t\t\t\t\tmaxSize: batch === true ? 25 : batch.maxSize\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t\tmount(\n\t\t\toptions.rpcPrefix,\n\t\t\tnew RPCHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n\n\tif (options.openapi) {\n\t\tconst { openapi } = options\n\t\tconst filter = openapi.filter ? { filter: openapi.filter } : {}\n\t\tconst converters = [new ZodToJsonSchemaConverter()]\n\t\tconst plugins: Plugin[] = [...(openapi.plugins ?? [])]\n\t\tif (openapi.smartCoercion) {\n\t\t\tplugins.push(new SmartCoercionPlugin({ schemaConverters: converters }))\n\t\t}\n\t\tplugins.push(\n\t\t\tnew OpenAPIReferencePlugin({\n\t\t\t\tdocsProvider: 'scalar',\n\t\t\t\t...(openapi.docsPath ? { docsPath: openapi.docsPath } : {}),\n\t\t\t\tschemaConverters: converters,\n\t\t\t\tspecGenerateOptions: {\n\t\t\t\t\tinfo: openapi.info ?? { title: 'API', version: '0.0.0' },\n\t\t\t\t\tservers: [{ url: openapi.prefix }],\n\t\t\t\t\t...filter,\n\t\t\t\t\t...openapi.spec\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t\tmount(\n\t\t\topenapi.prefix,\n\t\t\tnew OpenAPIHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\t...filter,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n}\n"]}
1
+ {"version":3,"file":"hono.js","sourceRoot":"","sources":["../src/hono.ts"],"names":[],"mappings":"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","sourcesContent":["import { SmartCoercionPlugin } from '@orpc/json-schema'\nimport type { OpenAPIGeneratorGenerateOptions } from '@orpc/openapi'\nimport { OpenAPIHandler } from '@orpc/openapi/fetch'\nimport { OpenAPIReferencePlugin } from '@orpc/openapi/plugins'\nimport {\n\ttype AnyRouter,\n\ttype InferRouterInitialContext,\n\tonError as orpcOnError\n} from '@orpc/server'\nimport { RPCHandler } from '@orpc/server/fetch'\nimport { BatchHandlerPlugin } from '@orpc/server/plugins'\nimport type { StandardHandlerPlugin } from '@orpc/server/standard'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\nimport type { Context as HonoContext, Env, Hono } from 'hono'\nimport type { StatusCode } from 'hono/utils/http-status'\nimport { REQUEST_TIMING, type InvocationTiming } from './timing.js'\nimport { isExpectedClientError } from './expected-client-error.js'\nimport type { ProcedureFilter } from './mcp.js'\n\n/** Per-request timings in ms; `fn()` adds `handler_ms`. Sent as Server-Timing. */\nexport type RequestTiming = Record<string, number>\n\n/** What every request starts with; the default context when `context` is omitted. */\nexport type BaseContext = { headers: Headers; timing: RequestTiming }\n\n/**\n * Builds the router's initial context from the request. Return a `Response`\n * to answer (e.g. 401) instead.\n */\nexport type ContextFactory<E extends Env, R extends AnyRouter> = (\n\tc: HonoContext<E>,\n\tbase: BaseContext\n) =>\n\t| InferRouterInitialContext<R>\n\t| Response\n\t| Promise<InferRouterInitialContext<R> | Response>\n\n/** `context` is optional only when the base context already satisfies the router. */\ntype ContextOption<E extends Env, R extends AnyRouter> =\n\tBaseContext extends InferRouterInitialContext<R>\n\t\t? { context?: ContextFactory<E, R> }\n\t\t: { context: ContextFactory<E, R> }\n\ntype Path = `/${string}`\ntype Plugin<T extends object> = StandardHandlerPlugin<T>\n\nexport type MountOrpcOptions<\n\tE extends Env,\n\tR extends AnyRouter\n> = ContextOption<E, R> & {\n\trouter: R\n\t/** Mount the RPC handler (oRPC's `RPCLink`) here. Omit to skip it. */\n\trpcPrefix?: Path\n\t/** Mount the OpenAPI (REST) handler and its Scalar docs here. */\n\topenapi?: {\n\t\tprefix: Path\n\t\tinfo?: { title: string; version: string; description?: string }\n\t\t/** Docs page, relative to `prefix` (default '/'); the spec is at `/spec.json`. */\n\t\tdocsPath?: Path\n\t\t/** Only expose matching procedures (also filters the spec). */\n\t\tfilter?: ProcedureFilter\n\t\t/** Turn JSON strings back into `Date`s etc. for `z.date()` inputs. */\n\t\tsmartCoercion?: boolean\n\t\t/** Extra spec fields, e.g. `components.securitySchemes` and `security`. */\n\t\tspec?: Omit<OpenAPIGeneratorGenerateOptions, 'filter'>\n\t\tplugins?: Plugin<InferRouterInitialContext<R>>[]\n\t}\n\t/** Collapse parallel RPC calls into one HTTP request. Default: true (25 calls). */\n\tbatch?: boolean | { maxSize: number }\n\t/** Add a Server-Timing header from the request timing. Default: true */\n\tserverTiming?: boolean\n\t/** SSE keep-alive comments every N ms (default 15000), or false. */\n\tsseKeepAlive?: boolean | number\n\t/** Extra RPC plugins (e.g. `CORSPlugin`). */\n\tplugins?: Plugin<InferRouterInitialContext<R>>[]\n\t/** Rewrite request headers before they reach the context (see `normalizeExpoOrigin`). */\n\tnormalizeHeaders?: (headers: Headers) => Headers\n\t/** Time spent before the handler ran, reported as `queue`. */\n\tqueueMs?: (request: Request) => number | undefined\n\t/**\n\t * Unexpected procedure errors (oRPC turns thrown errors into responses, so\n\t * Hono's `onError` never sees them). Expected client errors are skipped.\n\t */\n\tonError?: (error: unknown, request: { url: string; method: string }) => void\n\t/** Default: 4xx `ORPCError` or `AbortError`. */\n\tisExpectedError?: (error: unknown) => boolean\n}\n\n/**\n * Expo native sends `expo-origin` but not `origin`; copy it so cookie-based\n * auth (e.g. Better Auth) sees the origin.\n */\nexport function normalizeExpoOrigin(raw: Headers): Headers {\n\tconst expo = raw.get('expo-origin')\n\tif (!expo || raw.get('origin')) return raw\n\tconst headers = new Headers(raw)\n\theaders.set('origin', expo)\n\treturn headers\n}\n\nexport function formatServerTiming(\n\ttotalMs: number,\n\ttiming: Record<string, number | undefined>\n): string {\n\tconst parts = [`total;dur=${totalMs.toFixed(2)}`]\n\tfor (const [key, value] of Object.entries(timing)) {\n\t\tif (value !== undefined) {\n\t\t\tparts.push(`${key.replace(/_ms$/, '')};dur=${value.toFixed(2)}`)\n\t\t}\n\t}\n\treturn parts.join(', ')\n}\n\n/**\n * Response headers plus Server-Timing. For SSE, also disable proxy buffering\n * so keep-alive comments reach the edge (empty `:` lines are otherwise easy\n * for nginx/Fastly to hold until an idle kill). A copy: some responses (e.g.\n * redirects) have immutable headers.\n */\nexport function finishOrpcHeaders(\n\tresponse: Response,\n\tserverTiming: string | undefined\n): Headers {\n\tconst headers = new Headers(response.headers)\n\tif (serverTiming) {\n\t\theaders.set('Server-Timing', serverTiming)\n\t\theaders.append('Access-Control-Expose-Headers', 'Server-Timing')\n\t}\n\tif ((headers.get('content-type') ?? '').includes('text/event-stream')) {\n\t\theaders.set('Cache-Control', 'no-cache')\n\t\theaders.set('X-Accel-Buffering', 'no')\n\t}\n\treturn headers\n}\n\n/** Mount oRPC's RPC and OpenAPI handlers on a Hono app. */\nexport function mountOrpc<E extends Env, R extends AnyRouter>(\n\tapp: Hono<E>,\n\toptions: MountOrpcOptions<E, R>\n): void {\n\tconst {\n\t\trouter,\n\t\tbatch = true,\n\t\tserverTiming = true,\n\t\tsseKeepAlive = true\n\t} = options\n\tconst isExpectedError = options.isExpectedError ?? isExpectedClientError\n\tconst keepAlive =\n\t\tsseKeepAlive === false\n\t\t\t? { eventIteratorKeepAliveEnabled: false }\n\t\t\t: {\n\t\t\t\t\teventIteratorKeepAliveEnabled: true,\n\t\t\t\t\t// Explicit keep-alive under proxy idle timers (~30s); oRPC's default is 5s.\n\t\t\t\t\teventIteratorKeepAliveInterval:\n\t\t\t\t\t\tsseKeepAlive === true ? 15_000 : sseKeepAlive\n\t\t\t\t}\n\tconst report = (\n\t\terror: unknown,\n\t\t{ request }: { request: { url: URL; method: string } }\n\t) => {\n\t\ttry {\n\t\t\tif (isExpectedError(error)) return\n\t\t\toptions.onError?.(error, {\n\t\t\t\turl: request.url.pathname,\n\t\t\t\tmethod: request.method\n\t\t\t})\n\t\t} catch {\n\t\t\t/* Error reporting cannot replace transport outcomes. */\n\t\t}\n\t}\n\n\tconst mount = (\n\t\tprefix: Path,\n\t\thandler: Pick<RPCHandler<InferRouterInitialContext<R>>, 'handle'>\n\t) => {\n\t\tapp.use(`${prefix}/*`, async (c, next) => {\n\t\t\tconst timing: RequestTiming = {}\n\t\t\tconst queueMs = options.queueMs?.(c.req.raw)\n\t\t\tif (queueMs !== undefined)\n\t\t\t\ttiming.queue_ms = Math.round(queueMs * 100) / 100\n\t\t\tconst started = performance.now()\n\t\t\tconst headers = options.normalizeHeaders\n\t\t\t\t? options.normalizeHeaders(c.req.raw.headers)\n\t\t\t\t: c.req.raw.headers\n\t\t\tconst context = options.context\n\t\t\t\t? await options.context(c, { headers, timing })\n\t\t\t\t: { headers, timing }\n\t\t\tif (context instanceof Response) return context\n\t\t\tconst invocationTiming: InvocationTiming = { procedureMs: 0, calls: 0 }\n\t\t\tconst { matched, response } = await handler.handle(c.req.raw, {\n\t\t\t\tprefix,\n\t\t\t\tcontext: {\n\t\t\t\t\t...context,\n\t\t\t\t\t[REQUEST_TIMING]: invocationTiming\n\t\t\t\t} as InferRouterInitialContext<R>\n\t\t\t})\n\t\t\tif (!matched) return next()\n\t\t\tconst timed = serverTiming\n\t\t\t\t? formatServerTiming(performance.now() - started, {\n\t\t\t\t\t\t...timing,\n\t\t\t\t\t\thandler_ms: invocationTiming.procedureMs\n\t\t\t\t\t})\n\t\t\t\t: undefined\n\t\t\treturn c.newResponse(response.body, {\n\t\t\t\t// oRPC only produces valid HTTP status codes.\n\t\t\t\tstatus: response.status as StatusCode,\n\t\t\t\theaders: finishOrpcHeaders(response, timed)\n\t\t\t})\n\t\t})\n\t}\n\n\tif (options.rpcPrefix) {\n\t\tconst plugins: Plugin<InferRouterInitialContext<R>>[] = [\n\t\t\t...(options.plugins ?? [])\n\t\t]\n\t\tif (batch) {\n\t\t\tplugins.push(\n\t\t\t\tnew BatchHandlerPlugin({\n\t\t\t\t\tmaxSize: batch === true ? 25 : batch.maxSize\n\t\t\t\t})\n\t\t\t)\n\t\t}\n\t\tmount(\n\t\t\toptions.rpcPrefix,\n\t\t\tnew RPCHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n\n\tif (options.openapi) {\n\t\tconst { openapi } = options\n\t\tconst filter = openapi.filter ? { filter: openapi.filter } : {}\n\t\tconst converters = [new ZodToJsonSchemaConverter()]\n\t\tconst plugins: Plugin<InferRouterInitialContext<R>>[] = [\n\t\t\t...(openapi.plugins ?? [])\n\t\t]\n\t\tif (openapi.smartCoercion) {\n\t\t\tplugins.push(new SmartCoercionPlugin({ schemaConverters: converters }))\n\t\t}\n\t\tplugins.push(\n\t\t\tnew OpenAPIReferencePlugin({\n\t\t\t\tdocsProvider: 'scalar',\n\t\t\t\t...(openapi.docsPath ? { docsPath: openapi.docsPath } : {}),\n\t\t\t\tschemaConverters: converters,\n\t\t\t\tspecGenerateOptions: {\n\t\t\t\t\tinfo: openapi.info ?? { title: 'API', version: '0.0.0' },\n\t\t\t\t\tservers: [{ url: openapi.prefix }],\n\t\t\t\t\t...filter,\n\t\t\t\t\t...openapi.spec\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t\tmount(\n\t\t\topenapi.prefix,\n\t\t\tnew OpenAPIHandler(router, {\n\t\t\t\t...keepAlive,\n\t\t\t\t...filter,\n\t\t\t\tplugins,\n\t\t\t\tinterceptors: options.onError ? [orpcOnError(report)] : []\n\t\t\t})\n\t\t)\n\t}\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ export { type CreateFnOptions, createFn, type FnFactory } from './create-fn.js';
3
3
  export { isExpectedClientError } from './expected-client-error.js';
4
4
  export { createBoundedEventQueue } from './live/pub-sub.js';
5
5
  export { createDefaultLogger, type FnLogger, type LogAttributes } from './logger.js';
6
- export { FN_META_KEY, type FnMeta, readFnMeta } from './meta.js';
6
+ export { defineMeta, FN_META_KEY, type FnMeta, readFnMeta } from './meta.js';
7
7
  export type { AttributeValue, OtelApiLike, SpanLike, SpanOf, Tracing } from './otel.js';
8
- export { createRouter } from './router.js';
8
+ export { createRouter, createStreamManifest, createStreamManifestAsync } from './router.js';
9
9
  export type { AnyFnContext, BuilderLike, CurrentContextOf, Fn, FnCompletedEvent, FnContext, FnDefinition, FnProcedure, FnRouteOptions, Guard, GuardOptions, GuardParams, HandlerParams, InitialContextOf, ProcedureContext, ProcedureInput, ProcedureKey, ProcedureOption, ProcedureOutput, ReservedOptionKey, RouteConfig } from './types.js';
10
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,SAAS,EACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAChE,YAAY,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,MAAM,EACN,OAAO,EACP,MAAM,WAAW,CAAA;AAClB,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,YAAY,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,EAAE,EACF,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,WAAW,EACX,cAAc,EACd,KAAK,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EACN,KAAK,eAAe,EACpB,QAAQ,EACR,KAAK,SAAS,EACd,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EACnB,KAAK,QAAQ,EACb,KAAK,aAAa,EAClB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,KAAK,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC5E,YAAY,EACX,cAAc,EACd,WAAW,EACX,QAAQ,EACR,MAAM,EACN,OAAO,EACP,MAAM,WAAW,CAAA;AAClB,OAAO,EACN,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,aAAa,CAAA;AACpB,YAAY,EACX,YAAY,EACZ,WAAW,EACX,gBAAgB,EAChB,EAAE,EACF,gBAAgB,EAChB,SAAS,EACT,YAAY,EACZ,WAAW,EACX,cAAc,EACd,KAAK,EACL,YAAY,EACZ,WAAW,EACX,aAAa,EACb,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,MAAM,YAAY,CAAA"}
package/dist/index.js CHANGED
@@ -3,6 +3,6 @@ export { createFn } from './create-fn.js';
3
3
  export { isExpectedClientError } from './expected-client-error.js';
4
4
  export { createBoundedEventQueue } from './live/pub-sub.js';
5
5
  export { createDefaultLogger } from './logger.js';
6
- export { FN_META_KEY, readFnMeta } from './meta.js';
7
- export { createRouter } from './router.js';
6
+ export { defineMeta, FN_META_KEY, readFnMeta } from './meta.js';
7
+ export { createRouter, createStreamManifest, createStreamManifestAsync } from './router.js';
8
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAEN,QAAQ,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EAGnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,WAAW,EAAe,UAAU,EAAE,MAAM,WAAW,CAAA;AAQhE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA","sourcesContent":["export { type BoundCall, createBoundCall } from './bound-call.js'\nexport {\n\ttype CreateFnOptions,\n\tcreateFn,\n\ttype FnFactory\n} from './create-fn.js'\nexport { isExpectedClientError } from './expected-client-error.js'\nexport { createBoundedEventQueue } from './live/pub-sub.js'\nexport {\n\tcreateDefaultLogger,\n\ttype FnLogger,\n\ttype LogAttributes\n} from './logger.js'\nexport { FN_META_KEY, type FnMeta, readFnMeta } from './meta.js'\nexport type {\n\tAttributeValue,\n\tOtelApiLike,\n\tSpanLike,\n\tSpanOf,\n\tTracing\n} from './otel.js'\nexport { createRouter } from './router.js'\nexport type {\n\tAnyFnContext,\n\tBuilderLike,\n\tCurrentContextOf,\n\tFn,\n\tFnCompletedEvent,\n\tFnContext,\n\tFnDefinition,\n\tFnProcedure,\n\tFnRouteOptions,\n\tGuard,\n\tGuardOptions,\n\tGuardParams,\n\tHandlerParams,\n\tInitialContextOf,\n\tProcedureContext,\n\tProcedureInput,\n\tProcedureKey,\n\tProcedureOption,\n\tProcedureOutput,\n\tReservedOptionKey,\n\tRouteConfig\n} from './types.js'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAkB,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACjE,OAAO,EAEN,QAAQ,EAER,MAAM,gBAAgB,CAAA;AACvB,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAA;AAClE,OAAO,EAAE,uBAAuB,EAAE,MAAM,mBAAmB,CAAA;AAC3D,OAAO,EACN,mBAAmB,EAGnB,MAAM,aAAa,CAAA;AACpB,OAAO,EAAE,UAAU,EAAE,WAAW,EAAe,UAAU,EAAE,MAAM,WAAW,CAAA;AAQ5E,OAAO,EACN,YAAY,EACZ,oBAAoB,EACpB,yBAAyB,EACzB,MAAM,aAAa,CAAA","sourcesContent":["export { type BoundCall, createBoundCall } from './bound-call.js'\nexport {\n\ttype CreateFnOptions,\n\tcreateFn,\n\ttype FnFactory\n} from './create-fn.js'\nexport { isExpectedClientError } from './expected-client-error.js'\nexport { createBoundedEventQueue } from './live/pub-sub.js'\nexport {\n\tcreateDefaultLogger,\n\ttype FnLogger,\n\ttype LogAttributes\n} from './logger.js'\nexport { defineMeta, FN_META_KEY, type FnMeta, readFnMeta } from './meta.js'\nexport type {\n\tAttributeValue,\n\tOtelApiLike,\n\tSpanLike,\n\tSpanOf,\n\tTracing\n} from './otel.js'\nexport {\n\tcreateRouter,\n\tcreateStreamManifest,\n\tcreateStreamManifestAsync\n} from './router.js'\nexport type {\n\tAnyFnContext,\n\tBuilderLike,\n\tCurrentContextOf,\n\tFn,\n\tFnCompletedEvent,\n\tFnContext,\n\tFnDefinition,\n\tFnProcedure,\n\tFnRouteOptions,\n\tGuard,\n\tGuardOptions,\n\tGuardParams,\n\tHandlerParams,\n\tInitialContextOf,\n\tProcedureContext,\n\tProcedureInput,\n\tProcedureKey,\n\tProcedureOption,\n\tProcedureOutput,\n\tReservedOptionKey,\n\tRouteConfig\n} from './types.js'\n"]}
@@ -44,4 +44,6 @@ export type ToolSchema<TIn = unknown, TOut = TIn> = {
44
44
  export declare function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn>;
45
45
  /** Tool output the procedure already validated: described, passed through. */
46
46
  export declare function passThroughOutputSchema<TOut>(schema: AnySchema): ToolSchema<TOut>;
47
+ /** Tool protocols permit unions only when every branch accepts an object. */
48
+ export declare function isObjectJsonSchema(schema: JsonSchema): boolean;
47
49
  //# sourceMappingURL=json-schema.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI/C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,GAAG,OAAO,EAAE,IAAI,GAAG,GAAG,IAAI;IACnD,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CACT,KAAK,EAAE,OAAO,KAEZ;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GAC9C,OAAO,CACL;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAC/C,CAAA;QACJ,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,GAAG,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAA;QACpC,UAAU,EAAE;YACX,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;YACxC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;SACzC,CAAA;KACD,CAAA;CACD,CAAA;AAYD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAiBtE;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,IAAI,EAC3C,MAAM,EAAE,SAAS,GACf,UAAU,CAAC,IAAI,CAAC,CAUlB"}
1
+ {"version":3,"file":"json-schema.d.ts","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAI/C,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;AAEhD;;;GAGG;AACH,MAAM,MAAM,UAAU,CAAC,GAAG,GAAG,OAAO,EAAE,IAAI,GAAG,GAAG,IAAI;IACnD,WAAW,EAAE;QACZ,OAAO,EAAE,CAAC,CAAA;QACV,MAAM,EAAE,MAAM,CAAA;QACd,QAAQ,EAAE,CACT,KAAK,EAAE,OAAO,KAEZ;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,GAC9C,OAAO,CACL;YAAE,KAAK,EAAE,IAAI,CAAC;YAAC,MAAM,CAAC,EAAE,SAAS,CAAA;SAAE,GACnC;YAAE,MAAM,EAAE,aAAa,CAAC;gBAAE,OAAO,EAAE,MAAM,CAAA;aAAE,CAAC,CAAA;SAAE,CAC/C,CAAA;QACJ,KAAK,CAAC,EAAE;YAAE,KAAK,EAAE,GAAG,CAAC;YAAC,MAAM,EAAE,IAAI,CAAA;SAAE,CAAA;QACpC,UAAU,EAAE;YACX,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;YACxC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,UAAU,CAAA;SACzC,CAAA;KACD,CAAA;CACD,CAAA;AAYD;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,CAiBtE;AAED,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,IAAI,EAC3C,MAAM,EAAE,SAAS,GACf,UAAU,CAAC,IAAI,CAAC,CAUlB;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAa9D"}
@@ -41,4 +41,15 @@ export function passThroughOutputSchema(schema) {
41
41
  }
42
42
  };
43
43
  }
44
+ /** Tool protocols permit unions only when every branch accepts an object. */
45
+ export function isObjectJsonSchema(schema) {
46
+ if (schema.type === 'object')
47
+ return true;
48
+ const union = schema.anyOf ?? schema.oneOf;
49
+ return (Array.isArray(union) &&
50
+ union.length > 0 &&
51
+ union.every((branch) => typeof branch === 'object' &&
52
+ branch !== null &&
53
+ isObjectJsonSchema(branch)));
54
+ }
44
55
  //# sourceMappingURL=json-schema.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AA6BzD,MAAM,SAAS,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAChD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;AAEvC,SAAS,YAAY,CACpB,MAAiB,EACjB,QAA4B;IAE5B,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAe,CAAA;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAM,MAAiB;IACpD,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAQ,CAAA;gBACxD,MAAM,MAAM,GAAG,CACd,MAA+D,EAC9D,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;gBACrE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACpD,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACxE,CAAC;YACD,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CACtC,MAAiB;IAEjB,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACjD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAa,EAAE,CAAC;YAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport { JsonSchemaCoercer } from '@orpc/json-schema'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\n\nexport type JsonSchema = Record<string, unknown>\n\n/**\n * A Standard Schema with JSON Schema attached, as MCP SDKs and Mastra expect.\n * `TIn` is what is validated and what `validate` returns.\n */\nexport type ToolSchema<TIn = unknown, TOut = TIn> = {\n\t'~standard': {\n\t\tversion: 1\n\t\tvendor: string\n\t\tvalidate: (\n\t\t\tvalue: unknown\n\t\t) =>\n\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t| Promise<\n\t\t\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t >\n\t\ttypes?: { input: TIn; output: TOut }\n\t\tjsonSchema: {\n\t\t\tinput: (options?: unknown) => JsonSchema\n\t\t\toutput: (options?: unknown) => JsonSchema\n\t\t}\n\t}\n}\n\nconst converter = new ZodToJsonSchemaConverter()\nconst coercer = new JsonSchemaCoercer()\n\nfunction toJsonSchema(\n\tschema: AnySchema,\n\tstrategy: 'input' | 'output'\n): JsonSchema {\n\treturn converter.convert(schema, { strategy })[1] as JsonSchema\n}\n\n/**\n * Tool input that validates like the procedure but returns the RAW input for\n * the procedure's own input schema to parse. Transforms run in both passes\n * but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like\n * `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs\n * (dates become string/date-time), and clients send those dates as strings,\n * so values are coerced back before validating.\n */\nexport function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn> {\n\tconst jsonSchema = toJsonSchema(schema, 'input')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => {\n\t\t\t\tconst coerced = coercer.coerce(jsonSchema, value) as TIn\n\t\t\t\tconst finish = (\n\t\t\t\t\tresult: Awaited<ReturnType<AnySchema['~standard']['validate']>>\n\t\t\t\t) => (result.issues ? { issues: result.issues } : { value: coerced })\n\t\t\t\tconst result = schema['~standard'].validate(coerced)\n\t\t\t\treturn result instanceof Promise ? result.then(finish) : finish(result)\n\t\t\t},\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool output the procedure already validated: described, passed through. */\nexport function passThroughOutputSchema<TOut>(\n\tschema: AnySchema\n): ToolSchema<TOut> {\n\tconst jsonSchema = toJsonSchema(schema, 'output')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => ({ value: value as TOut }),\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"json-schema.js","sourceRoot":"","sources":["../src/json-schema.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAA;AACrD,OAAO,EAAE,wBAAwB,EAAE,MAAM,gBAAgB,CAAA;AA6BzD,MAAM,SAAS,GAAG,IAAI,wBAAwB,EAAE,CAAA;AAChD,MAAM,OAAO,GAAG,IAAI,iBAAiB,EAAE,CAAA;AAEvC,SAAS,YAAY,CACpB,MAAiB,EACjB,QAA4B;IAE5B,OAAO,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAe,CAAA;AAChE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAM,MAAiB;IACpD,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAChD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE;gBACnB,MAAM,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAQ,CAAA;gBACxD,MAAM,MAAM,GAAG,CACd,MAA+D,EAC9D,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAA;gBACrE,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;gBACpD,OAAO,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;YACxE,CAAC;YACD,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,uBAAuB,CACtC,MAAiB;IAEjB,MAAM,UAAU,GAAG,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACjD,OAAO;QACN,WAAW,EAAE;YACZ,OAAO,EAAE,CAAC;YACV,MAAM,EAAE,SAAS;YACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAa,EAAE,CAAC;YAC/C,UAAU,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;SACjE;KACD,CAAA;AACF,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,MAAkB;IACpD,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAA;IACzC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,IAAI,MAAM,CAAC,KAAK,CAAA;IAC1C,OAAO,CACN,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACpB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,KAAK,CACV,CAAC,MAAM,EAAE,EAAE,CACV,OAAO,MAAM,KAAK,QAAQ;YAC1B,MAAM,KAAK,IAAI;YACf,kBAAkB,CAAC,MAAM,CAAC,CAC3B,CACD,CAAA;AACF,CAAC","sourcesContent":["import type { AnySchema } from '@orpc/contract'\nimport { JsonSchemaCoercer } from '@orpc/json-schema'\nimport { ZodToJsonSchemaConverter } from '@orpc/zod/zod4'\n\nexport type JsonSchema = Record<string, unknown>\n\n/**\n * A Standard Schema with JSON Schema attached, as MCP SDKs and Mastra expect.\n * `TIn` is what is validated and what `validate` returns.\n */\nexport type ToolSchema<TIn = unknown, TOut = TIn> = {\n\t'~standard': {\n\t\tversion: 1\n\t\tvendor: string\n\t\tvalidate: (\n\t\t\tvalue: unknown\n\t\t) =>\n\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t| Promise<\n\t\t\t\t\t| { value: TOut; issues?: undefined }\n\t\t\t\t\t| { issues: ReadonlyArray<{ message: string }> }\n\t\t\t >\n\t\ttypes?: { input: TIn; output: TOut }\n\t\tjsonSchema: {\n\t\t\tinput: (options?: unknown) => JsonSchema\n\t\t\toutput: (options?: unknown) => JsonSchema\n\t\t}\n\t}\n}\n\nconst converter = new ZodToJsonSchemaConverter()\nconst coercer = new JsonSchemaCoercer()\n\nfunction toJsonSchema(\n\tschema: AnySchema,\n\tstrategy: 'input' | 'output'\n): JsonSchema {\n\treturn converter.convert(schema, { strategy })[1] as JsonSchema\n}\n\n/**\n * Tool input that validates like the procedure but returns the RAW input for\n * the procedure's own input schema to parse. Transforms run in both passes\n * but never on their own output, which handing over the parsed value would do. Zod's JSON Schema export rejects types like\n * `z.date()`; oRPC's converter gives the same JSON Schema as the OpenAPI docs\n * (dates become string/date-time), and clients send those dates as strings,\n * so values are coerced back before validating.\n */\nexport function rawInputSchema<TIn>(schema: AnySchema): ToolSchema<TIn> {\n\tconst jsonSchema = toJsonSchema(schema, 'input')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => {\n\t\t\t\tconst coerced = coercer.coerce(jsonSchema, value) as TIn\n\t\t\t\tconst finish = (\n\t\t\t\t\tresult: Awaited<ReturnType<AnySchema['~standard']['validate']>>\n\t\t\t\t) => (result.issues ? { issues: result.issues } : { value: coerced })\n\t\t\t\tconst result = schema['~standard'].validate(coerced)\n\t\t\t\treturn result instanceof Promise ? result.then(finish) : finish(result)\n\t\t\t},\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool output the procedure already validated: described, passed through. */\nexport function passThroughOutputSchema<TOut>(\n\tschema: AnySchema\n): ToolSchema<TOut> {\n\tconst jsonSchema = toJsonSchema(schema, 'output')\n\treturn {\n\t\t'~standard': {\n\t\t\tversion: 1,\n\t\t\tvendor: 'orpc-fn',\n\t\t\tvalidate: (value) => ({ value: value as TOut }),\n\t\t\tjsonSchema: { input: () => jsonSchema, output: () => jsonSchema }\n\t\t}\n\t}\n}\n\n/** Tool protocols permit unions only when every branch accepts an object. */\nexport function isObjectJsonSchema(schema: JsonSchema): boolean {\n\tif (schema.type === 'object') return true\n\tconst union = schema.anyOf ?? schema.oneOf\n\treturn (\n\t\tArray.isArray(union) &&\n\t\tunion.length > 0 &&\n\t\tunion.every(\n\t\t\t(branch) =>\n\t\t\t\ttypeof branch === 'object' &&\n\t\t\t\tbranch !== null &&\n\t\t\t\tisObjectJsonSchema(branch)\n\t\t)\n\t)\n}\n"]}
@@ -4,6 +4,11 @@
4
4
  * intact. Payloads without the envelope are read as plain JSON, so a
5
5
  * publisher on the old format keeps working during a rolling deploy.
6
6
  */
7
- export declare function encodePayload(value: unknown): string;
7
+ export declare function encodePayload(value: unknown, id?: string): string;
8
8
  export declare function decodePayload(payload: string): unknown;
9
+ /** IDs distinguish replay/live overlap; legacy payloads remain readable. */
10
+ export declare function decodeMessage(payload: string): {
11
+ id: string | undefined;
12
+ value: unknown;
13
+ };
9
14
  //# sourceMappingURL=codec.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMpD;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWtD"}
1
+ {"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;AACH,wBAAgB,aAAa,CAC5B,KAAK,EAAE,OAAO,EACd,EAAE,GAAE,MAA4B,GAC9B,MAAM,CAMR;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAWtD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;IAC/C,EAAE,EAAE,MAAM,GAAG,SAAS,CAAA;IACtB,KAAK,EAAE,OAAO,CAAA;CACd,CAUA"}
@@ -7,21 +7,32 @@ const MARKER = 'orpc-fn';
7
7
  * intact. Payloads without the envelope are read as plain JSON, so a
8
8
  * publisher on the old format keeps working during a rolling deploy.
9
9
  */
10
- export function encodePayload(value) {
10
+ export function encodePayload(value, id = crypto.randomUUID()) {
11
11
  const [json, meta, maps, blobs] = serializer.serialize(value);
12
12
  if (maps.length > 0 || blobs.length > 0) {
13
13
  throw new TypeError('orpc-fn: pub/sub events cannot contain files or blobs');
14
14
  }
15
- return JSON.stringify({ [MARKER]: 1, json, meta });
15
+ return JSON.stringify({ [MARKER]: 2, id, json, meta });
16
16
  }
17
17
  export function decodePayload(payload) {
18
18
  const parsed = JSON.parse(payload);
19
19
  if (typeof parsed === 'object' &&
20
20
  parsed !== null &&
21
- parsed[MARKER] === 1) {
21
+ [1, 2].includes(Number(parsed[MARKER]))) {
22
22
  const { json, meta } = parsed;
23
23
  return serializer.deserialize(json, meta);
24
24
  }
25
25
  return parsed;
26
26
  }
27
+ /** IDs distinguish replay/live overlap; legacy payloads remain readable. */
28
+ export function decodeMessage(payload) {
29
+ const envelope = JSON.parse(payload);
30
+ const id = typeof envelope === 'object' &&
31
+ envelope !== null &&
32
+ envelope[MARKER] === 2 &&
33
+ typeof envelope.id === 'string'
34
+ ? envelope.id
35
+ : undefined;
36
+ return { id, value: decodePayload(payload) };
37
+ }
27
38
  //# sourceMappingURL=codec.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE,MAAM,UAAU,GAAG,IAAI,yBAAyB,EAAE,CAAA;AAClD,MAAM,MAAM,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc;IAC3C,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,uDAAuD,CAAC,CAAA;IAC7E,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC5C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC3C,IACC,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACd,MAAkC,CAAC,MAAM,CAAC,KAAK,CAAC,EAChD,CAAC;QACF,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAqC,CAAA;QAC5D,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC","sourcesContent":["import { StandardRPCJsonSerializer } from '@orpc/client/standard'\n\nconst serializer = new StandardRPCJsonSerializer()\nconst MARKER = 'orpc-fn'\n\n/**\n * Wire format for pub/sub payloads: oRPC's own JSON serializer, so values\n * plain JSON loses (`Date`, `Map`, `Set`, `BigInt`, `URL`, `undefined`) arrive\n * intact. Payloads without the envelope are read as plain JSON, so a\n * publisher on the old format keeps working during a rolling deploy.\n */\nexport function encodePayload(value: unknown): string {\n\tconst [json, meta, maps, blobs] = serializer.serialize(value)\n\tif (maps.length > 0 || blobs.length > 0) {\n\t\tthrow new TypeError('orpc-fn: pub/sub events cannot contain files or blobs')\n\t}\n\treturn JSON.stringify({ [MARKER]: 1, json, meta })\n}\n\nexport function decodePayload(payload: string): unknown {\n\tconst parsed: unknown = JSON.parse(payload)\n\tif (\n\t\ttypeof parsed === 'object' &&\n\t\tparsed !== null &&\n\t\t(parsed as Record<string, unknown>)[MARKER] === 1\n\t) {\n\t\tconst { json, meta } = parsed as { json: unknown; meta: [] }\n\t\treturn serializer.deserialize(json, meta)\n\t}\n\treturn parsed\n}\n"]}
1
+ {"version":3,"file":"codec.js","sourceRoot":"","sources":["../../src/live/codec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,yBAAyB,EAAE,MAAM,uBAAuB,CAAA;AAEjE,MAAM,UAAU,GAAG,IAAI,yBAAyB,EAAE,CAAA;AAClD,MAAM,MAAM,GAAG,SAAS,CAAA;AAExB;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAC5B,KAAc,EACd,EAAE,GAAW,MAAM,CAAC,UAAU,EAAE;IAEhC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC7D,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACzC,MAAM,IAAI,SAAS,CAAC,uDAAuD,CAAC,CAAA;IAC7E,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAA;AACvD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC5C,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAC3C,IACC,OAAO,MAAM,KAAK,QAAQ;QAC1B,MAAM,KAAK,IAAI;QACf,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAE,MAAkC,CAAC,MAAM,CAAC,CAAC,CAAC,EACnE,CAAC;QACF,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,MAAqC,CAAA;QAC5D,OAAO,UAAU,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAA;IAC1C,CAAC;IACD,OAAO,MAAM,CAAA;AACd,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,OAAe;IAI5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAY,CAAA;IAC/C,MAAM,EAAE,GACP,OAAO,QAAQ,KAAK,QAAQ;QAC5B,QAAQ,KAAK,IAAI;QAChB,QAAoC,CAAC,MAAM,CAAC,KAAK,CAAC;QACnD,OAAQ,QAAoC,CAAC,EAAE,KAAK,QAAQ;QAC3D,CAAC,CAAE,QAA2B,CAAC,EAAE;QACjC,CAAC,CAAC,SAAS,CAAA;IACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,aAAa,CAAC,OAAO,CAAC,EAAE,CAAA;AAC7C,CAAC","sourcesContent":["import { StandardRPCJsonSerializer } from '@orpc/client/standard'\n\nconst serializer = new StandardRPCJsonSerializer()\nconst MARKER = 'orpc-fn'\n\n/**\n * Wire format for pub/sub payloads: oRPC's own JSON serializer, so values\n * plain JSON loses (`Date`, `Map`, `Set`, `BigInt`, `URL`, `undefined`) arrive\n * intact. Payloads without the envelope are read as plain JSON, so a\n * publisher on the old format keeps working during a rolling deploy.\n */\nexport function encodePayload(\n\tvalue: unknown,\n\tid: string = crypto.randomUUID()\n): string {\n\tconst [json, meta, maps, blobs] = serializer.serialize(value)\n\tif (maps.length > 0 || blobs.length > 0) {\n\t\tthrow new TypeError('orpc-fn: pub/sub events cannot contain files or blobs')\n\t}\n\treturn JSON.stringify({ [MARKER]: 2, id, json, meta })\n}\n\nexport function decodePayload(payload: string): unknown {\n\tconst parsed: unknown = JSON.parse(payload)\n\tif (\n\t\ttypeof parsed === 'object' &&\n\t\tparsed !== null &&\n\t\t[1, 2].includes(Number((parsed as Record<string, unknown>)[MARKER]))\n\t) {\n\t\tconst { json, meta } = parsed as { json: unknown; meta: [] }\n\t\treturn serializer.deserialize(json, meta)\n\t}\n\treturn parsed\n}\n\n/** IDs distinguish replay/live overlap; legacy payloads remain readable. */\nexport function decodeMessage(payload: string): {\n\tid: string | undefined\n\tvalue: unknown\n} {\n\tconst envelope = JSON.parse(payload) as unknown\n\tconst id =\n\t\ttypeof envelope === 'object' &&\n\t\tenvelope !== null &&\n\t\t(envelope as Record<string, unknown>)[MARKER] === 2 &&\n\t\ttypeof (envelope as Record<string, unknown>).id === 'string'\n\t\t\t? (envelope as { id: string }).id\n\t\t\t: undefined\n\treturn { id, value: decodePayload(payload) }\n}\n"]}
@@ -1,10 +1,11 @@
1
- import type { Schema } from '@orpc/contract';
1
+ import type { AnySchema, ErrorMap, Schema } from '@orpc/contract';
2
2
  import { type AnyProcedure } from '@orpc/server';
3
3
  import type { ZodType, z } from 'zod';
4
+ import { RAW_INPUT } from '../timing.js';
4
5
  import type { FnLogger } from '../logger.js';
5
6
  import { type SpanLike } from '../otel.js';
6
7
  import type { FnContext, FnDefinition, FnProcedure, FnRouteOptions, HandlerParams, MaybePromise, ProcedureKey } from '../types.js';
7
- import type { AuthFn, Channel, ChannelDefinition, ChannelOptions, ObjectSchema, PublisherConfig } from './pub-sub.js';
8
+ import type { AuthFn, Channel, ChannelDefinition, ChannelOptions, ChannelQueueOptions, ObjectSchema, PublisherConfig } from './pub-sub.js';
8
9
  declare const fnLivePatchMarker: unique symbol;
9
10
  /**
10
11
  * Transformer result that splits the internal accumulator from the wire
@@ -18,27 +19,31 @@ export type FnLivePatch<TOutput, TEmit> = {
18
19
  emit: TEmit;
19
20
  };
20
21
  export declare function fnLivePatch<TOutput, TEmit>(state: TOutput, emit: TEmit): FnLivePatch<TOutput, TEmit>;
21
- export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit = never> = Omit<PublisherConfig, 'name'> & {
22
+ export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit = never, TErrors extends ErrorMap = Record<never, never>> = Omit<PublisherConfig, 'name'> & ChannelQueueOptions & {
22
23
  /** Subscribe route name; default `${name}.live`. */
23
24
  name?: string;
25
+ /** Validates parsed reducer state without reapplying an output transform. Required with a transformer. */
26
+ stateSchema?: Schema<TOutput, TOutput>;
27
+ /** Validates patch payloads. Required when a transformer returns fnLivePatch. */
28
+ emitSchema?: Schema<TEmit, TEmit>;
29
+ /** Optional access check before each update; idle streams keep their initial authorization. */
30
+ reauthorize?: AuthFn<TInput, FnContext<TDef, TKey>>;
24
31
  eventSchema: TEventSchema;
25
32
  channel: ChannelDefinition<TInput, z.output<TEventSchema>, FnContext<TDef, TKey>>;
26
33
  /** Fold an event into the snapshot; without it every event re-runs the handler. */
27
- transformerFn?: (params: HandlerParams<TDef, TInput, TKey> & {
28
- event: z.output<TEventSchema>;
29
- previous: TOutput | undefined;
30
- rerun: (input?: TInput) => Promise<TOutput>;
31
- }) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
34
+ transformerFn?: FnLiveConfigTransformer<TDef, TInput, TEventSchema, TOutput, TKey, TEmit, TErrors>;
32
35
  /** Return false to skip an event. */
33
- shouldUpdate?: (params: HandlerParams<TDef, TInput, TKey> & {
36
+ shouldUpdate?: (params: HandlerParams<TDef, TInput, TKey, TErrors> & {
34
37
  event: z.output<TEventSchema>;
35
- previous: TOutput | undefined;
38
+ previous: TOutput;
36
39
  }) => MaybePromise<boolean>;
37
40
  authFn?: AuthFn<TInput, FnContext<TDef, TKey>>;
38
41
  /** Log publish failures instead of throwing them into the publishing route. */
39
42
  safePublish?: boolean;
40
43
  /** Batch events arriving within this window into one snapshot update. */
41
44
  coalesceMs?: number;
45
+ /** Maximum events collected in one coalescing batch (default 1000). */
46
+ maxBatchSize?: number;
42
47
  /**
43
48
  * When a slow subscriber's queue overflows (drop-oldest), this marker is
44
49
  * enqueued INSTEAD of the dropped event so the client resyncs. Return
@@ -47,11 +52,29 @@ export type FnLiveConfig<TDef extends FnDefinition, TInput, TEventSchema extends
47
52
  overflowMarker?: (input: TInput) => z.output<TEventSchema> | null;
48
53
  summary?: string;
49
54
  description?: string;
50
- };
51
- export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInput extends ObjectSchema, TOutputSchema extends Schema<unknown, unknown>, TOutput, TEventSchema extends ZodType, TEmit = never> = {
52
- procedure: FnProcedure<TDef, TKey, TInput, TOutputSchema>;
53
- subscribe: FnProcedure<TDef, TKey, TInput, Schema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>>;
55
+ } & ({
56
+ transformerFn?: undefined;
57
+ } | {
58
+ transformerFn: FnLiveConfigTransformer<TDef, TInput, TEventSchema, TOutput, TKey, TEmit, TErrors>;
59
+ stateSchema: Schema<TOutput, TOutput>;
60
+ }) & ([TEmit] extends [never] ? object : {
61
+ emitSchema: Schema<TEmit, TEmit>;
62
+ });
63
+ type FnLiveConfigTransformer<TDef extends FnDefinition, TInput, TEventSchema extends ZodType, TOutput, TKey extends ProcedureKey<TDef>, TEmit, TErrors extends ErrorMap> = (params: HandlerParams<TDef, TInput, TKey, TErrors> & {
64
+ event: z.output<TEventSchema>;
65
+ previous: TOutput;
66
+ rerun: () => Promise<TOutput>;
67
+ }) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
68
+ export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TDef>, TInput extends ObjectSchema, TOutputSchema extends Schema<unknown, unknown>, TOutput, TEventSchema extends ZodType, TEmit = never, TErrors extends ErrorMap = Record<never, never>> = {
69
+ procedure: FnProcedure<TDef, TKey, TInput, TOutputSchema, TErrors>;
70
+ subscribe: FnProcedure<TDef, TKey, TInput, Schema<AsyncGenerator<TOutput | TEmit>, AsyncGenerator<TOutput | TEmit>>, TErrors>;
54
71
  publish: (event: z.input<TEventSchema>) => Promise<void>;
72
+ getSubscriptionChannelName: (params: {
73
+ input: z.output<TInput>;
74
+ context: FnContext<TDef, TKey>;
75
+ }) => string;
76
+ getPublishChannelName: (event: z.output<TEventSchema>) => string;
77
+ /** @deprecated Prefer the separate required-input resolver methods. */
55
78
  getChannelName: (params: Partial<z.output<TInput>> | Partial<z.output<TEventSchema>>, context?: FnContext<TDef, TKey>) => string;
56
79
  };
57
80
  /**
@@ -59,22 +82,22 @@ export type FnLiveReturn<TDef extends FnDefinition, TKey extends ProcedureKey<TD
59
82
  * snapshot, then an update for every event published on the channel.
60
83
  */
61
84
  export interface FnLive<TDef extends FnDefinition> {
62
- <TInput extends ObjectSchema, TOutputSchema extends ZodType, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never>(options: {
85
+ <TInput extends ObjectSchema, TOutputSchema extends ZodType, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never, TErrors extends ErrorMap = Record<never, never>>(options: {
63
86
  input: TInput;
64
87
  output: TOutputSchema;
65
- handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {
88
+ handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>, TErrors> & {
66
89
  publish: (event: z.input<TEventSchema>) => Promise<void>;
67
90
  }) => MaybePromise<z.input<TOutputSchema>>;
68
- live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, z.output<TOutputSchema>, NoInfer<TKey>, TEmit>;
69
- } & FnRouteOptions<TDef, TKey>): FnLiveReturn<TDef, TKey, TInput, TOutputSchema, z.output<TOutputSchema>, TEventSchema, TEmit>;
70
- <TInput extends ObjectSchema, TOutput, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never>(options: {
91
+ live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, z.output<TOutputSchema>, NoInfer<TKey>, TEmit, TErrors>;
92
+ } & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>): FnLiveReturn<TDef, TKey, TInput, TOutputSchema, z.output<TOutputSchema>, TEventSchema, TEmit, TErrors>;
93
+ <TInput extends ObjectSchema, TOutput, TEventSchema extends ZodType, TKey extends ProcedureKey<TDef> = TDef['default'], TEmit = never, TErrors extends ErrorMap = Record<never, never>>(options: {
71
94
  input: TInput;
72
95
  output?: undefined;
73
- handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>> & {
96
+ handler: (params: HandlerParams<TDef, z.output<TInput>, NoInfer<TKey>, TErrors> & {
74
97
  publish: (event: z.input<TEventSchema>) => Promise<void>;
75
98
  }) => MaybePromise<TOutput>;
76
- live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, TOutput, NoInfer<TKey>, TEmit>;
77
- } & FnRouteOptions<TDef, TKey>): FnLiveReturn<TDef, TKey, TInput, Schema<TOutput, TOutput>, TOutput, TEventSchema, TEmit>;
99
+ live: FnLiveConfig<TDef, z.output<TInput>, TEventSchema, TOutput, NoInfer<TKey>, TEmit, TErrors>;
100
+ } & FnRouteOptions<TDef, TKey, z.output<TInput>, TErrors>): FnLiveReturn<TDef, TKey, TInput, Schema<TOutput, TOutput>, TOutput, TEventSchema, TEmit, TErrors>;
78
101
  }
79
102
  /**
80
103
  * Fail a live subscription whose initial snapshot could not be built.
@@ -104,6 +127,9 @@ isExpected?: (error: unknown) => boolean): never;
104
127
  */
105
128
  export declare function streamLiveSnapshots<TEvent, TOutput, TEmit = never>(opts: {
106
129
  source: AsyncIterator<TEvent>;
130
+ /** Maximum events retained in one coalescing batch. */
131
+ maxBatchSize?: number;
132
+ applyBatch?: (events: readonly TEvent[], previous: TOutput) => MaybePromise<TOutput | undefined>;
107
133
  initial: TOutput;
108
134
  coalesceMs?: number | undefined;
109
135
  apply: (event: TEvent, previous: TOutput) => MaybePromise<TOutput | FnLivePatch<TOutput, TEmit> | undefined>;
@@ -113,14 +139,20 @@ type RuntimeParams = Record<string, unknown> & {
113
139
  context: unknown;
114
140
  signal: AbortSignal | undefined;
115
141
  logger: FnLogger;
142
+ call: (procedure: AnyProcedure, input: unknown) => Promise<unknown>;
143
+ [RAW_INPUT]: unknown;
116
144
  };
117
145
  /** `FnLiveConfig` with the generics erased: what the implementation reads. */
118
146
  type RuntimeLiveConfig = Omit<ChannelOptions, 'name'> & {
119
147
  name?: string;
148
+ stateSchema?: AnySchema;
149
+ emitSchema?: AnySchema;
150
+ reauthorize?: AuthFn<Record<string, unknown>, unknown>;
120
151
  transformerFn?: (params: RuntimeParams & Record<string, unknown>) => unknown;
121
152
  shouldUpdate?: (params: RuntimeParams & Record<string, unknown>) => unknown;
122
153
  safePublish?: boolean;
123
154
  coalesceMs?: number;
155
+ maxBatchSize?: number;
124
156
  summary?: string;
125
157
  description?: string;
126
158
  };
@@ -150,6 +182,15 @@ export declare function createFnLive(runtime: {
150
182
  getChannelName: (params: {
151
183
  [x: string]: unknown;
152
184
  }, context?: unknown) => string;
185
+ getSubscriptionChannelName: (params: {
186
+ input: {
187
+ [x: string]: unknown;
188
+ };
189
+ context: unknown;
190
+ }) => string;
191
+ getPublishChannelName: (event: {
192
+ [x: string]: unknown;
193
+ }) => string;
153
194
  };
154
195
  export {};
155
196
  //# sourceMappingURL=fn-live.d.ts.map