@orpc/server 0.15.0 → 0.17.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,182 @@
1
+ // src/utils.ts
2
+ function mergeContext(a, b) {
3
+ if (!a)
4
+ return b;
5
+ if (!b)
6
+ return a;
7
+ return {
8
+ ...a,
9
+ ...b
10
+ };
11
+ }
12
+
13
+ // src/procedure.ts
14
+ import { isContractProcedure } from "@orpc/contract";
15
+ var Procedure = class {
16
+ "~type" = "Procedure";
17
+ "~orpc";
18
+ constructor(def) {
19
+ this["~orpc"] = def;
20
+ }
21
+ };
22
+ function isProcedure(item) {
23
+ if (item instanceof Procedure) {
24
+ return true;
25
+ }
26
+ return (typeof item === "object" || typeof item === "function") && item !== null && "~type" in item && item["~type"] === "Procedure" && "~orpc" in item && typeof item["~orpc"] === "object" && item["~orpc"] !== null && "contract" in item["~orpc"] && isContractProcedure(item["~orpc"].contract) && "func" in item["~orpc"] && typeof item["~orpc"].func === "function";
27
+ }
28
+
29
+ // src/lazy.ts
30
+ var LAZY_LOADER_SYMBOL = Symbol("ORPC_LAZY_LOADER");
31
+ function lazy(loader) {
32
+ return {
33
+ [LAZY_LOADER_SYMBOL]: loader
34
+ };
35
+ }
36
+ function isLazy(item) {
37
+ return (typeof item === "object" || typeof item === "function") && item !== null && LAZY_LOADER_SYMBOL in item && typeof item[LAZY_LOADER_SYMBOL] === "function";
38
+ }
39
+ function unlazy(lazied) {
40
+ return isLazy(lazied) ? lazied[LAZY_LOADER_SYMBOL]() : Promise.resolve({ default: lazied });
41
+ }
42
+ function flatLazy(lazied) {
43
+ const flattenLoader = async () => {
44
+ let current = await unlazy(lazied);
45
+ while (true) {
46
+ if (!isLazy(current.default)) {
47
+ break;
48
+ }
49
+ current = await unlazy(current.default);
50
+ }
51
+ return current;
52
+ };
53
+ return lazy(flattenLoader);
54
+ }
55
+
56
+ // src/procedure-client.ts
57
+ import { executeWithHooks, value } from "@orpc/shared";
58
+ import { ORPCError } from "@orpc/shared/error";
59
+ function createProcedureClient(options) {
60
+ return async (...[input, callerOptions]) => {
61
+ const path = options.path ?? [];
62
+ const { default: procedure } = await unlazy(options.procedure);
63
+ const context = await value(options.context);
64
+ const meta = {
65
+ path,
66
+ procedure,
67
+ signal: callerOptions?.signal
68
+ };
69
+ const executeWithValidation = async () => {
70
+ const validInput = await validateInput(procedure, input);
71
+ const output = await executeMiddlewareChain(
72
+ procedure,
73
+ validInput,
74
+ context,
75
+ meta
76
+ );
77
+ return validateOutput(procedure, output);
78
+ };
79
+ return executeWithHooks({
80
+ hooks: options,
81
+ input,
82
+ context,
83
+ meta,
84
+ execute: executeWithValidation
85
+ });
86
+ };
87
+ }
88
+ async function validateInput(procedure, input) {
89
+ const schema = procedure["~orpc"].contract["~orpc"].InputSchema;
90
+ if (!schema)
91
+ return input;
92
+ const result = await schema["~standard"].validate(input);
93
+ if (result.issues) {
94
+ throw new ORPCError({
95
+ message: "Input validation failed",
96
+ code: "BAD_REQUEST",
97
+ issues: result.issues
98
+ });
99
+ }
100
+ return result.value;
101
+ }
102
+ async function validateOutput(procedure, output) {
103
+ const schema = procedure["~orpc"].contract["~orpc"].OutputSchema;
104
+ if (!schema)
105
+ return output;
106
+ const result = await schema["~standard"].validate(output);
107
+ if (result.issues) {
108
+ throw new ORPCError({
109
+ message: "Output validation failed",
110
+ code: "INTERNAL_SERVER_ERROR",
111
+ issues: result.issues
112
+ });
113
+ }
114
+ return result.value;
115
+ }
116
+ async function executeMiddlewareChain(procedure, input, context, meta) {
117
+ const middlewares = procedure["~orpc"].middlewares ?? [];
118
+ let currentMidIndex = 0;
119
+ let currentContext = context;
120
+ const next = async (nextOptions) => {
121
+ const mid = middlewares[currentMidIndex];
122
+ currentMidIndex += 1;
123
+ currentContext = mergeContext(currentContext, nextOptions.context);
124
+ if (mid) {
125
+ return await mid(input, currentContext, {
126
+ ...meta,
127
+ next,
128
+ output: (output) => ({ output, context: void 0 })
129
+ });
130
+ }
131
+ const result = {
132
+ output: await procedure["~orpc"].func(input, currentContext, meta),
133
+ context: currentContext
134
+ };
135
+ return result;
136
+ };
137
+ return (await next({})).output;
138
+ }
139
+
140
+ // src/router.ts
141
+ function getRouterChild(router, ...path) {
142
+ let current = router;
143
+ for (let i = 0; i < path.length; i++) {
144
+ const segment = path[i];
145
+ if (!current) {
146
+ return void 0;
147
+ }
148
+ if (isProcedure(current)) {
149
+ return void 0;
150
+ }
151
+ if (!isLazy(current)) {
152
+ current = current[segment];
153
+ continue;
154
+ }
155
+ const lazied = current;
156
+ const rest = path.slice(i);
157
+ const newLazy = lazy(async () => {
158
+ const unwrapped = await unlazy(lazied);
159
+ if (!unwrapped.default) {
160
+ return unwrapped;
161
+ }
162
+ const next = getRouterChild(unwrapped.default, ...rest);
163
+ return { default: next };
164
+ });
165
+ return flatLazy(newLazy);
166
+ }
167
+ return current;
168
+ }
169
+
170
+ export {
171
+ mergeContext,
172
+ Procedure,
173
+ isProcedure,
174
+ LAZY_LOADER_SYMBOL,
175
+ lazy,
176
+ isLazy,
177
+ unlazy,
178
+ flatLazy,
179
+ createProcedureClient,
180
+ getRouterChild
181
+ };
182
+ //# sourceMappingURL=chunk-FN62GL22.js.map
package/dist/fetch.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import {
2
- createProcedureCaller,
3
- isLazy,
4
- isProcedure
5
- } from "./chunk-3JMSDC5L.js";
2
+ createProcedureClient,
3
+ getRouterChild,
4
+ isProcedure,
5
+ unlazy
6
+ } from "./chunk-FN62GL22.js";
6
7
 
