@orpc/server 2.0.0-beta.48 → 2.0.0-beta.49

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 (269) hide show
  1. package/README.md +4 -4
  2. package/dist/adapters/aws-lambda/handler.d.ts +25 -0
  3. package/dist/adapters/aws-lambda/handler.js +24 -0
  4. package/dist/adapters/aws-lambda/index.d.ts +16 -0
  5. package/dist/adapters/aws-lambda/index.js +2 -0
  6. package/dist/adapters/aws-lambda/rpc-handler.d.ts +19 -0
  7. package/dist/adapters/aws-lambda/rpc-handler.js +18 -0
  8. package/dist/adapters/crossws/handler.d.ts +45 -0
  9. package/dist/adapters/crossws/handler.js +60 -0
  10. package/dist/adapters/crossws/index.d.ts +2 -0
  11. package/dist/adapters/crossws/index.js +2 -0
  12. package/dist/adapters/crossws/rpc-handler.d.ts +16 -0
  13. package/dist/adapters/crossws/rpc-handler.js +15 -0
  14. package/dist/adapters/fastify/handler.d.ts +21 -0
  15. package/dist/adapters/fastify/handler.js +20 -0
  16. package/dist/adapters/fastify/index.d.ts +2 -0
  17. package/dist/adapters/fastify/index.js +2 -0
  18. package/dist/adapters/fastify/rpc-handler.d.ts +15 -0
  19. package/dist/adapters/fastify/rpc-handler.js +14 -0
  20. package/dist/adapters/fetch/handler.d.ts +23 -0
  21. package/dist/adapters/fetch/handler.js +22 -0
  22. package/dist/adapters/fetch/index.d.ts +7 -0
  23. package/dist/adapters/fetch/index.js +7 -0
  24. package/dist/adapters/fetch/rpc-handler.d.ts +17 -0
  25. package/dist/adapters/fetch/rpc-handler.js +16 -0
  26. package/dist/adapters/message-port/handler.d.ts +64 -0
  27. package/dist/adapters/message-port/handler.js +86 -0
  28. package/dist/adapters/message-port/index.d.ts +2 -0
  29. package/dist/adapters/message-port/index.js +2 -0
  30. package/dist/adapters/message-port/rpc-handler.d.ts +16 -0
  31. package/dist/adapters/message-port/rpc-handler.js +15 -0
  32. package/dist/adapters/node/handler.d.ts +21 -0
  33. package/dist/adapters/node/handler.js +20 -0
  34. package/dist/adapters/node/index.d.ts +7 -0
  35. package/dist/adapters/node/index.js +7 -0
  36. package/dist/adapters/node/rpc-handler.d.ts +16 -0
  37. package/dist/adapters/node/rpc-handler.js +15 -0
  38. package/dist/adapters/standard/codec.d.ts +16 -0
  39. package/dist/adapters/standard/handler.d.ts +68 -0
  40. package/dist/adapters/standard/handler.js +205 -0
  41. package/dist/adapters/standard/index.d.ts +6 -0
  42. package/dist/adapters/standard/index.js +5 -0
  43. package/dist/adapters/standard/plugin.d.ts +32 -0
  44. package/dist/adapters/standard/plugin.js +16 -0
  45. package/dist/adapters/standard/rpc-handler-codec.d.ts +46 -0
  46. package/dist/adapters/standard/rpc-handler-codec.js +51 -0
  47. package/dist/adapters/standard/rpc-matcher.d.ts +53 -0
  48. package/dist/adapters/standard/rpc-matcher.js +152 -0
  49. package/dist/adapters/standard/utils.d.ts +10 -0
  50. package/dist/adapters/standard/utils.js +6 -0
  51. package/dist/adapters/standard-peer/index.d.ts +1 -0
  52. package/dist/adapters/standard-peer/index.js +1 -0
  53. package/dist/adapters/standard-peer/{utils.d.mts → utils.d.ts} +3 -3
  54. package/dist/adapters/standard-peer/utils.js +7 -0
  55. package/dist/adapters/websocket/handler.d.ts +59 -0
  56. package/dist/adapters/websocket/handler.js +85 -0
  57. package/dist/adapters/websocket/index.d.ts +2 -0
  58. package/dist/adapters/websocket/index.js +2 -0
  59. package/dist/adapters/websocket/rpc-handler.d.ts +16 -0
  60. package/dist/adapters/websocket/rpc-handler.js +15 -0
  61. package/dist/builder-variants.d.ts +226 -0
  62. package/dist/builder.d.ts +127 -0
  63. package/dist/builder.js +226 -0
  64. package/dist/context.d.ts +6 -0
  65. package/dist/extensions/callable.d.ts +11 -0
  66. package/dist/extensions/callable.js +7 -0
  67. package/dist/helpers/base64url.d.ts +31 -0
  68. package/dist/helpers/base64url.js +53 -0
  69. package/dist/helpers/cookie.d.ts +51 -0
  70. package/dist/helpers/cookie.js +69 -0
  71. package/dist/helpers/encryption.d.ts +28 -0
  72. package/dist/helpers/encryption.js +80 -0
  73. package/dist/helpers/index.d.ts +4 -0
  74. package/dist/helpers/index.js +4 -0
  75. package/dist/helpers/signing.d.ts +50 -0
  76. package/dist/helpers/signing.js +88 -0
  77. package/dist/implementer-procedure.d.ts +16 -0
  78. package/dist/implementer-procedure.js +44 -0
  79. package/dist/implementer-router.d.ts +40 -0
  80. package/dist/implementer-router.js +117 -0
  81. package/dist/implementer.d.ts +16 -0
  82. package/dist/implementer.js +37 -0
  83. package/dist/index.d.ts +61 -0
  84. package/dist/index.js +48 -0
  85. package/dist/lazy.d.ts +20 -0
  86. package/dist/lazy.js +31 -0
  87. package/dist/middleware-decorated.d.ts +10 -0
  88. package/dist/middleware-decorated.js +71 -0
  89. package/dist/middleware.d.ts +54 -0
  90. package/dist/plugins/batch.d.ts +102 -0
  91. package/dist/plugins/batch.js +405 -0
  92. package/dist/plugins/cors.d.ts +73 -0
  93. package/dist/plugins/cors.js +112 -0
  94. package/dist/plugins/get-method-csrf-protection.d.ts +23 -0
  95. package/dist/plugins/get-method-csrf-protection.js +64 -0
  96. package/dist/plugins/head-method.d.ts +23 -0
  97. package/dist/plugins/head-method.js +104 -0
  98. package/dist/plugins/index.d.ts +39 -0
  99. package/dist/plugins/index.js +29 -0
  100. package/dist/plugins/method-override.d.ts +38 -0
  101. package/dist/plugins/method-override.js +50 -0
  102. package/dist/plugins/request-compression.d.ts +16 -0
  103. package/dist/plugins/request-compression.js +82 -0
  104. package/dist/plugins/request-headers.d.ts +22 -0
  105. package/dist/plugins/request-headers.js +30 -0
  106. package/dist/plugins/request-limit.d.ts +30 -0
  107. package/dist/plugins/request-limit.js +68 -0
  108. package/dist/plugins/response-compression.d.ts +59 -0
  109. package/dist/plugins/response-compression.js +209 -0
  110. package/dist/plugins/response-headers.d.ts +30 -0
  111. package/dist/plugins/response-headers.js +47 -0
  112. package/dist/plugins/rethrow.d.ts +33 -0
  113. package/dist/plugins/rethrow.js +59 -0
  114. package/dist/plugins/signal-sync.d.ts +13 -0
  115. package/dist/plugins/signal-sync.js +91 -0
  116. package/dist/plugins/timeout.d.ts +37 -0
  117. package/dist/plugins/timeout.js +59 -0
  118. package/dist/procedure-client.d.ts +19 -0
  119. package/dist/procedure-client.js +175 -0
  120. package/dist/procedure-decorated.d.ts +10 -0
  121. package/dist/procedure-decorated.js +44 -0
  122. package/dist/procedure-utils.d.ts +41 -0
  123. package/dist/procedure-utils.js +49 -0
  124. package/dist/procedure.d.ts +72 -0
  125. package/dist/procedure.js +24 -0
  126. package/dist/router-client.d.ts +23 -0
  127. package/dist/router-client.js +43 -0
  128. package/dist/{router-hidden.d.mts → router-hidden.d.ts} +3 -3
  129. package/dist/router-hidden.js +14 -0
  130. package/dist/router-utils.d.ts +48 -0
  131. package/dist/router-utils.js +202 -0
  132. package/dist/router.d.ts +72 -0
  133. package/package.json +84 -86
  134. package/dist/adapters/aws-lambda/handler.d.mts +0 -25
  135. package/dist/adapters/aws-lambda/handler.mjs +0 -21
  136. package/dist/adapters/aws-lambda/index.d.mts +0 -16
  137. package/dist/adapters/aws-lambda/index.mjs +0 -2
  138. package/dist/adapters/aws-lambda/rpc-handler.d.mts +0 -18
  139. package/dist/adapters/aws-lambda/rpc-handler.mjs +0 -10
  140. package/dist/adapters/crossws/handler.d.mts +0 -41
  141. package/dist/adapters/crossws/handler.mjs +0 -38
  142. package/dist/adapters/crossws/index.d.mts +0 -2
  143. package/dist/adapters/crossws/index.mjs +0 -2
  144. package/dist/adapters/crossws/rpc-handler.d.mts +0 -15
  145. package/dist/adapters/crossws/rpc-handler.mjs +0 -10
  146. package/dist/adapters/fastify/handler.d.mts +0 -21
  147. package/dist/adapters/fastify/handler.mjs +0 -20
  148. package/dist/adapters/fastify/index.d.mts +0 -2
  149. package/dist/adapters/fastify/index.mjs +0 -2
  150. package/dist/adapters/fastify/rpc-handler.d.mts +0 -14
  151. package/dist/adapters/fastify/rpc-handler.mjs +0 -10
  152. package/dist/adapters/fetch/handler.d.mts +0 -23
  153. package/dist/adapters/fetch/handler.mjs +0 -22
  154. package/dist/adapters/fetch/index.d.mts +0 -7
  155. package/dist/adapters/fetch/index.mjs +0 -5
  156. package/dist/adapters/fetch/rpc-handler.d.mts +0 -16
  157. package/dist/adapters/fetch/rpc-handler.mjs +0 -10
  158. package/dist/adapters/message-port/handler.d.mts +0 -57
  159. package/dist/adapters/message-port/handler.mjs +0 -62
  160. package/dist/adapters/message-port/index.d.mts +0 -2
  161. package/dist/adapters/message-port/index.mjs +0 -2
  162. package/dist/adapters/message-port/rpc-handler.d.mts +0 -15
  163. package/dist/adapters/message-port/rpc-handler.mjs +0 -10
  164. package/dist/adapters/node/handler.d.mts +0 -21
  165. package/dist/adapters/node/handler.mjs +0 -20
  166. package/dist/adapters/node/index.d.mts +0 -7
  167. package/dist/adapters/node/index.mjs +0 -5
  168. package/dist/adapters/node/rpc-handler.d.mts +0 -15
  169. package/dist/adapters/node/rpc-handler.mjs +0 -10
  170. package/dist/adapters/standard/codec.d.mts +0 -16
  171. package/dist/adapters/standard/handler.d.mts +0 -68
  172. package/dist/adapters/standard/handler.mjs +0 -185
  173. package/dist/adapters/standard/index.d.mts +0 -6
  174. package/dist/adapters/standard/index.mjs +0 -5
  175. package/dist/adapters/standard/plugin.d.mts +0 -32
  176. package/dist/adapters/standard/plugin.mjs +0 -16
  177. package/dist/adapters/standard/rpc-handler-codec.d.mts +0 -42
  178. package/dist/adapters/standard/rpc-handler-codec.mjs +0 -51
  179. package/dist/adapters/standard/rpc-matcher.d.mts +0 -53
  180. package/dist/adapters/standard/rpc-matcher.mjs +0 -140
  181. package/dist/adapters/standard/utils.d.mts +0 -10
  182. package/dist/adapters/standard/utils.mjs +0 -6
  183. package/dist/adapters/standard-peer/index.d.mts +0 -1
  184. package/dist/adapters/standard-peer/index.mjs +0 -1
  185. package/dist/adapters/standard-peer/utils.mjs +0 -11
  186. package/dist/adapters/websocket/handler.d.mts +0 -55
  187. package/dist/adapters/websocket/handler.mjs +0 -55
  188. package/dist/adapters/websocket/index.d.mts +0 -2
  189. package/dist/adapters/websocket/index.mjs +0 -2
  190. package/dist/adapters/websocket/rpc-handler.d.mts +0 -15
  191. package/dist/adapters/websocket/rpc-handler.mjs +0 -10
  192. package/dist/builder-variants.d.mts +0 -267
  193. package/dist/builder.d.mts +0 -141
  194. package/dist/builder.mjs +0 -145
  195. package/dist/context.d.mts +0 -13
  196. package/dist/extensions/callable.d.mts +0 -17
  197. package/dist/extensions/callable.mjs +0 -7
  198. package/dist/helpers/base64url.d.mts +0 -31
  199. package/dist/helpers/base64url.mjs +0 -25
  200. package/dist/helpers/cookie.d.mts +0 -50
  201. package/dist/helpers/cookie.mjs +0 -35
  202. package/dist/helpers/encryption.d.mts +0 -28
  203. package/dist/helpers/encryption.mjs +0 -62
  204. package/dist/helpers/index.d.mts +0 -4
  205. package/dist/helpers/index.mjs +0 -4
  206. package/dist/helpers/signing.d.mts +0 -50
  207. package/dist/helpers/signing.mjs +0 -43
  208. package/dist/implementer-procedure.d.mts +0 -36
  209. package/dist/implementer-procedure.mjs +0 -38
  210. package/dist/implementer-router.d.mts +0 -78
  211. package/dist/implementer-router.mjs +0 -77
  212. package/dist/implementer.d.mts +0 -22
  213. package/dist/implementer.mjs +0 -30
  214. package/dist/index.d.mts +0 -57
  215. package/dist/index.mjs +0 -30
  216. package/dist/lazy.d.mts +0 -20
  217. package/dist/lazy.mjs +0 -22
  218. package/dist/middleware-decorated.d.mts +0 -27
  219. package/dist/middleware-decorated.mjs +0 -65
  220. package/dist/middleware.d.mts +0 -70
  221. package/dist/plugins/batch.d.mts +0 -104
  222. package/dist/plugins/batch.mjs +0 -373
  223. package/dist/plugins/cors.d.mts +0 -67
  224. package/dist/plugins/cors.mjs +0 -134
  225. package/dist/plugins/get-method-csrf-protection.d.mts +0 -23
  226. package/dist/plugins/get-method-csrf-protection.mjs +0 -45
  227. package/dist/plugins/head-method.d.mts +0 -23
  228. package/dist/plugins/head-method.mjs +0 -95
  229. package/dist/plugins/index.d.mts +0 -39
  230. package/dist/plugins/index.mjs +0 -23
  231. package/dist/plugins/method-override.d.mts +0 -38
  232. package/dist/plugins/method-override.mjs +0 -50
  233. package/dist/plugins/request-compression.d.mts +0 -16
  234. package/dist/plugins/request-compression.mjs +0 -67
  235. package/dist/plugins/request-headers.d.mts +0 -22
  236. package/dist/plugins/request-headers.mjs +0 -21
  237. package/dist/plugins/request-limit.d.mts +0 -30
  238. package/dist/plugins/request-limit.mjs +0 -53
  239. package/dist/plugins/response-compression.d.mts +0 -59
  240. package/dist/plugins/response-compression.mjs +0 -172
  241. package/dist/plugins/response-headers.d.mts +0 -30
  242. package/dist/plugins/response-headers.mjs +0 -34
  243. package/dist/plugins/rethrow.d.mts +0 -33
  244. package/dist/plugins/rethrow.mjs +0 -46
  245. package/dist/plugins/signal-sync.d.mts +0 -13
  246. package/dist/plugins/signal-sync.mjs +0 -84
  247. package/dist/plugins/timeout.d.mts +0 -37
  248. package/dist/plugins/timeout.mjs +0 -56
  249. package/dist/procedure-client.d.mts +0 -41
  250. package/dist/procedure-client.mjs +0 -157
  251. package/dist/procedure-decorated.d.mts +0 -20
  252. package/dist/procedure-decorated.mjs +0 -41
  253. package/dist/procedure-utils.d.mts +0 -52
  254. package/dist/procedure-utils.mjs +0 -33
  255. package/dist/procedure.d.mts +0 -93
  256. package/dist/procedure.mjs +0 -20
  257. package/dist/router-client.d.mts +0 -27
  258. package/dist/router-client.mjs +0 -35
  259. package/dist/router-hidden.mjs +0 -12
  260. package/dist/router-utils.d.mts +0 -59
  261. package/dist/router-utils.mjs +0 -191
  262. package/dist/router.d.mts +0 -61
  263. /package/dist/adapters/standard/{codec.mjs → codec.js} +0 -0
  264. /package/dist/{builder-variants.mjs → builder-variants.js} +0 -0
  265. /package/dist/{constants.d.mts → constants.d.ts} +0 -0
  266. /package/dist/{constants.mjs → constants.js} +0 -0
  267. /package/dist/{context.mjs → context.js} +0 -0
  268. /package/dist/{middleware.mjs → middleware.js} +0 -0
  269. /package/dist/{router.mjs → router.js} +0 -0
