@orpc/openapi 2.0.0-beta.4 → 2.0.0-beta.41

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 (45) hide show
  1. package/README.md +97 -94
  2. package/dist/adapters/aws-lambda/index.d.mts +26 -0
  3. package/dist/adapters/aws-lambda/index.d.ts +26 -0
  4. package/dist/adapters/aws-lambda/index.mjs +21 -0
  5. package/dist/adapters/fastify/index.d.mts +23 -0
  6. package/dist/adapters/fastify/index.d.ts +23 -0
  7. package/dist/adapters/fastify/index.mjs +21 -0
  8. package/dist/adapters/fetch/index.d.mts +15 -5
  9. package/dist/adapters/fetch/index.d.ts +15 -5
  10. package/dist/adapters/fetch/index.mjs +6 -6
  11. package/dist/adapters/node/index.d.mts +9 -4
  12. package/dist/adapters/node/index.d.ts +9 -4
  13. package/dist/adapters/node/index.mjs +4 -4
  14. package/dist/adapters/standard/index.d.mts +10 -46
  15. package/dist/adapters/standard/index.d.ts +10 -46
  16. package/dist/adapters/standard/index.mjs +6 -6
  17. package/dist/extensions/route.d.mts +5 -7
  18. package/dist/extensions/route.d.ts +5 -7
  19. package/dist/helpers/index.d.mts +9 -1
  20. package/dist/helpers/index.d.ts +9 -1
  21. package/dist/helpers/index.mjs +1 -1
  22. package/dist/index.d.mts +77 -45
  23. package/dist/index.d.ts +77 -45
  24. package/dist/index.mjs +614 -765
  25. package/dist/plugins/index.d.mts +35 -6
  26. package/dist/plugins/index.d.ts +35 -6
  27. package/dist/plugins/index.mjs +15 -10
  28. package/dist/shared/{openapi.B2SK0ZAr.mjs → openapi.8cM6P94D.mjs} +32 -36
  29. package/dist/shared/openapi.B2G-HeFn.mjs +123 -0
  30. package/dist/shared/{openapi.7vgmPxca.d.ts → openapi.BCNfESWr.d.ts} +12 -9
  31. package/dist/shared/{openapi.CX6Ri5dP.d.mts → openapi.BgpM--nz.d.mts} +12 -9
  32. package/dist/shared/{openapi.CTlpLuKN.mjs → openapi.Bi1qxGF9.mjs} +102 -54
  33. package/dist/shared/{openapi.DmAa7YPO.mjs → openapi.Bu_PfTtX.mjs} +140 -61
  34. package/dist/shared/{openapi.C7m7NAmH.d.mts → openapi.C2LayTNZ.d.mts} +16 -5
  35. package/dist/shared/{openapi.C7m7NAmH.d.ts → openapi.C2LayTNZ.d.ts} +16 -5
  36. package/dist/shared/openapi.C6FFC29v.d.mts +31 -0
  37. package/dist/shared/openapi.C6FFC29v.d.ts +31 -0
  38. package/dist/shared/{openapi.BQzzr4-4.d.ts → openapi.Cem81Zhm.d.mts} +41 -12
  39. package/dist/shared/{openapi.BcEtAxQj.d.mts → openapi.Cem81Zhm.d.ts} +41 -12
  40. package/dist/shared/openapi.Cg9h6jpm.d.mts +45 -0
  41. package/dist/shared/openapi.D0yWs-uW.d.ts +45 -0
  42. package/package.json +57 -17
  43. package/dist/shared/openapi.Bt87OzTt.mjs +0 -131
  44. package/dist/shared/openapi.CYgMBSUF.d.mts +0 -18
  45. package/dist/shared/openapi.CYgMBSUF.d.ts +0 -18
@@ -1,8 +1,8 @@
1
1
  import { COMMON_ERROR_STATUS_MAP } from '@orpc/client';
2
2
  import { walkProcedureContractsSync, Procedure, unlazy, getRouter, createContractProcedure, DEFAULT_SUCCESS_STATUS, DEFAULT_ERROR_STATUS } from '@orpc/server';