7
- // src/fetch/handle.ts
8
+ // src/fetch/handle-request.ts
8
9
  import { ORPCError } from "@orpc/shared/error";
9
10
  async function handleFetchRequest(options) {
10
11
  for (const handler of options.handlers) {
@@ -22,28 +23,27 @@ async function handleFetchRequest(options) {
22
23
  });
23
24
  }
24
25
 
25
- // src/fetch/handler.ts
26
- import { ORPC_HEADER, ORPC_HEADER_VALUE } from "@orpc/contract";
27
- import { executeWithHooks, trim, value } from "@orpc/shared";
26
+ // src/fetch/orpc-handler.ts
27
+ import { executeWithHooks, ORPC_PROTOCOL_HEADER, ORPC_PROTOCOL_VALUE, trim, value } from "@orpc/shared";
28
28
  import { ORPCError as ORPCError2 } from "@orpc/shared/error";
29
29
  import { ORPCDeserializer, ORPCSerializer } from "@orpc/transformer";
30
30
  var serializer = new ORPCSerializer();
31
31
  var deserializer = new ORPCDeserializer();
32
32
  function createORPCHandler() {
33
33
  return async (options) => {
34
- if (options.request.headers.get(ORPC_HEADER) !== ORPC_HEADER_VALUE) {
34
+ if (!options.request.headers.get(ORPC_PROTOCOL_HEADER)?.includes(ORPC_PROTOCOL_VALUE)) {
35
35
  return void 0;
36
36
  }
37
37
  const context = await value(options.context);
38
38
  const handler = async () => {
39
39
  const url = new URL(options.request.url);
40
40
  const pathname = `/${trim(url.pathname.replace(options.prefix ?? "", ""), "/")}`;
41
- const match = resolveORPCRouter(options.router, pathname);
41
+ const match = await resolveRouterMatch(options.router, pathname);
42
42
  if (!match) {
43
43
  throw new ORPCError2({ code: "NOT_FOUND", message: "Not found" });
44
44
  }
45
- const input = await deserializeRequest(options.request);
46
- const caller = createProcedureCaller({
45
+ const input = await parseRequestInput(options.request);
46
+ const caller = createProcedureClient({
47
47
  context,
48
48
  procedure: match.procedure,
49
49
  path: match.path
@@ -65,46 +65,46 @@ function createORPCHandler() {
65
65
  signal: options.signal
66
66
  }
67
67
  });
68
- } catch (e) {
69
- const error = e instanceof ORPCError2 ? e : new ORPCError2({
70
- code: "INTERNAL_SERVER_ERROR",
71
- message: "Internal server error",
72
- cause: e
73
- });
74
- const { body, headers } = serializer.serialize(error.toJSON());
75
- return new Response(body, {
76
- status: error.status,
77
- headers
78
- });
68
+ } catch (error) {
69
+ return handleErrorResponse(error);
79
70
  }
80
71
  };
81
72
  }
82
- function resolveORPCRouter(router, pathname) {
83
- const path = trim(pathname, "/").split("/").map(decodeURIComponent);
84
- let current = router;
85
- for (const segment of path) {
86
- if (typeof current !== "object" && typeof current !== "function" || !current) {
87
- current = void 0;
88
- break;
89
- }
90
- current = current[segment];
73
+ async function resolveRouterMatch(router, pathname) {
74
+ const pathSegments = trim(pathname, "/").split("/").map(decodeURIComponent);
75
+ const match = getRouterChild(router, ...pathSegments);
76
+ const { default: maybeProcedure } = await unlazy(match);
77
+ if (!isProcedure(maybeProcedure)) {
78
+ return void 0;
91
79
  }
92
- return isProcedure(current) || isLazy(current) ? {
93
- procedure: current,
94
- path
95
- } : void 0;
80
+ return {
81
+ procedure: maybeProcedure,
82
+ path: pathSegments
83
+ };
96
84
  }
97
- async function deserializeRequest(request) {
85
+ async function parseRequestInput(request) {
98
86
  try {
99
87
  return await deserializer.deserialize(request);
100
- } catch (e) {
88
+ } catch (error) {
101
89
  throw new ORPCError2({
102
90
  code: "BAD_REQUEST",
103
91
  message: "Cannot parse request. Please check the request body and Content-Type header.",
104
- cause: e
92
+ cause: error
105
93
  });
106
94
  }
107
95
  }
96
+ function handleErrorResponse(error) {
97
+ const orpcError = error instanceof ORPCError2 ? error : new ORPCError2({
98
+ code: "INTERNAL_SERVER_ERROR",
99
+ message: "Internal server error",
100
+ cause: error
101
+ });
102
+ const { body, headers } = serializer.serialize(orpcError.toJSON());
103
+ return new Response(body, {
104
+ status: orpcError.status,
105
+ headers
106
+ });
107
+ }
108
108
  export {
109
109
  createORPCHandler,
110
110
  handleFetchRequest