@@ -0,0 +1,152 @@
1
+ import { normalizeHttpPath, pathToHttpPath, value } from '@orpc/shared';
2
+ import { unlazy } from '../../lazy.js';
3
+ import { Procedure } from '../../procedure.js';
4
+ import { resolveContractProcedure, walkProcedureContractsSync } from '../../router-utils.js';
5
+ /**
6
+ * Methods that can invoke procedures by default. Browsers cannot trigger them
7
+ * cross-site without a CORS preflight or an HTML form, unlike `GET`, which a plain
8
+ * `<a>` click or redirect can trigger with `SameSite=Lax` cookies attached. Other
9
+ * methods (`HEAD`, `OPTIONS`, `QUERY`, ...) have safe semantics that should not
10
+ * invoke a procedure that can modify data.
11
+ *
12
+ * @see {@link https://orpc.dev/docs/rpc/handler#supported-http-methods | RPC Handler - Supported HTTP Methods}
13
+ */
14
+ export const RPC_DEFAULT_ALLOW_METHODS = [
15
+ 'POST',
16
+ 'PUT',
17
+ 'PATCH',
18
+ 'DELETE',
19
+ ];
20
+ // `%` or a char `encodeURIComponent` encodes, meaning normalization may change the pathname
21
+ const NORMALIZABLE_PATHNAME_REGEX = /[^\w\-.!~*'()/]/;
22
+ export class RPCMatcher {
23
+ filter;
24
+ allowMethodsSet;
25
+ allowMethodsFn;
26
+ rootRouter;
27
+ tree = new Map();
28
+ pendingLazyRouters = new Map();
29
+ /** segment count of the deepest pending key, never lowered so it stays an upper bound */
30
+ maxPendingLazyRouterDepth = 0;
31
+ constructor(router, options = {}) {
32
+ this.filter = options.filter ?? true;
33
+ const allowMethods = options.allowMethods ?? RPC_DEFAULT_ALLOW_METHODS;
34
+ if (typeof allowMethods !== 'function') {
35
+ this.allowMethodsSet = new Set(allowMethods);
36
+ }
37
+ else {
38
+ this.allowMethodsFn = allowMethods;
39
+ }
40
+ this.rootRouter = router;
41
+ this.index(router);
42
+ }
43
+ index(router, path = []) {
44
+ const lazyResults = walkProcedureContractsSync(router, (procedure, procedurePath) => {
45
+ if (!value(this.filter, procedure, procedurePath)) {
46
+ return;
47
+ }
48
+ this.tree.set(pathToHttpPath(procedurePath), {
49
+ path: procedurePath,
50
+ contract: procedure,
51
+ // contract-first entries have no implementation yet, resolveProcedure fills it in on demand
52
+ procedure: procedure instanceof Procedure ? procedure : undefined,
53
+ });
54
+ }, path);
55
+ for (const result of lazyResults) {
56
+ this.pendingLazyRouters.set(pathToHttpPath(result.path), result);
57
+ this.maxPendingLazyRouterDepth = Math.max(this.maxPendingLazyRouterDepth, result.path.length);
58
+ }
59
+ }
60
+ async match(method, pathname, prefix) {
61
+ if (this.allowMethodsSet && !this.allowMethodsSet.has(method)) {
62
+ return undefined;
63
+ }
64
+ if (prefix) {
65
+ if (!pathname.startsWith(prefix)) {
66
+ return undefined;
67
+ }
68
+ const charAfterPrefix = pathname[prefix.length];
69
+ if (charAfterPrefix === '/') {
70
+ pathname = pathname.slice(prefix.length);
71
+ }
72
+ else if (charAfterPrefix === undefined) {
73
+ pathname = '/';
74
+ }
75
+ else if (prefix[prefix.length - 1] === '/') {
76
+ pathname = pathname.slice(prefix.length - 1);
77
+ }
78
+ else {
79
+ return undefined;
80
+ }
81
+ }
82
+ if (pathname.length > 1 && pathname.endsWith('/')) {
83
+ pathname = pathname.slice(0, -1);
84
+ }
85
+ // most requests `await undefined` so conditionally await it to save a microtask turn
86
+ const loading = this.resolvePendingLazyRouters(pathname);
87
+ if (loading !== undefined) {
88
+ await loading;
89
+ }
90
+ let entry = this.tree.get(pathname);
91
+ if (entry === undefined && NORMALIZABLE_PATHNAME_REGEX.test(pathname)) {
92
+ // Retry with a normalized path: users may percent-encode characters that we store
93
+ // unencoded ("a%62c" vs "abc"), or leave raw characters that we store encoded
94
+ // ("a^b" vs "a%5Eb"), so normalization handles both without duplicate entries.
95
+ const normalizedPathname = normalizeHttpPath(pathname);
96
+ // most requests `await undefined` so conditionally await it to save a microtask turn
97
+ const normalizedLoading = this.resolvePendingLazyRouters(normalizedPathname);
98
+ if (normalizedLoading !== undefined) {
99
+ await normalizedLoading;
100
+ }
101
+ entry = this.tree.get(normalizedPathname);
102
+ }
103
+ if (entry === undefined) {
104
+ return undefined;
105
+ }
106
+ const procedure = entry.procedure ?? (await this.resolveProcedure(entry));
107
+ if (this.allowMethodsFn && !this.allowMethodsFn(method, procedure, entry.path)) {
108
+ return undefined;
109
+ }
110
+ return {
111
+ path: entry.path,
112
+ procedure,
113
+ };
114
+ }
115
+ resolvePendingLazyRouters(pathname) {
116
+ if (this.pendingLazyRouters.size === 0) {
117
+ return;
118
+ }
119
+ let slashIndex = 0;
120
+ // a pending key has as many segments as its path, so deeper prefixes can never match,
121
+ // and scanning them would cost quadratic time on slash-heavy pathnames
122
+ for (let depth = 1; slashIndex !== -1 && depth <= this.maxPendingLazyRouterDepth; depth++) {
123
+ const nextSlashIndex = pathname.indexOf('/', slashIndex + 1);
124
+ const httpPathPrefix = nextSlashIndex === -1 ? pathname : pathname.slice(0, nextSlashIndex);
125
+ const pending = this.pendingLazyRouters.get(httpPathPrefix);
126
+ if (pending !== undefined) {
127
+ return this.loadPendingLazyRouter(httpPathPrefix, pending).then(() => this.resolvePendingLazyRouters(pathname));
128
+ }
129
+ slashIndex = nextSlashIndex;
130
+ }
131
+ }
132
+ loadPendingLazyRouter(httpPathPrefix, pending) {
133
+ if (pending.loading === undefined) {
134
+ pending.loading = this.indexPendingLazyRouter(httpPathPrefix, pending).catch((error) => {
135
+ pending.loading = undefined;
136
+ throw error;
137
+ });
138
+ }
139
+ return pending.loading;
140
+ }
141
+ async indexPendingLazyRouter(httpPathPrefix, pending) {
142
+ const { default: router } = await unlazy(pending.router);
143
+ this.index(router, pending.path);
144
+ // removed only once indexed, so a concurrent match never observes this router as
145
+ // neither pending nor indexed
146
+ this.pendingLazyRouters.delete(httpPathPrefix);
147
+ }
148
+ async resolveProcedure(entry) {
149
+ entry.procedure = await resolveContractProcedure(this.rootRouter, entry.contract, entry.path);
150
+ return entry.procedure;
151
+ }
152
+ }
@@ -0,0 +1,10 @@
1
+ import type { Promisable, Value } from '@orpc/shared';
2
+ import type { StandardLazyRequest } from '@standard-server/core';
3
+ import type { Context } from '../../context.ts';
4
+ import type { StandardHandlerHandleOptions } from './handler.ts';
5
+ export type FriendlyStandardHandlerHandleOptions<T extends Context> = Omit<StandardHandlerHandleOptions<T>, 'context'> & (object extends T ? {
6
+ context?: Value<Promisable<T>, [request: StandardLazyRequest]> | undefined;
7
+ } : {
8
+ context: Value<Promisable<T>, [request: StandardLazyRequest]>;
9
+ });
10
+ export declare function resolveFriendlyStandardHandlerHandleOptions<T extends Context>(options: FriendlyStandardHandlerHandleOptions<T>): StandardHandlerHandleOptions<T>;
@@ -0,0 +1,6 @@
1
+ export function resolveFriendlyStandardHandlerHandleOptions(options) {
2
+ return {
3
+ ...options,
4
+ context: options.context ?? {}, // Context only optional if all fields are optional
5
+ };
6
+ }
@@ -0,0 +1 @@
1
+ export * from './utils.ts';
@@ -0,0 +1 @@
1
+ export * from './utils.js';
@@ -1,4 +1,4 @@
1
- import type { StandardLazyRequest, StandardResponse } from "@standard-server/core";
2
- import type { Context } from "../../context.mjs";
3
- import type { FriendlyStandardHandlerHandleOptions, StandardHandler } from "../standard/index.mjs";
1
+ import type { StandardLazyRequest, StandardResponse } from '@standard-server/core';
2
+ import type { Context } from '../../context.ts';
3
+ import type { FriendlyStandardHandlerHandleOptions, StandardHandler } from '../standard/index.ts';
4
4
  export declare function createStandardPeerRequestHandler<T extends Context>(handler: StandardHandler<T>, options: FriendlyStandardHandlerHandleOptions<T>): (request: StandardLazyRequest) => Promise<StandardResponse>;
@@ -0,0 +1,7 @@
1
+ import { resolveFriendlyStandardHandlerHandleOptions } from '../standard/index.js';
2
+ export function createStandardPeerRequestHandler(handler, options) {
3
+ return async (request) => {
4
+ const { response } = await handler.handle(request, resolveFriendlyStandardHandlerHandleOptions(options));
5
+ return response ?? { status: 404, headers: {}, body: 'No procedure matched' };
6
+ };
7
+ }
@@ -0,0 +1,59 @@
1
+ import type { Arrayable, MaybeOptionalOptions } from '@orpc/shared';
2
+ import type { DecodePeerMessageOptions, EncodePeerMessageOptions } from '@standard-server/peer';
3
+ import type { Context } from '../../context.ts';
4
+ import type { FriendlyStandardHandlerHandleOptions, StandardHandler } from '../standard/index.ts';
5
+ /**
6
+ * Supports standard WebSocket instances, Bun ServerWebSocket, "ws" ServerWebSocket,
7
+ * Cloudflare WebSocket Hibernation, and similar implementations.
8
+ */
9
+ export type WebSocketLike = {
10
+ send: (data: string | Uint8Array<ArrayBuffer>) => unknown;
11
+ };
12
+ export interface WebSocketHandlerOptions<_T extends Context> {
13
+ /**
14
+ * Options for encoding peer messages. such as `prefix` for distinguishing messages on the same channel..
15
+ */
16
+ encodePeerMessage?: EncodePeerMessageOptions | undefined;
17
+ /**
18
+ * Options for decoding peer messages. such as `prefix` for distinguishing messages on the same channel..
19
+ */
20
+ decodePeerMessage?: DecodePeerMessageOptions | undefined;
21
+ }
22
+ export declare class WebSocketHandler<T extends Context> {
23
+ private readonly handler;
24
+ /**
25
+ * `null` marks a closed socket, so late messages never create a new peer.
26
+ */
27
+ private readonly peers;
28
+ private readonly encodePeerMessageOptions;
29
+ private readonly decodePeerMessageOptions;
30
+ constructor(handler: StandardHandler<T>, options?: NoInfer<WebSocketHandlerOptions<T>>);
31
+ /**
32
+ * Handles a single WebSocket message.
33
+ *
34
+ * Message order matters. Call this immediately after receiving a message,
35
+ * before any other async work, to preserve ordering.
36
+ *
37
+ * To avoid async Blob reads, configure `ws.binaryType` to return binary data
38
+ * directly (for example, `arraybuffer`).
39
+ *
40
+ * @param ws The WebSocket instance. Use the same instance for all messages.
41
+ * @param data The received message. Binary data should already be loaded (not a `Blob`).
42
+ */
43
+ message(ws: WebSocketLike, data: Arrayable<string | ArrayBuffer | Pick<Uint8Array<ArrayBuffer>, 'buffer' | 'byteOffset' | 'byteLength'>>, ...rest: MaybeOptionalOptions<FriendlyStandardHandlerHandleOptions<T>>): Promise<{
44
+ matched: boolean;
45
+ }>;
46
+ /**
47
+ * Cleans up peer state for a closed WebSocket.
48
+ * Messages passed to `.message()` for this WebSocket afterwards are ignored.
49
+ *
50
+ * @param ws The same WebSocket instance passed to `.message()`.
51
+ */
52
+ close(ws: WebSocketLike): Promise<void>;
53
+ /**
54
+ * Attaches message, close, and error event listeners to a WebSocket.
55
+ *
56
+ * Prefer this over calling `.message()` and `.close()` manually.
57
+ */
58
+ upgrade(ws: Pick<WebSocket, 'send' | 'addEventListener' | 'removeEventListener'>, ...rest: MaybeOptionalOptions<FriendlyStandardHandlerHandleOptions<T>>): void;
59
+ }
@@ -0,0 +1,85 @@
1
+ import { loadBytes, resolveMaybeOptionalOptions, sequential, toStringOrBytes } from '@orpc/shared';
2
+ import { decodePeerMessage, encodePeerMessage, isClientPeerSendMessage, ServerPeer, } from '@standard-server/peer';
3
+ import { createStandardPeerRequestHandler } from '../standard-peer/index.js';
4
+ export class WebSocketHandler {
5
+ handler;
6
+ /**
7
+ * `null` marks a closed socket, so late messages never create a new peer.
8
+ */
9
+ peers = new WeakMap();
10
+ encodePeerMessageOptions;
11
+ decodePeerMessageOptions;
12
+ constructor(handler, options = {}) {
13
+ this.handler = handler;
14
+ this.encodePeerMessageOptions = options.encodePeerMessage;
15
+ this.decodePeerMessageOptions = options.decodePeerMessage;
16
+ }
17
+ /**
18
+ * Handles a single WebSocket message.
19
+ *
20
+ * Message order matters. Call this immediately after receiving a message,
21
+ * before any other async work, to preserve ordering.
22
+ *
23
+ * To avoid async Blob reads, configure `ws.binaryType` to return binary data
24
+ * directly (for example, `arraybuffer`).
25
+ *
26
+ * @param ws The WebSocket instance. Use the same instance for all messages.
27
+ * @param data The received message. Binary data should already be loaded (not a `Blob`).
28
+ */
29
+ async message(ws, data, ...rest) {
30
+ /**
31
+ * Message order is important: loading -> decode -> .message.
32
+ * This flow must stay synchronous, or we need to use `sequential` helper
33
+ */
34
+ const encoded = toStringOrBytes(data);
35
+ const result = decodePeerMessage(encoded, this.decodePeerMessageOptions);
36
+ let peer = this.peers.get(ws);
37
+ // Closed (e.g. a Blob finished loading after close): a new peer here would leak and never be aborted.
38
+ if (peer === null) {
39
+ return result;
40
+ }
41
+ if (!peer) {
42
+ this.peers.set(ws, (peer = new ServerPeer(async (message) => {
43
+ const encoded = await encodePeerMessage(message, this.encodePeerMessageOptions);
44
+ await ws.send(encoded);
45
+ })));
46
+ }
47
+ if (result.matched && isClientPeerSendMessage(result.message)) {
48
+ await peer.message(result.message, createStandardPeerRequestHandler(this.handler, resolveMaybeOptionalOptions(rest)));
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Cleans up peer state for a closed WebSocket.
54
+ * Messages passed to `.message()` for this WebSocket afterwards are ignored.
55
+ *
56
+ * @param ws The same WebSocket instance passed to `.message()`.
57
+ */
58
+ async close(ws) {
59
+ const peer = this.peers.get(ws);
60
+ this.peers.set(ws, null);
61
+ await peer?.close();
62
+ }
63
+ /**
64
+ * Attaches message, close, and error event listeners to a WebSocket.
65
+ *
66
+ * Prefer this over calling `.message()` and `.close()` manually.
67
+ */
68
+ upgrade(ws, ...rest) {
69
+ /**
70
+ * Message order is important: loading -> decode -> .message.
71
+ * This flow must stay synchronous, or we need to use `sequential` helper
72
+ */
73
+ ws.addEventListener('message', sequential(async (event) => {
74
+ // For better compatibility avoid control or depend on websocket.binaryType
75
+ const data = event.data instanceof Blob ? await loadBytes(event.data) : event.data;
76
+ // Not awaited: `this.message` runs business logic that may be slow,
77
+ // and awaiting it would block decoding of subsequent messages.
78
+ void this.message(ws, data, ...rest);
79
+ }));
80
+ ws.addEventListener('close', () => this.close(ws));
81
+ // EventEmitter-based implementations like `ws` throw an unhandled `error` event,
82
+ // so a single malformed frame would crash the process. `close` always follows and handles cleanup.
83
+ ws.addEventListener('error', () => { });
84
+ }
85
+ }
@@ -0,0 +1,2 @@
1
+ export * from './handler.ts';
2
+ export * from './rpc-handler.ts';
@@ -0,0 +1,2 @@
1
+ export * from './handler.js';
2
+ export * from './rpc-handler.js';
@@ -0,0 +1,16 @@
1
+ import type { Context } from '../../context.ts';
2
+ import type { Router } from '../../router.ts';
3
+ import type { RPCHandlerCodecOptions, StandardHandlerOptions } from '../standard/index.ts';
4
+ import type { WebSocketHandlerOptions } from './handler.ts';
5
+ import { WebSocketHandler } from './handler.ts';
6
+ export interface RPCHandlerOptions<T extends Context> extends StandardHandlerOptions<T>, RPCHandlerCodecOptions<T>, WebSocketHandlerOptions<T> {
7
+ }
8
+ /**
9
+ * Serves an oRPC router over the RPC protocol on a standard WebSocket
10
+ * connection (Deno, Bun, Cloudflare Durable Objects, and more).
11
+ *
12
+ * @see {@link https://orpc.dev/docs/adapters/websocket | WebSocket Adapters}
13
+ */
14
+ export declare class RPCHandler<T extends Context> extends WebSocketHandler<T> {
15
+ constructor(router: Router<T>, options?: NoInfer<RPCHandlerOptions<T>>);
16
+ }
@@ -0,0 +1,15 @@
1
+ import { RPCHandlerCodec, StandardHandler } from '../standard/index.js';
2
+ import { WebSocketHandler } from './handler.js';
3
+ /**
4
+ * Serves an oRPC router over the RPC protocol on a standard WebSocket
5
+ * connection (Deno, Bun, Cloudflare Durable Objects, and more).
6
+ *
7
+ * @see {@link https://orpc.dev/docs/adapters/websocket | WebSocket Adapters}
8
+ */
9
+ export class RPCHandler extends WebSocketHandler {
10
+ constructor(router, options = {}) {
11
+ const codec = new RPCHandlerCodec(router, options);
12
+ const handler = new StandardHandler(codec, options);
13
+ super(handler, options);
14
+ }
15
+ }
@@ -0,0 +1,226 @@
1
+ import type { AnySchema, ErrorMap, InferSchemaInput, InferSchemaOutput, InitialInputSchema, InitialOutputSchema, MergedErrorMap, MergedSchema, MetaPlugin, ORPCErrorConstructorMap, Schema } from '@orpc/contract';
2
+ import type { IntersectPick } from '@orpc/shared';
3
+ import type { BuilderDefinition } from './builder.ts';
4
+ import type { Context, MergedContext, MergedInitialContext } from './context.ts';
5
+ import type { Lazy } from './lazy.ts';
6
+ import type { DecoratedMiddleware } from './middleware-decorated.ts';
7
+ import type { Middleware } from './middleware.ts';
8
+ import type { DecoratedProcedure } from './procedure-decorated.ts';
9
+ import type { ProcedureHandler } from './procedure.ts';
10
+ import type { AugmentedRouterWithMiddlewares } from './router-utils.ts';
11
+ import type { Router } from './router.ts';
12
+ /**
13
+ * The builder variant returned after `.use` is called.
14
+ * `.$context` and `.$config` are no longer available once middleware is applied.
15
+ *
16
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
17
+ */
18
+ export interface BuilderWithMiddlewares<TInitialContext extends Context, TInjectedContext extends Context, TErrorMap extends ErrorMap> {
19
+ '~orpc': BuilderDefinition<InitialInputSchema, InitialOutputSchema, TErrorMap>;
20
+ /**
21
+ * Applies metadata plugins to procedures built from this builder.
22
+ *
23
+ * @see {@link https://orpc.dev/docs/metadata | Metadata}
24
+ */
25
+ 'meta'(...plugins: MetaPlugin<InitialInputSchema, InitialOutputSchema, TErrorMap>[]): BuilderWithMiddlewares<TInitialContext, TInjectedContext, TErrorMap>;
26
+ /**
27
+ * Defines typesafe errors that procedures built from this builder can throw
28
+ * via the `errors` utility in handlers and middleware.
29
+ *
30
+ * @see {@link https://orpc.dev/docs/error-handling#typesafe-errors | Error Handling - Typesafe Errors}
31
+ */
32
+ 'errors'<T extends ErrorMap>(errors: T): BuilderWithMiddlewares<TInitialContext, TInjectedContext, MergedErrorMap<TErrorMap, T>>;
33
+ /**
34
+ * Applies a middleware that runs before the handler of every procedure
35
+ * built from this builder.
36
+ *
37
+ * @see {@link https://orpc.dev/docs/middleware | Middleware}
38
+ */
39
+ 'use'<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $ErrorMap extends ErrorMap = TErrorMap>(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, InferSchemaOutput<InitialInputSchema>, InferSchemaInput<InitialOutputSchema>, $ErrorMap>): BuilderWithMiddlewares<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, MergedErrorMap<$ErrorMap, TErrorMap>>;
40
+ /**
41
+ * Creates a standalone middleware that can be composed and applied to any
42
+ * compatible builder or procedure with `.use`.
43
+ *
44
+ * @see {@link https://orpc.dev/docs/middleware | Middleware}
45
+ */
46
+ 'middleware'<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $Input, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $Output = any>(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, $Input, $Output, TErrorMap>): DecoratedMiddleware<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, $Input, $Output, TErrorMap>;
47
+ /**
48
+ * Defines the input schema used to validate and type the procedure input.
49
+ *
50
+ * @see {@link https://orpc.dev/docs/procedure#inputoutput-validation | Procedure - Input/Output Validation}
51
+ */
52
+ 'input'<T extends AnySchema>(schema: T): BuilderWithInput<TInitialContext, TInjectedContext, T, TErrorMap>;
53
+ /**
54
+ * Defines the output schema used to validate and type the procedure output.
55
+ *
56
+ * @see {@link https://orpc.dev/docs/procedure#inputoutput-validation | Procedure - Input/Output Validation}
57
+ */
58
+ 'output'<T extends AnySchema>(schema: T): BuilderWithOutput<TInitialContext, TInjectedContext, T, TErrorMap>;
59
+ /**
60
+ * Defines the function that implements the procedure and completes the
61
+ * chain, returning a callable procedure.
62
+ *
63
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
64
+ */
65
+ 'handler'<T>(handler: ProcedureHandler<MergedContext<TInitialContext, TInjectedContext>, InferSchemaOutput<InitialInputSchema>, T, ORPCErrorConstructorMap<TErrorMap>>): DecoratedProcedure<TInitialContext, TInjectedContext, InitialInputSchema, Schema<T>, TErrorMap>;
66
+ /**
67
+ * Applies the builder's middleware, errors, and metadata to every procedure
68
+ * in the given router.
69
+ *
70
+ * @see {@link https://orpc.dev/docs/router#extending-router | Router - Extending Router}
71
+ */
72
+ 'router'<T extends Router<MergedContext<TInitialContext, TInjectedContext>>>(router: T): AugmentedRouterWithMiddlewares<T, TInitialContext, TInjectedContext, TErrorMap>;
73
+ /**
74
+ * Like `.router`, but loads the router lazily on first access, which helps
75
+ * reduce startup time for large applications.
76
+ *
77
+ * @see {@link https://orpc.dev/docs/router#lazy-router | Router - Lazy Router}
78
+ */
79
+ 'lazy'<T extends Router<MergedContext<TInitialContext, TInjectedContext>>>(loader: () => Promise<{
80
+ default: T;
81
+ }>): Lazy<AugmentedRouterWithMiddlewares<T, TInitialContext, TInjectedContext, TErrorMap>>;
82
+ }
83
+ /**
84
+ * The builder variant returned after `.input` is called.
85
+ * Only procedure-level methods remain available once an input schema is defined.
86
+ *
87
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
88
+ */
89
+ export interface BuilderWithInput<TInitialContext extends Context, TInjectedContext extends Context, TInputSchema extends AnySchema, TErrorMap extends ErrorMap> {
90
+ '~orpc': BuilderDefinition<TInputSchema, InitialOutputSchema, TErrorMap>;
91
+ /**
92
+ * Applies metadata plugins to procedures built from this builder.
93
+ *
94
+ * @see {@link https://orpc.dev/docs/metadata | Metadata}
95
+ */
96
+ 'meta'(...plugins: MetaPlugin<TInputSchema, InitialOutputSchema, TErrorMap>[]): BuilderWithInput<TInitialContext, TInjectedContext, TInputSchema, TErrorMap>;
97
+ /**
98
+ * Defines typesafe errors that procedures built from this builder can throw
99
+ * via the `errors` utility in handlers and middleware.
100
+ *
101
+ * @see {@link https://orpc.dev/docs/error-handling#typesafe-errors | Error Handling - Typesafe Errors}
102
+ */
103
+ 'errors'<T extends ErrorMap>(errors: T): BuilderWithInput<TInitialContext, TInjectedContext, TInputSchema, MergedErrorMap<TErrorMap, T>>;
104
+ /**
105
+ * Applies a middleware that runs before the handler and can access the
106
+ * validated input.
107
+ *
108
+ * @see {@link https://orpc.dev/docs/middleware | Middleware}
109
+ */
110
+ 'use'<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $ErrorMap extends ErrorMap = TErrorMap>(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, InferSchemaOutput<TInputSchema>, InferSchemaInput<InitialOutputSchema>, $ErrorMap>): BuilderWithInput<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, TInputSchema, MergedErrorMap<$ErrorMap, TErrorMap>>;
111
+ /**
112
+ * Adds an additional input schema, merged with the previously defined one.
113
+ *
114
+ * @see {@link https://orpc.dev/docs/procedure#multiple-schemas | Procedure - Multiple Schemas}
115
+ */
116
+ 'input'<T extends AnySchema>(schema: T): BuilderWithInput<TInitialContext, TInjectedContext, MergedSchema<T, TInputSchema>, TErrorMap>;
117
+ /**
118
+ * Defines the output schema used to validate and type the procedure output.
119
+ *
120
+ * @see {@link https://orpc.dev/docs/procedure#inputoutput-validation | Procedure - Input/Output Validation}
121
+ */
122
+ 'output'<T extends AnySchema>(schema: T): BuilderWithInputOutput<TInitialContext, TInjectedContext, TInputSchema, T, TErrorMap>;
123
+ /**
124
+ * Defines the function that implements the procedure and completes the
125
+ * chain, returning a callable procedure.
126
+ *
127
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
128
+ */
129
+ 'handler'<T>(handler: ProcedureHandler<MergedContext<TInitialContext, TInjectedContext>, InferSchemaOutput<TInputSchema>, T, ORPCErrorConstructorMap<TErrorMap>>): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, Schema<T>, TErrorMap>;
130
+ }
131
+ /**
132
+ * The builder variant returned after `.output` is called.
133
+ * Only procedure-level methods remain available once an output schema is defined.
134
+ *
135
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
136
+ */
137
+ export interface BuilderWithOutput<TInitialContext extends Context, TInjectedContext extends Context, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> {
138
+ '~orpc': BuilderDefinition<InitialInputSchema, TOutputSchema, TErrorMap>;
139
+ /**
140
+ * Applies metadata plugins to procedures built from this builder.
141
+ *
142
+ * @see {@link https://orpc.dev/docs/metadata | Metadata}
143
+ */
144
+ 'meta'(...plugins: MetaPlugin<InitialInputSchema, TOutputSchema, TErrorMap>[]): BuilderWithOutput<TInitialContext, TInjectedContext, TOutputSchema, TErrorMap>;
145
+ /**
146
+ * Defines typesafe errors that procedures built from this builder can throw
147
+ * via the `errors` utility in handlers and middleware.
148
+ *
149
+ * @see {@link https://orpc.dev/docs/error-handling#typesafe-errors | Error Handling - Typesafe Errors}
150
+ */
151
+ 'errors'<T extends ErrorMap>(errors: T): BuilderWithOutput<TInitialContext, TInjectedContext, TOutputSchema, MergedErrorMap<TErrorMap, T>>;
152
+ /**
153
+ * Applies a middleware that runs before the handler and can access the
154
+ * typed output.
155
+ *
156
+ * @see {@link https://orpc.dev/docs/middleware | Middleware}
157
+ */
158
+ 'use'<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $ErrorMap extends ErrorMap = TErrorMap>(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, InferSchemaOutput<InitialInputSchema>, InferSchemaInput<TOutputSchema>, $ErrorMap>): BuilderWithOutput<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, TOutputSchema, MergedErrorMap<$ErrorMap, TErrorMap>>;
159
+ /**
160
+ * Defines the input schema used to validate and type the procedure input.
161
+ *
162
+ * @see {@link https://orpc.dev/docs/procedure#inputoutput-validation | Procedure - Input/Output Validation}
163
+ */
164
+ 'input'<T extends AnySchema>(schema: T): BuilderWithInputOutput<TInitialContext, TInjectedContext, T, TOutputSchema, TErrorMap>;
165
+ /**
166
+ * Adds an additional output schema, merged with the previously defined one.
167
+ *
168
+ * @see {@link https://orpc.dev/docs/procedure#multiple-schemas | Procedure - Multiple Schemas}
169
+ */
170
+ 'output'<T extends AnySchema>(schema: T): BuilderWithOutput<TInitialContext, TInjectedContext, MergedSchema<T, TOutputSchema>, TErrorMap>;
171
+ /**
172
+ * Defines the function that implements the procedure and completes the
173
+ * chain, returning a callable procedure.
174
+ *
175
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
176
+ */
177
+ 'handler'<T extends InferSchemaInput<TOutputSchema>>(handler: ProcedureHandler<MergedContext<TInitialContext, TInjectedContext>, InferSchemaOutput<InitialInputSchema>, T, ORPCErrorConstructorMap<TErrorMap>>): DecoratedProcedure<TInitialContext, TInjectedContext, InitialInputSchema, TOutputSchema, TErrorMap>;
178
+ }
179
+ /**
180
+ * The builder variant returned after both `.input` and `.output` are called.
181
+ * Only procedure-level methods remain available.
182
+ *
183
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
184
+ */
185
+ export interface BuilderWithInputOutput<TInitialContext extends Context, TInjectedContext extends Context, TInputSchema extends AnySchema, TOutputSchema extends AnySchema, TErrorMap extends ErrorMap> {
186
+ '~orpc': BuilderDefinition<TInputSchema, TOutputSchema, TErrorMap>;
187
+ /**
188
+ * Applies metadata plugins to procedures built from this builder.
189
+ *
190
+ * @see {@link https://orpc.dev/docs/metadata | Metadata}
191
+ */
192
+ 'meta'(...plugins: MetaPlugin<TInputSchema, TOutputSchema, TErrorMap>[]): BuilderWithInputOutput<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
193
+ /**
194
+ * Defines typesafe errors that procedures built from this builder can throw
195
+ * via the `errors` utility in handlers and middleware.
196
+ *
197
+ * @see {@link https://orpc.dev/docs/error-handling#typesafe-errors | Error Handling - Typesafe Errors}
198
+ */
199
+ 'errors'<T extends ErrorMap>(errors: T): BuilderWithInputOutput<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, MergedErrorMap<TErrorMap, T>>;
200
+ /**
201
+ * Applies a middleware that runs before the handler and can access the
202
+ * validated input and typed output.
203
+ *
204
+ * @see {@link https://orpc.dev/docs/middleware | Middleware}
205
+ */
206
+ 'use'<$OutContext extends IntersectPick<MergedContext<TInitialContext, TInjectedContext>, $OutContext>, $InContext extends Context = MergedContext<TInitialContext, TInjectedContext>, $ErrorMap extends ErrorMap = TErrorMap>(middleware: Middleware<$InContext | MergedContext<TInitialContext, TInjectedContext>, $OutContext, InferSchemaOutput<TInputSchema>, InferSchemaInput<TOutputSchema>, $ErrorMap>): BuilderWithInputOutput<MergedInitialContext<TInitialContext, TInjectedContext, $InContext>, MergedContext<TInjectedContext, $OutContext>, TInputSchema, TOutputSchema, MergedErrorMap<$ErrorMap, TErrorMap>>;
207
+ /**
208
+ * Adds an additional input schema, merged with the previously defined one.
209
+ *
210
+ * @see {@link https://orpc.dev/docs/procedure#multiple-schemas | Procedure - Multiple Schemas}
211
+ */
212
+ 'input'<T extends AnySchema>(schema: T): BuilderWithInputOutput<TInitialContext, TInjectedContext, MergedSchema<T, TInputSchema>, TOutputSchema, TErrorMap>;
213
+ /**
214
+ * Adds an additional output schema, merged with the previously defined one.
215
+ *
216
+ * @see {@link https://orpc.dev/docs/procedure#multiple-schemas | Procedure - Multiple Schemas}
217
+ */
218
+ 'output'<T extends AnySchema>(schema: T): BuilderWithInputOutput<TInitialContext, TInjectedContext, TInputSchema, MergedSchema<T, TOutputSchema>, TErrorMap>;
219
+ /**
220
+ * Defines the function that implements the procedure and completes the
221
+ * chain, returning a callable procedure.
222
+ *
223
+ * @see {@link https://orpc.dev/docs/procedure | Procedure}
224
+ */
225
+ 'handler'<T extends InferSchemaInput<TOutputSchema>>(handler: ProcedureHandler<MergedContext<TInitialContext, TInjectedContext>, InferSchemaOutput<TInputSchema>, T, ORPCErrorConstructorMap<TErrorMap>>): DecoratedProcedure<TInitialContext, TInjectedContext, TInputSchema, TOutputSchema, TErrorMap>;
226
+ }