3
- import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, tryDecodeURIComponent, isPlainObject, stringifyJSON, parseEmptyableJSON, isTypescriptObject, NullProtoObj } from '@orpc/shared';
4
- import { parseStandardUrl, isStandardHeaders } from '@standardserver/core';
5
- import { D as DEFAULT_OPENAPI_METHOD, g as getDynamicPathParams, O as OpenAPISerializer, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.DmAa7YPO.mjs';
3
+ import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, safeDecodeURIComponent, NullProtoObj, isTypescriptObject, isPlainObject, stringifyJSON, getOwn, parseEmptyableJSON } from '@orpc/shared';
4
+ import { parseStandardUrl } from '@standard-server/core';
5
+ import { D as DEFAULT_OPENAPI_METHOD, g as getDynamicPathParams, O as OpenAPISerializer, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, i as isBodylessMethod, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.Bu_PfTtX.mjs';
6
6
  import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
7
7
  import { createRouter, addRoute, findRoute, routeToRegExp } from 'rou3';
8
8
 
@@ -10,7 +10,7 @@ class OpenAPIMatcher {
10
10
  filter;
11
11
  rootRouter;
12
12
  tree = createRouter();
13
- pendingLazyRouters = [];
13
+ pendingLazyRouters = /* @__PURE__ */ new Set();
14
14
  constructor(router, options = {}) {
15
15
  this.filter = options.filter ?? true;
16
16
  this.rootRouter = router;
@@ -32,13 +32,13 @@ class OpenAPIMatcher {
32
32
  procedure: contract instanceof Procedure ? contract : void 0
33
33
  });
34
34
  }, path);
35
- this.pendingLazyRouters.push(...lazyResults.map((result) => {
35
+ for (const result of lazyResults) {
36
36
  const prefix = getOpenAPIMeta(result.router)?.prefix;
37
- return {
37
+ this.pendingLazyRouters.add({
38
38
  ...result,
39
39
  matcher: prefix ? toRou3PrefixMatcher(prefix) : void 0
40
- };
41
- }));
40
+ });
41
+ }
42
42
  }
