@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
@@ -1,373 +0,0 @@
1
- import { ORPCError } from "@orpc/client";
2
- import { BATCH_HEADER, DEFAULT_BATCH_MAX_SIZE } from "@orpc/client/plugins";
3
- import { isAsyncIteratorObject, promiseWithResolvers, toArray, value } from "@orpc/shared";
4
- import { flattenStandardHeader, parseStandardUrl } from "@standard-server/core";
5
- import { encodePeerMessage, isClientPeerSendMessage, isPeerMessage, ServerPeer } from "@standard-server/peer";
6
-
7
- export const BATCH_CONTENT_TYPE = "application/vnd.orpc.batch";
8
- const textEncoder = /* @__PURE__ */ new TextEncoder();
9
- function encodeLengthPrefix(length) {
10
- const prefix = new Uint8Array(4);
11
- new DataView(prefix.buffer).setUint32(0, length, false);
12
- return prefix;
13
- }
14
-
15
- async function encodeFrame(message) {
16
- const encoded = await encodePeerMessage(message);
17
- const bytes = typeof encoded === "string" ? textEncoder.encode(encoded) : encoded;
18
- return [encodeLengthPrefix(bytes.byteLength), bytes];
19
- }
20
-
21
- function isBodyHeader(name) {
22
- return name.startsWith("content-") || name === "standard-server";
23
- }
24
-
25
- function isClientPeerSendMessages(maybe) {
26
- return Array.isArray(maybe) && maybe.every((m) => isPeerMessage(m) && isClientPeerSendMessage(m));
27
- }
28
-
29
- function internalError(err) {
30
- Promise.reject(err);
31
- return {
32
- status: 500,
33
- headers: {},
34
- body: "Internal server error"
35
- };
36
- }
37
-
38
- function firstSubresponseHead(heads) {
39
- return new Promise((resolve) => {
40
- for (const promise of heads) {
41
- void promise.then((head) => head && resolve(head));
42
- }
43
- void Promise.all(heads).then(() => resolve(undefined));
44
- });
45
- }
46
-
47
- function liftCookies(headers, sources) {
48
- const cookies = new Set(sources.flatMap((source) => toArray(source["set-cookie"])));
49
- return cookies.size > 0 ? {
50
- ...headers,
51
- "set-cookie": [...cookies]
52
- } : headers;
53
- }
54
-
55
- function liftSubresponseHeaders(batchHeaders, subresponseHeaders) {
56
- const [first = {}, ...rest] = subresponseHeaders;
57
- const shared = {};
58
- for (const [name, value] of Object.entries(first)) {
59
- if (value === undefined || isBodyHeader(name)) {
60
- continue;
61
- }
62
- const flattened = flattenStandardHeader(value);
63
- if (rest.every((other) => flattenStandardHeader(other[name]) === flattened)) {
64
- shared[name] = value;
65
- }
66
- }
67
- const headers = liftCookies({
68
- ...shared,
69
- ...batchHeaders
70
- }, [batchHeaders, ...subresponseHeaders]);
71
- const varies = new Map();
72
- for (const value of [batchHeaders, ...subresponseHeaders].flatMap((other) => toArray(other.vary))) {
73
- for (const field of value.split(",")) {
74
- const name = field.trim();
75
- const key = name.toLowerCase();
76
- if (name && !varies.has(key)) {
77
- varies.set(key, name);
78
- }
79
- }
80
- }
81
- if (varies.size > 0) {
82
- headers.vary = varies.has("*") ? "*" : [...varies.values()].join(", ");
83
- }
84
- return headers;
85
- }
86
-
87
- export class BatchHandlerPlugin {
88
- name = "~batch";
89
-
90
- after = ["~tracing"];
91
- maxSize;
92
- mapSubrequest;
93
- mapSubresponse;
94
- successStatus;
95
- headers;
96
- keepAliveEnabled;
97
- keepAliveInterval;
98
- constructor(options = {}) {
99
- this.maxSize = options.maxSize ?? DEFAULT_BATCH_MAX_SIZE;
100
- this.mapSubrequest = options.mapSubrequest ?? ((subRequest, { request: batchRequest }) => ({
101
- ...subRequest,
102
- headers: {
103
- ...subRequest.headers,
104
-
105
- ...batchRequest.headers,
106
- [BATCH_HEADER]: undefined
107
- }
108
- }));
109
- this.mapSubresponse = options.mapSubresponse ?? ((subresponse, { headers: batchHeaders }) => {
110
- const headers = {};
111
- for (const [name, value] of Object.entries(subresponse.headers)) {
112
- if (name !== "set-cookie" && flattenStandardHeader(value) !== flattenStandardHeader(batchHeaders[name])) {
113
- headers[name] = value;
114
- }
115
- }
116
- return {
117
- ...subresponse,
118
- headers
119
- };
120
- });
121
- this.successStatus = options.successStatus ?? 207;
122
- this.headers = options.headers ?? {};
123
- this.keepAliveEnabled = options.keepAlive?.enabled ?? true;
124
- this.keepAliveInterval = options.keepAlive?.interval ?? 15e3;
125
- }
126
- init(options) {
127
- const routingInterceptor = async (interceptorOptions) => {
128
- const batchHeader = flattenStandardHeader(interceptorOptions.request.headers[BATCH_HEADER]);
129
- if (batchHeader === undefined) {
130
- return interceptorOptions.next();
131
- }
132
- const streaming = batchHeader === "streaming";
133
- let messages;
134
- try {
135
- if (interceptorOptions.request.method === "GET") {
136
- const [, search] = parseStandardUrl(interceptorOptions.request.url);
137
- const params = new URLSearchParams(search);
138
- const data = params.getAll("data").at(-1);
139
- if (!data) {
140
- return {
141
- matched: true,
142
- response: {
143
- status: 400,
144
- headers: {},
145
- body: "Missing data parameter for batch request"
146
- }
147
- };
148
- }
149
- const mightBeMessages = JSON.parse(data);
150
- if (!isClientPeerSendMessages(mightBeMessages)) {
151
- return {
152
- matched: true,
153
- response: {
154
- status: 400,
155
- headers: {},
156
- body: "Invalid batch request data parameter"
157
- }
158
- };
159
- }
160
- messages = mightBeMessages;
161
- } else {
162
- const mightBeMessages = await interceptorOptions.request.resolveBody();
163
- if (!isClientPeerSendMessages(mightBeMessages)) {
164
- return {
165
- matched: true,
166
- response: {
167
- status: 400,
168
- headers: {},
169
- body: "Invalid batch request body"
170
- }
171
- };
172
- }
173
- messages = mightBeMessages;
174
- }
175
- } catch (error) {
176
- return {
177
- matched: true,
178
- response: {
179
- status: 400,
180
- headers: {},
181
- body: error instanceof ORPCError ? error.message : "Invalid batch request"
182
- }
183
- };
184
- }
185
- const outerMethod = interceptorOptions.request.method;
186
- if ((outerMethod === "GET" || outerMethod === "QUERY") && messages.some((message) => message.kind === "request" && message.json.method !== outerMethod)) {
187
- return {
188
- matched: true,
189
- response: {
190
- status: 400,
191
- headers: {},
192
- body: `${outerMethod} batch requests only accept ${outerMethod} sub-requests`
193
- }
194
- };
195
- }
196
- const maxSize = await value(this.maxSize, interceptorOptions);
197
- if (messages.length > maxSize) {
198
- return {
199
- matched: true,
200
- response: {
201
- status: 413,
202
- headers: {},
203
- body: "Batch request size exceeds the maximum allowed size"
204
- }
205
- };
206
- }
207
- const status = await value(this.successStatus, interceptorOptions);
208
- const headers = await value(this.headers, interceptorOptions);
209
-
210
- const bufferedMessages = [];
211
- let streamController;
212
- let keepAliveTimer;
213
-
214
- const ready = messages.map(() => promiseWithResolvers());
215
- const heads = ready.map(({ promise }) => promise);
216
- const lifting = streaming ? firstSubresponseHead(heads).then((head) => ({
217
- batchHeaders: liftCookies(headers, [headers, head?.headers ?? {}]),
218
- streams: true
219
- })) : Promise.all(heads).then((all) => {
220
- const present = all.filter((head) => head !== undefined);
221
- return {
222
- batchHeaders: liftSubresponseHeaders(headers, present.map((head) => head.headers)),
223
- streams: present.some((head) => head.stream)
224
- };
225
- });
226
- const clearKeepAlive = () => {
227
- if (keepAliveTimer !== undefined) {
228
- clearInterval(keepAliveTimer);
229
- keepAliveTimer = undefined;
230
- }
231
- };
232
- const scheduleKeepAlive = () => {
233
- if (!this.keepAliveEnabled) {
234
- return;
235
- }
236
- clearKeepAlive();
237
- keepAliveTimer = setInterval(() => {
238
- try {
239
-
240
- streamController.enqueue(encodeLengthPrefix(0));
241
- } catch {
242
-
243
- clearKeepAlive();
244
- }
245
- }, this.keepAliveInterval);
246
- };
247
- const enqueueMessage = async (message) => {
248
- for (const chunk of await encodeFrame(message)) {
249
- streamController.enqueue(chunk);
250
- }
251
- scheduleKeepAlive();
252
- };
253
- const peer = new ServerPeer(async (message) => {
254
- if (streamController === undefined) {
255
- bufferedMessages.push(message);
256
- } else {
257
- await enqueueMessage(message);
258
- }
259
- });
260
- const handleIndividualRequest = async (request, markReady) => {
261
- let response;
262
- try {
263
- request = this.mapSubrequest(request, interceptorOptions);
264
- const result = await interceptorOptions.next({
265
- ...interceptorOptions,
266
- request
267
- });
268
- response = result.matched ? result.response : {
269
- status: 404,
270
- headers: {},
271
- body: "No procedure matched"
272
- };
273
- } catch (err) {
274
- response = internalError(err);
275
- }
276
- markReady({
277
- headers: response.headers,
278
- stream: response.body instanceof ReadableStream || isAsyncIteratorObject(response.body)
279
- });
280
- const { batchHeaders } = await lifting;
281
- try {
282
- return this.mapSubresponse(response, {
283
- status,
284
- headers: batchHeaders
285
- }, interceptorOptions);
286
- } catch (err) {
287
- return internalError(err);
288
- }
289
- };
290
- const runSubrequests = async () => {
291
- const promise = Promise.all(messages.map((msg, i) => {
292
- const { resolve } = ready[i];
293
-
294
- return peer.message(msg, (request) => handleIndividualRequest(request, resolve)).finally(() => resolve(undefined));
295
- }));
296
- const signal = interceptorOptions.request.signal;
297
- const closePeer = () => peer.close(signal?.reason);
298
- if (signal?.aborted) {
299
- closePeer();
300
- }
301
- signal?.addEventListener("abort", closePeer);
302
- try {
303
- await promise;
304
- } finally {
305
- signal?.removeEventListener("abort", closePeer);
306
- }
307
- };
308
- const subrequests = runSubrequests();
309
- const { batchHeaders, streams } = await lifting;
310
- const framedHeaders = {
311
- ...batchHeaders,
312
- "content-type": batchHeaders["content-type"] ?? BATCH_CONTENT_TYPE
313
- };
314
- if (!streams) {
315
- await subrequests;
316
- await peer.close();
317
- if (bufferedMessages.some((msg) => msg.binary !== undefined)) {
318
- const chunks = (await Promise.all(bufferedMessages.map(encodeFrame))).flat();
319
- return {
320
- matched: true,
321
- response: {
322
- status,
323
- headers: framedHeaders,
324
- body: new Blob(chunks)
325
- }
326
- };
327
- }
328
- return {
329
- matched: true,
330
- response: {
331
- status,
332
- headers: batchHeaders,
333
- body: bufferedMessages
334
- }
335
- };
336
- }
337
-
338
- const body = new ReadableStream({
339
- start(controller) {
340
- streamController = controller;
341
- scheduleKeepAlive();
342
- },
343
- async cancel(reason) {
344
- clearKeepAlive();
345
- await peer.close(reason);
346
- }
347
- });
348
- const flushed = Promise.all(bufferedMessages.splice(0).map(enqueueMessage));
349
-
350
- Promise.all([flushed, subrequests]).then(async () => {
351
- clearKeepAlive();
352
- streamController.close();
353
- await peer.close();
354
- }).catch(async (error) => {
355
- clearKeepAlive();
356
- streamController.error(error);
357
- await peer.close(error);
358
- });
359
- return {
360
- matched: true,
361
- response: {
362
- status,
363
- headers: framedHeaders,
364
- body
365
- }
366
- };
367
- };
368
- return {
369
- ...options,
370
- routingInterceptors: [routingInterceptor, ...toArray(options.routingInterceptors)]
371
- };
372
- }
373
- }
@@ -1,67 +0,0 @@
1
- import type { Promisable, Value } from "@orpc/shared";
2
- import type { StandardHandlerOptions, StandardHandlerPlugin, StandardHandlerRoutingInterceptorOptions } from "../adapters/standard/index.mjs";
3
- import type { Context } from "../context.mjs";
4
- export interface CORSHandlerPluginOptions<T extends Context> {
5
- /**
6
- * Configures the `Access-Control-Allow-Origin` header.
7
- * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
8
- *
9
- * A function must only return origins it has validated: returning the incoming origin
10
- * unchecked allows every origin.
11
- *
12
- * @default '*'
13
- */
14
- origin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string, options: StandardHandlerRoutingInterceptorOptions<T>]> | undefined;
15
- /**
16
- * Configures the `Timing-Allow-Origin` header.
17
- * Can be a string, an array of allowed origins, or a function (optionally async) that returns the allowed origin(s).
18
- */
19
- timingOrigin?: Value<Promisable<string | readonly string[] | null | undefined>, [origin: string, options: StandardHandlerRoutingInterceptorOptions<T>]> | undefined;
20
- /**
21
- * Configures the `Access-Control-Allow-Methods` header for preflight requests.
22
- *
23
- * @default ['GET', 'HEAD', 'PUT', 'POST', 'DELETE', 'PATCH', 'QUERY']
24
- */
25
- allowMethods?: readonly string[] | undefined;
26
- /**
27
- * Configures the `Access-Control-Allow-Headers` header for preflight requests.
28
- * Falls back to the request's `Access-Control-Request-Headers` if not set.
29
- * When set, it replaces that fallback, so include every non-safelisted header
30
- * clients send, such as `Content-Type`.
31
- */
32
- allowHeaders?: readonly string[] | undefined;
33
- /**
34
- * Configures the `Access-Control-Max-Age` header (in seconds) for preflight requests.
35
- */
36
- maxAge?: number | undefined;
37
- /**
38
- * Configures the `Access-Control-Allow-Credentials` header.
39
- *
40
- * When enabled, `origin` must allow trusted origins only: every allowed origin can send
41
- * authenticated requests as your users and read the responses.
42
- */
43
- credentials?: boolean | undefined;
44
- /**
45
- * Configures the `Access-Control-Expose-Headers` header.
46
- */
47
- exposeHeaders?: readonly string[] | undefined;
48
- }
49
- /**
50
- * Configures the [CORS Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS)
51
- * for your API, including preflight requests.
52
- *
53
- * @see {@link https://orpc.dev/docs/plugins/cors | CORS Handler Plugin}
54
- */
55
- export declare class CORSHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
56
- private readonly options;
57
- name: string;
58
- /**
59
- * - Do not create spans for CORS preflight requests.
60
- * - Run CORS interceptors before batch interceptors so headers are applied to
61
- * the actual response rather than sub-responses.
62
- */
63
- after: string[];
64
- constructor(options?: CORSHandlerPluginOptions<T>);
65
- init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
66
- private resolveOrigin;
67
- }
@@ -1,134 +0,0 @@
1
- import { toArray } from "@orpc/shared";
2
- import { flattenStandardHeader } from "@standard-server/core";
3
-
4
- export class CORSHandlerPlugin {
5
- options;
6
- name = "~cors";
7
-
8
- after = ["~tracing", "~batch"];
9
- constructor(options = {}) {
10
- const defaults = {
11
- origin: "*",
12
- allowMethods: [
13
- "GET",
14
- "HEAD",
15
- "PUT",
16
- "POST",
17
- "DELETE",
18
- "PATCH",
19
- "QUERY"
20
- ]
21
- };
22
- this.options = {
23
- ...defaults,
24
- ...options
25
- };
26
- }
27
- init(options) {
28
- const corsHeadersInterceptor = async (interceptorOptions) => {
29
- const result = await interceptorOptions.next();
30
- if (!result.matched) {
31
- return result;
32
- }
33
- const resHeaders = { ...result.response.headers };
34
- const origin = flattenStandardHeader(interceptorOptions.request.headers.origin);
35
- const allowOrigin = await this.resolveOrigin(this.options.origin, origin, interceptorOptions);
36
- const timingAllowOrigin = await this.resolveOrigin(this.options.timingOrigin, origin, interceptorOptions);
37
- if (allowOrigin.value !== undefined) {
38
- resHeaders["access-control-allow-origin"] = allowOrigin.value;
39
- }
40
- if (timingAllowOrigin.value !== undefined) {
41
- resHeaders["timing-allow-origin"] = timingAllowOrigin.value;
42
- }
43
- if (allowOrigin.varies || timingAllowOrigin.varies) {
44
- const existingVary = flattenStandardHeader(resHeaders.vary);
45
- if (!existingVary?.split(",").some((v) => v.trim().toLowerCase() === "origin")) {
46
- resHeaders.vary = existingVary ? `${existingVary}, Origin` : "Origin";
47
- }
48
- }
49
- if (this.options.credentials) {
50
- resHeaders["access-control-allow-credentials"] = "true";
51
- }
52
- if (this.options.exposeHeaders?.length) {
53
- resHeaders["access-control-expose-headers"] = flattenStandardHeader(this.options.exposeHeaders);
54
- }
55
- return {
56
- ...result,
57
- response: {
58
- ...result.response,
59
- headers: resHeaders
60
- }
61
- };
62
- };
63
- const preflightInterceptor = async (interceptorOptions) => {
64
- if (interceptorOptions.request.method === "OPTIONS") {
65
- const resHeaders = {};
66
- if (this.options.maxAge !== undefined) {
67
- resHeaders["access-control-max-age"] = this.options.maxAge.toString();
68
- }
69
- if (this.options.allowMethods?.length) {
70
- resHeaders["access-control-allow-methods"] = flattenStandardHeader(this.options.allowMethods);
71
- }
72
- const allowHeaders = this.options.allowHeaders ?? interceptorOptions.request.headers["access-control-request-headers"];
73
- if (typeof allowHeaders === "string" || allowHeaders?.length) {
74
- resHeaders["access-control-allow-headers"] = flattenStandardHeader(allowHeaders);
75
- }
76
- return {
77
- matched: true,
78
- response: {
79
- status: 204,
80
- headers: resHeaders,
81
- body: undefined
82
- }
83
- };
84
- }
85
- return interceptorOptions.next();
86
- };
87
- return {
88
- ...options,
89
- routingInterceptors: [
90
- corsHeadersInterceptor,
91
- preflightInterceptor,
92
- ...toArray(options.routingInterceptors)
93
- ]
94
- };
95
- }
96
- async resolveOrigin(option, origin, interceptorOptions) {
97
- if (typeof option === "function") {
98
- if (origin === undefined) {
99
- return {
100
- value: undefined,
101
- varies: true
102
- };
103
- }
104
- const allowed = toArray(await option(origin, interceptorOptions));
105
- if (allowed.includes("*")) {
106
- return {
107
- value: "*",
108
- varies: true
109
- };
110
- }
111
- return {
112
- value: allowed.includes(origin) ? origin : undefined,
113
- varies: true
114
- };
115
- }
116
- const allowed = toArray(await option);
117
- if (allowed.includes("*")) {
118
- return {
119
- value: "*",
120
- varies: false
121
- };
122
- }
123
- if (origin !== undefined && allowed.includes(origin)) {
124
- return {
125
- value: origin,
126
- varies: true
127
- };
128
- }
129
- return {
130
- value: undefined,
131
- varies: allowed.length > 0
132
- };
133
- }
134
- }
@@ -1,23 +0,0 @@
1
- import type { StandardHandlerOptions, StandardHandlerPlugin } from "../adapters/standard/index.mjs";
2
- import type { Context } from "../context.mjs";
3
- /**
4
- * Adds Cross-Site Request Forgery (CSRF) protection that makes the safe `GET` method as
5
- * secure as unsafe ones such as `POST`. It rejects `GET` requests arriving as top-level
6
- * navigations initiated cross-site or from outside the browser, the only context where
7
- * another site can make a browser attach `SameSite=Lax` cookies to a safe-method request.
8
- * Requests matching no procedure stay unmatched, so they can fall through to whatever
9
- * serves the rest of the site.
10
- *
11
- * @remarks
12
- * **Note**: Requests browsers send without `SameSite=Lax` cookies, such as cross-site `fetch`
13
- * and `<img>`, pass through, so procedures stay reachable from other sites. This safeguard
14
- * requires authentication cookies explicitly marked `SameSite=Lax` or `SameSite=Strict`,
15
- * since browsers may attach other cookies to the requests that pass.
16
- *
17
- * @see {@link https://orpc.dev/docs/plugins/get-method-csrf-protection | GET Method CSRF Protection Plugin}
18
- */
19
- export declare class GetMethodCsrfProtectionHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
20
- name: string;
21
- init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
22
- private isAllowed;
23
- }
@@ -1,45 +0,0 @@
1
- import { ORPCError } from "@orpc/client";
2
- import { toArray } from "@orpc/shared";
3
- import { flattenStandardHeader } from "@standard-server/core";
4
-
5
- export class GetMethodCsrfProtectionHandlerPlugin {
6
- name = "~get-method-csrf-protection";
7
- init(options) {
8
-
9
- const interceptor = (interceptorOptions) => {
10
- if (this.isAllowed(interceptorOptions)) {
11
- return interceptorOptions.next();
12
- }
13
- throw new ORPCError("FORBIDDEN", { message: "Request blocked by CSRF protection." });
14
- };
15
- return {
16
- ...options,
17
- interceptors: [interceptor, ...toArray(options.interceptors)]
18
- };
19
- }
20
- isAllowed({ request }) {
21
-
22
-
23
- if (request.method !== "GET") {
24
- return true;
25
- }
26
- const site = flattenStandardHeader(request.headers["sec-fetch-site"])?.toLowerCase();
27
-
28
-
29
-
30
-
31
- if (site === undefined || site === "same-origin" || site === "same-site") {
32
- return true;
33
- }
34
-
35
-
36
-
37
-
38
- const mode = flattenStandardHeader(request.headers["sec-fetch-mode"])?.toLowerCase();
39
- const dest = flattenStandardHeader(request.headers["sec-fetch-dest"])?.toLowerCase();
40
- if (mode === undefined || dest === undefined) {
41
- return false;
42
- }
43
- return mode !== "navigate" || dest !== "document";
44
- }
45
- }
@@ -1,23 +0,0 @@
1
- import type { StandardHandlerOptions, StandardHandlerPlugin } from "../adapters/standard/index.mjs";
2
- import type { Context } from "../context.mjs";
3
- /**
4
- * Answers `HEAD` requests with the headers of the matching `GET` procedure, like Fastify's
5
- * `exposeHeadRoutes`, so clients can check a resource's existence, type, and size without
6
- * downloading it. A procedure routed as `HEAD` itself takes precedence over the `GET` one.
7
- *
8
- * @remarks
9
- * - `HEAD` responses never carry a body: the plugin discards it, cancelling streams and
10
- * event iterators, and keeps the headers it implies, such as `Content-Type`, and
11
- * `Content-Length` when its size is known up front.
12
- * - `GET` procedures still need to be reachable, so with `RPCHandler`, `GET` must be in `allowMethods`.
13
- *
14
- * @see {@link https://orpc.dev/docs/plugins/head-method | HEAD Method Plugin}
15
- */
16
- export declare class HeadMethodHandlerPlugin<T extends Context> implements StandardHandlerPlugin<T> {
17
- name: string;
18
- /**
19
- * Discard the body after response compression, so `HEAD` reports the same `Content-Encoding` as `GET`.
20
- */
21
- after: string[];
22
- init(options: StandardHandlerOptions<T>): StandardHandlerOptions<T>;
23
- }