43
43
  async match(method, pathname, prefix) {
44
44
  if (prefix) {
@@ -56,44 +56,58 @@ class OpenAPIMatcher {
56
56
  return void 0;
57
57
  }
58
58
  }
59
- const result = await this.matchPathname(method, pathname);
60
- if (!result && pathname.includes("%")) {
61
- return this.matchPathname(method, normalizeHttpPath(pathname));
59
+ const loading = this.resolvePendingLazyRouters(pathname);
60
+ if (loading !== void 0) {
61
+ await loading;
62
62
  }
63
- return result;
64
- }
65
- async matchPathname(method, pathname) {
66
- await this.resolvePendingLazyRouters(pathname);
67
- const match = findRoute(this.tree, method, pathname);
68
- if (!match) {
63
+ let match = findRoute(this.tree, method, pathname);
64
+ if (match === void 0 && pathname.includes("%")) {
65
+ const normalizedPathname = normalizeHttpPath(pathname);
66
+ const normalizedLoading = this.resolvePendingLazyRouters(normalizedPathname);
67
+ if (normalizedLoading !== void 0) {
68
+ await normalizedLoading;
69
+ }
70
+ match = findRoute(this.tree, method, normalizedPathname);
71
+ }
72
+ if (match === void 0) {
69
73
  return void 0;
70
74
  }
71
- const procedure = await this.resolveProcedure(match.data);
75
+ const entry = match.data;
72
76
  return {
73
- path: match.data.path,
74
- procedure,
77
+ path: entry.path,
78
+ procedure: entry.procedure ?? await this.resolveProcedure(entry),
75
79
  params: match.params ? decodeParams(match.params) : void 0
76
80
  };
77
81
  }
78
- async resolvePendingLazyRouters(pathname) {
79
- if (!this.pendingLazyRouters.length) {
80
- return;
82
+ resolvePendingLazyRouters(pathname) {
83
+ for (const pending of this.pendingLazyRouters) {
84
+ if (pending.matcher === void 0 || pending.matcher.test(pathname)) {
85
+ return this.loadPendingLazyRouters(pathname);
86
+ }
81
87
  }
82
- const stillPending = [];
88
+ }
89
+ async loadPendingLazyRouters(pathname) {
83
90
  for (const pending of this.pendingLazyRouters) {
84
- if (!pending.matcher || pending.matcher.test(pathname)) {
85
- const { default: router } = await unlazy(pending.router);
86
- this.index(router, pending.path);
87
- } else {
88
- stillPending.push(pending);
91
+ if (pending.matcher === void 0 || pending.matcher.test(pathname)) {
92
+ await this.loadPendingLazyRouter(pending);
89
93
  }
90
94
  }
91
- this.pendingLazyRouters = stillPending;
92
95
  }
93
- async resolveProcedure(entry) {
94
- if (entry.procedure) {
95
- return entry.procedure;
96
+ loadPendingLazyRouter(pending) {
97
+ if (pending.loading === void 0) {
98
+ pending.loading = this.indexPendingLazyRouter(pending).catch((error) => {
99
+ pending.loading = void 0;
100
+ throw error;
101
+ });
96
102
  }
103
+ return pending.loading;
104
+ }
105
+ async indexPendingLazyRouter(pending) {
106
+ const { default: router } = await unlazy(pending.router);
107
+ this.index(router, pending.path);
108
+ this.pendingLazyRouters.delete(pending);
109
+ }
110
+ async resolveProcedure(entry) {
97
111
  const { default: maybeProcedure } = await unlazy(getRouter(this.rootRouter, entry.path));
98
112
  if (!(maybeProcedure instanceof Procedure)) {
99
113
  throw new TypeError(
@@ -121,7 +135,42 @@ function toRou3PrefixMatcher(path) {
121
135
  return routeToRegExp(pattern === "/" ? "/**" : `${pattern}/**`);
122
136
  }
123
137
  function decodeParams(params) {
124
- return Object.fromEntries(Object.entries(params).map(([key, val]) => [key, tryDecodeURIComponent(val)]));
138
+ return Object.fromEntries(Object.entries(params).map(([key, val]) => [key, safeDecodeURIComponent(val)]));
139
+ }
140
+
141
+ function serializeHeaders(headers, serializer) {
142
+ const result = new NullProtoObj();
143
+ for (const [key, value] of Object.entries(headers)) {
144
+ if (Array.isArray(value)) {
145
+ const lines = [];
146
+ for (const item of value) {
147
+ const line2 = serializeHeaderValue(item, serializer);
148
+ if (line2 !== void 0) {
149
+ lines.push(line2);
150
+ }
151
+ }
152
+ result[key] = lines;
153
+ continue;
154
+ }
155
+ const line = serializeHeaderValue(value, serializer);
156
+ if (line !== void 0) {
157
+ result[key] = line;
158
+ }
159
+ }
160
+ return result;
161
+ }
162
+ function serializeHeaderValue(value, serializer) {
163
+ const serialized = serializer.serialize(value);
164
+ if (Array.isArray(serialized)) {
165
+ return serialized.filter((item) => item !== void 0 && item !== null).map(String).join(",");
166
+ }
167
+ if (isTypescriptObject(serialized)) {
168
+ return Object.entries(serialized).filter(([, val]) => val !== void 0 && val !== null).map(([key, val]) => `${String(key)},${String(val)}`).join(",");
169
+ }
170
+ if (serialized !== void 0 && serialized !== null) {
171
+ return String(serialized);
172
+ }
173
+ return void 0;
125
174
  }
126
175
 
127
176
  class OpenAPIHandlerCodecCore {
@@ -134,30 +183,28 @@ class OpenAPIHandlerCodecCore {
134
183
  this.customErrorResponseBodySerializer = options.customErrorResponseBodyEncoder;
135
184
  }
136
185
  async decodeInput(matched, request) {
137
- const [_, search] = parseStandardUrl(request.url);
138
186
  const meta = getOpenAPIMeta(matched.procedure);
139
187
  const inputStructure = meta?.inputStructure ?? DEFAULT_OPENAPI_INPUT_STRUCTURE;
140
188
  const params = this.deserializeParams(matched.params, meta?.paramsStyles);
141
- const query = this.deserializeQuery(search, meta?.queryStyles);
142
189
  if (inputStructure === "compact") {
143
- const data = request.method === "GET" ? query : this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint));
190
+ const data = isBodylessMethod(request.method) ? this.deserializeQuery(request.url, meta?.queryStyles) : this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint));
144
191
  if (data === void 0) {
145
192
  return params;
146
193
  }
147
194
  if (!params || Object.keys(params).length < 1) {
148
195
  return data;
149
196
  }
150
- if (isPlainObject(data)) {
151
- return {
152
- ...params,
153
- ...data
154
- };
197
+ if (!isPlainObject(data)) {
198
+ return params;
155
199
  }
156
- return data;
200
+ return {
201
+ ...data,
202
+ ...params
203
+ };
157
204
  }
158
205
  return {
159
206
  params,
160
- query,
207
+ query: this.deserializeQuery(request.url, meta?.queryStyles),
161
208
  headers: request.headers,
162
209
  body: this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint))
163
210
  };
@@ -180,8 +227,8 @@ class OpenAPIHandlerCodecCore {
180
227
  throw new TypeError(`
181
228
  Invalid "detailed" output structure returned by procedure (${path.join(".")}):
182
229
  \u2022 Expected an object with optional properties:
183
- - status (number 200-399)
184
- - headers (Record<string, string | string[] | undefined>)
230
+ - status (number <400)
231
+ - headers (object)
185
232
  - body (any)
186
233
  \u2022 No extra keys allowed.
187
234
 
@@ -191,19 +238,20 @@ class OpenAPIHandlerCodecCore {
191
238
  }
192
239
  return {
193
240
  status: output.status ?? successStatus,
194
- headers: output.headers ?? {},
241
+ headers: output.headers !== void 0 ? serializeHeaders(output.headers, this.serializer) : {},
195
242
  body: this.serializer.serialize(output.body)
196
243
  };
197
244
  }
198
245
  encodeError(error) {
199
- const status = this.errorStatusMap[error.code] ?? DEFAULT_ERROR_STATUS;
246
+ const status = getOwn(this.errorStatusMap, error.code) ?? DEFAULT_ERROR_STATUS;
200
247
  return {
201
248
  status,
202
249
  headers: {},
203
250
  body: this.serializer.serialize(this.customErrorResponseBodySerializer?.(error) ?? error.toJSON())
204
251
  };
205
252
  }
206
- deserializeQuery(search, styles) {
253
+ deserializeQuery(url, styles) {
254
+ const [, search] = parseStandardUrl(url);
207
255
  const searchParams = new URLSearchParams(search);
208
256
  const parsed = this.serializer.deserialize(searchParams);
209
257
  if (!styles || !isPlainObject(parsed)) {
@@ -249,10 +297,10 @@ class OpenAPIHandlerCodecCore {
249
297
  }
250
298
  const parsed = { ...params };
251
299
  Object.entries(styles).forEach(([key, hint]) => {
252
- if (hint === void 0 || hint === "primitive") {
300
+ const value = getOwn(params, key);
301
+ if (hint === void 0 || hint === "primitive" || value === void 0) {
253
302
  return;
254
303
  }
255
- const value = params[key];
256
304
  if (hint === "comma-delimited-array") {
257
305
  parsed[key] = decodeDelimitedArray(value, ",");
258
306
  } else {
@@ -288,10 +336,10 @@ function isValidDetailedOutput(output) {
288
336
  if (Object.keys(output).some((key) => key !== "status" && key !== "headers" && key !== "body")) {
289
337
  return false;
290
338
  }
291
- if (output.status !== void 0 && (typeof output.status !== "number" || !Number.isInteger(output.status) || output.status < 200 || output.status > 399)) {
339
+ if (output.status !== void 0 && (typeof output.status !== "number" || !Number.isInteger(output.status) || output.status > 399)) {
292
340
  return false;
293
341
  }
294
- if (output.headers !== void 0 && !isStandardHeaders(output.headers)) {
342
+ if (output.headers !== void 0 && !isTypescriptObject(output.headers)) {
295
343
  return false;
296
344
  }
297
345
  return true;
@@ -315,4 +363,4 @@ function decodeDelimitedObject(value, delimiter) {
315
363
  return obj;
316
364
  }
317
365
 
318
- export { OpenAPIHandlerCodec as O, OpenAPIHandlerCodecCore as a, OpenAPIMatcher as b };
366
+ export { OpenAPIHandlerCodec as O, OpenAPIHandlerCodecCore as a, OpenAPIMatcher as b, serializeHeaders as s };
@@ -1,7 +1,7 @@
1
- import { wrapEventIteratorPreservingMeta, toORPCError, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
- import { isPlainObject, isAsyncIteratorObject } from '@orpc/shared';
3
- import { ErrorEvent } from '@standardserver/core';
4
- import { B as BracketNotationSerializer } from './openapi.Bt87OzTt.mjs';
1
+ import { wrapAsyncIteratorPreservingEventMeta, toORPCError, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
+ import { isPlainObject, NullProtoObj, copyOnWrite, isAsyncIteratorObject } from '@orpc/shared';
3
+ import { ErrorEvent } from '@standard-server/core';
4
+ import { B as BracketNotationSerializer } from './openapi.B2G-HeFn.mjs';
5
5
 
6
6
  const DEFAULT_OPENAPI_METHOD = "POST";
7
7
  const DEFAULT_OPENAPI_SUCCESS_DESCRIPTION = "OK";
@@ -48,18 +48,18 @@ const DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS = {
48
48
  },
49
49
  isTerminal: true
50
50
  },
51
- url: {
51
+ infinity: {
52
52
  condition(data) {
53
- return data instanceof URL;
53
+ return data === Number.POSITIVE_INFINITY || data === Number.NEGATIVE_INFINITY;
54
54
  },
55
- serialize(data) {
56
- return data.toString();
55
+ serialize() {
56
+ return null;
57
57
  },
58
58
  isTerminal: true
59
59
  },
60
- regexp: {
60
+ url: {
61
61
  condition(data) {
62
- return data instanceof RegExp;
62
+ return data instanceof URL;
63
63
  },
64
64
  serialize(data) {
65
65
  return data.toString();
@@ -84,45 +84,114 @@ const DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS = {
84
84
  }
85
85
  };
86
86
  class OpenAPIJsonSerializer {
87
- handlers;
87
+ inlineBuiltInHandlers;
88
+ handlerEntries;
88
89
  omitUndefinedProperties;
89
90
  constructor(options = {}) {
90
- this.handlers = {
91
- ...DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS,
92
- ...options.handlers
93
- };
94
91
  this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
92
+ const customHandlers = options.handlers;
93
+ if (customHandlers === void 0) {
94
+ this.inlineBuiltInHandlers = true;
95
+ return;
96
+ }
97
+ let inlineBuiltInHandlers = true;
98
+ let handlerEntries = [];
99
+ for (const key of Object.keys(customHandlers)) {
100
+ const handler = customHandlers[key];
101
+ if (inlineBuiltInHandlers && key in DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS) {
102
+ inlineBuiltInHandlers = false;
103
+ break;
104
+ }
105
+ if (handler !== void 0) {
106
+ handlerEntries.push(handler);
107
+ }
108
+ }
109
+ if (!inlineBuiltInHandlers) {
110
+ handlerEntries = [];
111
+ for (const handler of Object.values({ ...DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS, ...customHandlers })) {
112
+ if (handler !== void 0) {
113
+ handlerEntries.push(handler);
114
+ }
115
+ }
116
+ }
117
+ this.inlineBuiltInHandlers = inlineBuiltInHandlers;
118
+ this.handlerEntries = handlerEntries;
95
119
  }
96
120
  serialize(data) {
97
- const [json, maps, blobs] = this.serializeValue(data, [], [], []);
121
+ const maps = [];
122
+ const blobs = [];
123
+ const json = this.serializeValue(data, [], maps, blobs);
98
124
  return { json, maps, blobs };
99
125
  }
126
+ /**
127
+ * `segments` is a shared mutable stack (push/pop while walking),
128
+ * so it must be copied before being stored in `maps`.
129
+ */
100
130
  serializeValue(data, segments, maps, blobs) {
101
- for (const key in this.handlers) {
102
- const handler = this.handlers[key];
103
- if (handler && handler.condition(data)) {
104
- const serialized = handler.serialize(data);
105
- if (handler.isTerminal) {
106
- return [serialized, maps, blobs];
131
+ if (this.inlineBuiltInHandlers) {
132
+ switch (typeof data) {
133
+ case "string":
134
+ case "boolean":
135
+ return data;
136
+ case "number":
137
+ return Number.isFinite(data) ? data : null;
138
+ case "undefined":
139
+ return null;
140
+ case "bigint":
141
+ return data.toString();
142
+ case "object": {
143
+ if (data === null) {
144
+ return data;
145
+ }
146
+ if (data instanceof Date) {
147
+ return Number.isNaN(data.getTime()) ? null : data.toISOString();
148
+ }
149
+ if (data instanceof URL) {
150
+ return data.toString();
151
+ }
152
+ if (data instanceof Set) {
153
+ return this.serializeValue(Array.from(data), segments, maps, blobs);
154
+ }
155
+ if (data instanceof Map) {
156
+ return this.serializeValue(Array.from(data.entries()), segments, maps, blobs);
157
+ }
158
+ }
159
+ }
160
+ }
161
+ const handlerEntries = this.handlerEntries;
162
+ if (handlerEntries) {
163
+ for (let i = 0; i < handlerEntries.length; i++) {
164
+ const handler = handlerEntries[i];
165
+ if (handler.condition(data)) {
166
+ const serialized = handler.serialize(data);
167
+ if (handler.isTerminal) {
168
+ if (serialized instanceof Blob) {
169
+ maps.push(segments.slice());
170
+ blobs.push(serialized);
171
+ }
172
+ return serialized;
173
+ }
174
+ return this.serializeValue(serialized, segments, maps, blobs);
107
175
  }
108
- const result = this.serializeValue(serialized, segments, maps, blobs);
109
- return result;
110
176
  }
111
177
  }
112
178
  if (data instanceof Blob) {
113
- maps.push(segments);
179
+ maps.push(segments.slice());
114
180
  blobs.push(data);
115
- return [data, maps, blobs];
181
+ return data;
116
182
  }
117
183
  if (Array.isArray(data)) {
118
- const json = data.map((v, i) => {
119
- return this.serializeValue(v, [...segments, i], maps, blobs)[0];
120
- });
121
- return [json, maps, blobs];
184
+ const json = [];
185
+ for (let i = 0; i < data.length; i++) {
186
+ segments.push(i);
187
+ json.push(this.serializeValue(data[i], segments, maps, blobs));
188
+ segments.pop();
189
+ }
190
+ return json;
122
191
  }
123
192
  if (isPlainObject(data)) {
124
- const json = {};
125
- for (const k in data) {
193
+ const json = new NullProtoObj();
194
+ for (const k of Object.keys(data)) {
126
195
  const v = data[k];
127
196
  if (k === "toJSON" && typeof v === "function") {
128
197
  continue;
@@ -130,29 +199,38 @@ class OpenAPIJsonSerializer {
130
199
  if (v === void 0 && this.omitUndefinedProperties) {
131
200
  continue;
132
201
  }
133
- json[k] = this.serializeValue(v, [...segments, k], maps, blobs)[0];
202
+ segments.push(k);
203
+ json[k] = this.serializeValue(v, segments, maps, blobs);
204
+ segments.pop();
134
205
  }
135
- return [json, maps, blobs];
206
+ return json;
136
207
  }
137
- return [data, maps, blobs];
208
+ return data;
138
209
  }
139
210
  deserialize(serialized) {
140
- const ref = { data: serialized.json };
211
+ const ref = { json: serialized.json };
141
212
  if (serialized.blobs?.length) {
142
- serialized.maps.forEach((segments, i) => {
213
+ for (let i = 0; i < serialized.maps.length; i++) {
214
+ const blob = serialized.blobs[i];
215
+ if (!(blob instanceof Blob)) {
216
+ throw new TypeError(`Invalid OpenAPI serialized data: blob ${i} is not a Blob.`);
217
+ }
218
+ const segments = serialized.maps[i];
219
+ let original = serialized;
143
220
  let currentRef = ref;
144
- let preSegment = "data";
145
- segments.forEach((segment) => {
146
- currentRef = currentRef[preSegment];
147
- preSegment = segment;
221
+ let preSegment = "json";
222
+ for (let j = 0; j < segments.length; j++) {
223
+ original = original[preSegment];
224
+ currentRef = copyOnWrite(currentRef, preSegment, original);
225
+ preSegment = segments[j];
148
226
  if (!Object.hasOwn(currentRef, preSegment)) {
149
- throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
227
+ throw new TypeError(`Invalid OpenAPI serialized data: segment "${preSegment}" does not exist.`);
150
228
  }
151
- });
152
- currentRef[preSegment] = serialized.blobs[i];
153
- });
229
+ }
230
+ currentRef[preSegment] = blob;
231
+ }
154
232
  }
155
- return ref.data;
233
+ return ref.json;
156
234
  }
157
235
  }
158
236
 
@@ -166,34 +244,32 @@ class OpenAPISerializer {
166
244
  this.defaultSerializeOptions = serialize;
167
245
  }
168
246
  serialize(data, options = {}) {
169
- const useFormDataForBlobFields = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
170
- const asFormData = options.asFormData ?? this.defaultSerializeOptions?.asFormData ?? false;
171
247
  if (!options.asFormData) {
172
248
  if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
173
249
  return data;
174
250
  }
175
251
  if (isAsyncIteratorObject(data)) {
176
- return wrapEventIteratorPreservingMeta(data, {
252
+ return wrapAsyncIteratorPreservingEventMeta(data, {
177
253
  mapResult: (result) => {
178
254
  if (result.value === void 0) {
179
255
  return result;
180
256
  }
181
- return { done: result.done, value: this.serializeValue(result.value, { asFormData: false, useFormDataForBlobFields: false }) };
257
+ return { done: result.done, value: this.serializeValue(result.value, false, false) };
182
258
  },
183
- mapError: (e) => {
184
- return new ErrorEvent({
185
- data: this.serializeValue(toORPCError(e).toJSON(), { asFormData: false, useFormDataForBlobFields: false }),
186
- cause: e
187
- });
188
- }
259
+ mapError: (e) => new ErrorEvent(
260
+ this.serializeValue(toORPCError(e).toJSON(), false, false),
261
+ { cause: e }
262
+ )
189
263
  });
190
264
  }
191
265
  }
192
- return this.serializeValue(data, { useFormDataForBlobFields, asFormData });
266
+ const useFormDataForBlobFields = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
267
+ const asFormData = options.asFormData ?? this.defaultSerializeOptions?.asFormData ?? false;
268
+ return this.serializeValue(data, useFormDataForBlobFields, asFormData);
193
269
  }
194
- serializeValue(value, options) {
270
+ serializeValue(value, useFormDataForBlobFields, asFormData) {
195
271
  const { json, blobs } = this.jsonSerializer.serialize(value);
196
- if (!options.asFormData && (json instanceof Blob || json === void 0 || !blobs?.length || !options.useFormDataForBlobFields)) {
272
+ if (!asFormData && (json instanceof Blob || json === void 0 || !blobs?.length || !useFormDataForBlobFields)) {
197
273
  return json;
198
274
  }
199
275
  const form = new FormData();
@@ -211,7 +287,7 @@ class OpenAPISerializer {
211
287
  return data;
212
288
  }
213
289
  if (isAsyncIteratorObject(data)) {
214
- return wrapEventIteratorPreservingMeta(data, {
290
+ return wrapAsyncIteratorPreservingEventMeta(data, {
215
291
  mapResult: (result) => {
216
292
  if (result.value === void 0) {
217
293
  return result;
@@ -236,6 +312,9 @@ class OpenAPISerializer {
236
312
  }
237
313
  }
238
314
 
315
+ function isBodylessMethod(method) {
316
+ return method === "GET" || method === "HEAD";
317
+ }
239
318
  const PARAMETER_NAME_REGEX = /^[\w-]+$/;
240
319
  function getDynamicPathParams(path) {
241
320
  if (!path.includes("{")) {
@@ -272,4 +351,4 @@ function getDynamicPathParams(path) {
272
351
  return params;
273
352
  }
274
353
 
275
- export { DEFAULT_OPENAPI_METHOD as D, OpenAPISerializer as O, DEFAULT_OPENAPI_INPUT_STRUCTURE as a, DEFAULT_OPENAPI_OUTPUT_STRUCTURE as b, DEFAULT_OPENAPI_SUCCESS_DESCRIPTION as c, OpenAPIJsonSerializer as d, getDynamicPathParams as g };
354
+ export { DEFAULT_OPENAPI_METHOD as D, OpenAPISerializer as O, DEFAULT_OPENAPI_INPUT_STRUCTURE as a, DEFAULT_OPENAPI_OUTPUT_STRUCTURE as b, DEFAULT_OPENAPI_SUCCESS_DESCRIPTION as c, OpenAPIJsonSerializer as d, getDynamicPathParams as g, isBodylessMethod as i };
@@ -1,4 +1,4 @@
1
- import { StandardBody } from '@standardserver/core';
1
+ import { StandardBody } from '@standard-server/core';
2
2
  import { Segment } from '@orpc/shared';
3
3
 
4
4
  type BracketNotationSerializeResult = [string, unknown][];
@@ -81,10 +81,10 @@ interface OpenAPIJsonSerializerOptions {
81
81
  *
82
82
  * **Disabling:** Set a key to `undefined` to remove a built-in handler:
83
83
  * ```ts
84
- * handlers: { regexp: undefined }
84
+ * handlers: { url: undefined }
85
85
  * ```
86
86
  *
87
- * Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `regexp`, `set`, `map`.
87
+ * Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `infinity`, `url`, `set`, `map`.
88
88
  */
89
89
  handlers?: Record<string, undefined | OpenAPIJsonSerializerHandler> | undefined;
90
90
  /**
@@ -95,10 +95,15 @@ interface OpenAPIJsonSerializerOptions {
95
95
  omitUndefinedProperties?: boolean | undefined;
96
96
  }
97
97
  declare class OpenAPIJsonSerializer {
98
- private readonly handlers;
98
+ private readonly inlineBuiltInHandlers;
99
+ private readonly handlerEntries;
99
100
  private readonly omitUndefinedProperties;
100
101
  constructor(options?: OpenAPIJsonSerializerOptions);
101
102
  serialize(data: unknown): OpenAPIJsonSerialization;
103
+ /**
104
+ * `segments` is a shared mutable stack (push/pop while walking),
105
+ * so it must be copied before being stored in `maps`.
106
+ */
102
107
  private serializeValue;
103
108
  deserialize(serialized: OpenAPIJsonSerialization): unknown;
104
109
  }
@@ -118,7 +123,7 @@ interface OpenAPISerializerSerializeOptions {
118
123
  */
119
124
  asFormData?: boolean | undefined;
120
125
  }
121
- interface OpenAPISerializerOptions extends OpenAPIJsonSerializerOptions, OpenAPISerializerSerializeOptions {
126
+ interface OpenAPISerializerOptions extends OpenAPIJsonSerializerOptions {
122
127
  /**
123
128
  * Options for bracket notation serializer, like maxExplicitDeserializingArrayIndex
124
129
  */
@@ -128,6 +133,12 @@ interface OpenAPISerializerOptions extends OpenAPIJsonSerializerOptions, OpenAPI
128
133
  */
129
134
  serialize?: OpenAPISerializerSerializeOptions | undefined;
130
135
  }
136
+ /**
137
+ * Handles one-way serialization of oRPC payloads into JSON-friendly formats,
138
+ * partially supporting complex data types beyond plain JSON such as `Date`, `BigInt`, and `Set`.
139
+ *
140
+ * @see {@link https://orpc.dev/docs/openapi/serializer | OpenAPI Serializer}
141
+ */
131
142
  declare class OpenAPISerializer {
132
143
  private readonly jsonSerializer;
133
144
  private readonly bracketNotation;