@orpc/openapi 2.0.0-beta.40 → 2.0.0-beta.42

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 (38) hide show
  1. package/README.md +5 -5
  2. package/dist/adapters/aws-lambda/index.d.mts +1 -1
  3. package/dist/adapters/aws-lambda/index.d.ts +1 -1
  4. package/dist/adapters/aws-lambda/index.mjs +2 -2
  5. package/dist/adapters/fastify/index.d.mts +1 -1
  6. package/dist/adapters/fastify/index.d.ts +1 -1
  7. package/dist/adapters/fastify/index.mjs +2 -2
  8. package/dist/adapters/fetch/index.d.mts +1 -1
  9. package/dist/adapters/fetch/index.d.ts +1 -1
  10. package/dist/adapters/fetch/index.mjs +3 -3
  11. package/dist/adapters/node/index.d.mts +1 -1
  12. package/dist/adapters/node/index.d.ts +1 -1
  13. package/dist/adapters/node/index.mjs +2 -2
  14. package/dist/adapters/standard/index.d.mts +2 -2
  15. package/dist/adapters/standard/index.d.ts +2 -2
  16. package/dist/adapters/standard/index.mjs +3 -3
  17. package/dist/extensions/route.d.mts +1 -1
  18. package/dist/extensions/route.d.ts +1 -1
  19. package/dist/index.d.mts +11 -7
  20. package/dist/index.d.ts +11 -7
  21. package/dist/index.mjs +58 -153
  22. package/dist/plugins/index.d.mts +17 -3
  23. package/dist/plugins/index.d.ts +17 -3
  24. package/dist/plugins/index.mjs +8 -8
  25. package/dist/shared/{openapi.fnBK1ELE.d.mts → openapi.BDiBd3_k.d.mts} +2 -1
  26. package/dist/shared/{openapi.wQKxWEI2.mjs → openapi.BJRea9Uu.mjs} +81 -36
  27. package/dist/shared/{openapi.DI21x5Yo.d.mts → openapi.BTq9wym2.d.mts} +6 -4
  28. package/dist/shared/{openapi.DI21x5Yo.d.ts → openapi.BTq9wym2.d.ts} +6 -4
  29. package/dist/shared/{openapi.B1LWf28E.mjs → openapi.Bu_PfTtX.mjs} +10 -1
  30. package/dist/shared/{openapi.Dl3gew1x.d.mts → openapi.C2LayTNZ.d.mts} +1 -1
  31. package/dist/shared/{openapi.Dl3gew1x.d.ts → openapi.C2LayTNZ.d.ts} +1 -1
  32. package/dist/shared/{openapi.DE5kXinS.d.mts → openapi.Cg9h6jpm.d.mts} +1 -1
  33. package/dist/shared/{openapi.EM8eC1Xn.d.ts → openapi.CkzUS83v.d.ts} +2 -1
  34. package/dist/shared/{openapi.BwNINoeN.d.ts → openapi.D0yWs-uW.d.ts} +1 -1
  35. package/dist/shared/{openapi.BdClbrwk.mjs → openapi.D326pNzT.mjs} +7 -3
  36. package/dist/shared/{openapi.Cem81Zhm.d.ts → openapi.r98bZ3Ig.d.mts} +1 -1
  37. package/dist/shared/{openapi.Cem81Zhm.d.mts → openapi.r98bZ3Ig.d.ts} +1 -1
  38. package/package.json +12 -12
@@ -1,10 +1,10 @@
1
1
  import { COMMON_ERROR_STATUS_MAP } from '@orpc/client';
2
- import { walkProcedureContractsSync, Procedure, unlazy, getRouter, createContractProcedure, DEFAULT_SUCCESS_STATUS, DEFAULT_ERROR_STATUS } from '@orpc/server';
3
- import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, safeDecodeURIComponent, NullProtoObj, isTypescriptObject, isPlainObject, stringifyJSON, getOwn, parseEmptyableJSON } from '@orpc/shared';
2
+ import { walkProcedureContractsSync, unlazy, getRouter, Procedure, createContractProcedure, DEFAULT_SUCCESS_STATUS, DEFAULT_ERROR_STATUS } from '@orpc/server';
3
+ import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, setOwn, safeDecodeURIComponent, NullProtoObj, isTypescriptObject, isPlainObject, stringifyJSON, getOwn, parseEmptyableJSON } from '@orpc/shared';
4
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.B1LWf28E.mjs';
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
- import { createRouter, addRoute, findRoute, routeToRegExp } from 'rou3';
7
+ import { createRouter, addRoute, findRoute, findAllRoutes, routeToRegExp } from 'rou3';
8
8
 
9
9
  class OpenAPIMatcher {
10
10
  filter;
@@ -17,6 +17,7 @@ class OpenAPIMatcher {
17
17
  this.index(router);
18
18
  }
19
19
  index(router, path = []) {
20
+ const routes = [];
20
21
  const lazyResults = walkProcedureContractsSync(router, (contract, path2) => {
21
22
  if (!value(this.filter, contract, path2)) {
22
23
  return;
@@ -25,19 +26,30 @@ class OpenAPIMatcher {
25
26
  const method = meta?.method ?? DEFAULT_OPENAPI_METHOD;
26
27
  const postHttpPath = meta?.path ?? pathToHttpPath(path2);
27
28
  const openapiPath = meta?.prefix ? mergeHttpPath(meta.prefix, postHttpPath) : postHttpPath;
28
- const rou3Path = toRou3Pattern(openapiPath);
29
- addRoute(this.tree, method, rou3Path, {
30
- path: path2,
31
- contract,
32
- procedure: contract instanceof Procedure ? contract : void 0
29
+ const { pattern, ...route } = toRou3Route(openapiPath);
30
+ routes.push({
31
+ method,
32
+ pattern,
33
+ entry: {
34
+ path: path2,
35
+ contract,
36
+ procedure: contract instanceof Procedure ? contract : void 0,
37
+ ...route
38
+ }
33
39
  });
34
40
  }, path);
35
- for (const result of lazyResults) {
41
+ const pendingLazyRouters = lazyResults.map((result) => {
36
42
  const prefix = getOpenAPIMeta(result.router)?.prefix;
37
- this.pendingLazyRouters.add({
43
+ return {
38
44
  ...result,
39
45
  matcher: prefix ? toRou3PrefixMatcher(prefix) : void 0
40
- });
46
+ };
47
+ });
48
+ for (const { method, pattern, entry } of routes) {
49
+ addRoute(this.tree, method, pattern, entry);
50
+ }
51
+ for (const pending of pendingLazyRouters) {
52
+ this.pendingLazyRouters.add(pending);
41
53
  }
42
54
  }
43
55
  async match(method, pathname, prefix) {
@@ -60,14 +72,14 @@ class OpenAPIMatcher {
60
72
  if (loading !== void 0) {
61
73
  await loading;
62
74
  }
63
- let match = findRoute(this.tree, method, pathname);
75
+ let match = this.findMatch(method, pathname);
64
76
  if (match === void 0 && pathname.includes("%")) {
65
77
  const normalizedPathname = normalizeHttpPath(pathname);
66
78
  const normalizedLoading = this.resolvePendingLazyRouters(normalizedPathname);
67
79
  if (normalizedLoading !== void 0) {
68
80
  await normalizedLoading;
69
81
  }
70
- match = findRoute(this.tree, method, normalizedPathname);
82
+ match = this.findMatch(method, normalizedPathname);
71
83
  }
72
84
  if (match === void 0) {
73
85
  return void 0;
@@ -76,9 +88,16 @@ class OpenAPIMatcher {
76
88
  return {
77
89
  path: entry.path,
78
90
  procedure: entry.procedure ?? await this.resolveProcedure(entry),
79
- params: match.params ? decodeParams(match.params) : void 0
91
+ params: entry.params && decodeParams(entry.params, match.params)
80
92
  };
81
93
  }
94
+ findMatch(method, pathname) {
95
+ const match = findRoute(this.tree, method, pathname);
96
+ if (match === void 0 || !hasEmptyCatchAll(match)) {
97
+ return match;
98
+ }
99
+ return findAllRoutes(this.tree, method, pathname).reverse().find((match2) => !hasEmptyCatchAll(match2));
100
+ }
82
101
  resolvePendingLazyRouters(pathname) {
83
102
  for (const pending of this.pendingLazyRouters) {
84
103
  if (pending.matcher === void 0 || pending.matcher.test(pathname)) {
@@ -118,24 +137,51 @@ class OpenAPIMatcher {
118
137
  return entry.procedure;
119
138
  }
120
139
  }
121
- function toRou3Pattern(path) {
122
- const params = getDynamicPathParams(path);
123
- if (!params?.length) {
124
- return path;
140
+ function toRou3Route(path) {
141
+ const dynamicParams = getDynamicPathParams(path);
142
+ if (!dynamicParams) {
143
+ return { pattern: escapeRou3Literal(path) };
125
144
  }
126
- for (let i = params.length - 1; i >= 0; i--) {
127
- const param = params[i];
128
- const pattern = param.allowsSlash ? `**:${param.parameterName}` : `:${param.parameterName}`;
129
- path = path.slice(0, param.startIndex) + pattern + path.slice(param.startIndex + param.segment.length);
145
+ let pattern = "";
146
+ let literalStart = 0;
147
+ let catchAllKey;
148
+ const params = [];
149
+ for (const param of dynamicParams) {
150
+ const key = `p${params.length}`;
151
+ params.push([key, param.parameterName]);
152
+ pattern += escapeRou3Literal(path.slice(literalStart, param.startIndex));
153
+ literalStart = param.startIndex + param.segment.length;
154
+ if (param.allowsSlash) {
155
+ if (catchAllKey !== void 0) {
156
+ throw new TypeError(`OpenAPI path "${path}" has more than one catch-all param ({+name}), but only one is supported per path.`);
157
+ }
158
+ catchAllKey = key;
159
+ pattern += `:${key}(.*)`;
160
+ } else {
161
+ pattern += `:${key}`;
162
+ }
130
163
  }
131
- return path;
164
+ pattern += escapeRou3Literal(path.slice(literalStart));
165
+ return { pattern, params, catchAllKey };
132
166
  }
133
- function toRou3PrefixMatcher(path) {
134
- const pattern = toRou3Pattern(path);
135
- return routeToRegExp(pattern === "/" ? "/**" : `${pattern}/**`);
167
+ const ROU3_SYNTAX_REGEX = /[\\:*?+(){}]|(?<![^/])\.(?=\.?(?:\/|$))/g;
168
+ function escapeRou3Literal(text) {
169
+ return text.replace(ROU3_SYNTAX_REGEX, "\\$&");
136
170
  }
137
- function decodeParams(params) {
138
- return Object.fromEntries(Object.entries(params).map(([key, val]) => [key, safeDecodeURIComponent(val)]));
171
+ function toRou3PrefixMatcher(prefix) {
172
+ const catchAll = getDynamicPathParams(prefix)?.find((param) => param.allowsSlash);
173
+ const head = catchAll ? prefix.slice(0, catchAll.startIndex) : prefix;
174
+ return routeToRegExp(mergeHttpPath(toRou3Route(head).pattern, "/**"));
175
+ }
176
+ function hasEmptyCatchAll(match) {
177
+ return match.data.catchAllKey !== void 0 && !match.params?.[match.data.catchAllKey];
178
+ }
179
+ function decodeParams(params, values) {
180
+ const decoded = {};
181
+ for (const [rou3Key, name] of params) {
182
+ setOwn(decoded, name, safeDecodeURIComponent(values[rou3Key]));
183
+ }
184
+ return decoded;
139
185
  }
140
186
 
141
187
  function serializeHeaders(headers, serializer) {
@@ -183,13 +229,11 @@ class OpenAPIHandlerCodecCore {
183
229
  this.customErrorResponseBodySerializer = options.customErrorResponseBodyEncoder;
184
230
  }
185
231
  async decodeInput(matched, request) {
186
- const [_, search] = parseStandardUrl(request.url);
187
232
  const meta = getOpenAPIMeta(matched.procedure);
188
233
  const inputStructure = meta?.inputStructure ?? DEFAULT_OPENAPI_INPUT_STRUCTURE;
189
234
  const params = this.deserializeParams(matched.params, meta?.paramsStyles);
190
- const query = this.deserializeQuery(search, meta?.queryStyles);
191
235
  if (inputStructure === "compact") {
192
- const data = isBodylessMethod(request.method) ? query : this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint));
236
+ const data = isBodylessMethod(request.method) ? this.deserializeQuery(request.url, meta?.queryStyles) : this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint));
193
237
  if (data === void 0) {
194
238
  return params;
195
239
  }
@@ -206,7 +250,7 @@ class OpenAPIHandlerCodecCore {
206
250
  }
207
251
  return {
208
252
  params,
209
- query,
253
+ query: this.deserializeQuery(request.url, meta?.queryStyles),
210
254
  headers: request.headers,
211
255
  body: this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint))
212
256
  };
@@ -252,7 +296,8 @@ class OpenAPIHandlerCodecCore {
252
296
  body: this.serializer.serialize(this.customErrorResponseBodySerializer?.(error) ?? error.toJSON())
253
297
  };
254
298
  }
255
- deserializeQuery(search, styles) {
299
+ deserializeQuery(url, styles) {
300
+ const [, search] = parseStandardUrl(url);
256
301
  const searchParams = new URLSearchParams(search);
257
302
  const parsed = this.serializer.deserialize(searchParams);
258
303
  if (!styles || !isPlainObject(parsed)) {
@@ -298,10 +343,10 @@ class OpenAPIHandlerCodecCore {
298
343
  }
299
344
  const parsed = { ...params };
300
345
  Object.entries(styles).forEach(([key, hint]) => {
301
- if (hint === void 0 || hint === "primitive") {
346
+ const value = getOwn(params, key);
347
+ if (hint === void 0 || hint === "primitive" || value === void 0) {
302
348
  return;
303
349
  }
304
- const value = params[key];
305
350
  if (hint === "comma-delimited-array") {
306
351
  parsed[key] = decodeDelimitedArray(value, ",");
307
352
  } else {
@@ -1,4 +1,6 @@
1
- import { OpenAPIV3_0, OpenAPIV3_1, OpenAPIV3_2 } from '@openapi-spec/types';
1
+ import * as OpenAPIV3_0 from '@openapi-spec/types/v3.0';
2
+ import * as OpenAPIV3_1 from '@openapi-spec/types/v3.1';
3
+ import * as OpenAPIV3_2 from '@openapi-spec/types/v3.2';
2
4
  import { AnyNestedClient, Client, ORPCError } from '@orpc/client';
3
5
  import { AsyncIteratorClass } from '@orpc/shared';
4
6
 
@@ -14,10 +16,10 @@ type OpenAPIVersion = `3.0.${number}` | `3.1.${number}` | `3.2.${number}`;
14
16
  * @see {@link https://orpc.dev/docs/openapi/specification#openapi-version | OpenAPI Specification - OpenAPI Version}
15
17
  */
16
18
  type OpenAPIDocument<TVersion extends OpenAPIVersion> = TVersion extends `3.0.${string}` ? OpenAPIV3_0.OpenAPIObject : TVersion extends `3.1.${string}` ? OpenAPIV3_1.OpenAPIObject : OpenAPIV3_2.OpenAPIObject;
17
- type JsonifiedValue<T> = T extends string ? T : T extends number ? T : T extends boolean ? T : T extends null ? T : T extends undefined ? T : T extends Array<unknown> ? JsonifiedArray<T> : T extends Record<string, unknown> ? {
19
+ type JsonifiedValue<T> = T extends string | number | boolean | null | undefined ? T : T extends Date | bigint | URL ? string : T extends ReadonlyArray<unknown> ? JsonifiedArray<T> : T extends Blob | ReadonlyMap<any, any> | ReadonlySet<any> | AsyncIteratorObject<any, any, any> | Function ? T extends File ? File : T extends Blob ? Blob : T extends ReadonlyMap<infer K, infer V> ? JsonifiedArray<[K, V][]> : T extends ReadonlySet<infer U> ? JsonifiedArray<U[]> : T extends AsyncIteratorClass<infer U, infer V> ? AsyncIteratorClass<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncGenerator<infer U, infer V> ? AsyncGenerator<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncIteratorObject<infer U, infer V> ? AsyncIteratorObject<JsonifiedValue<U>, JsonifiedValue<V>> : unknown : T extends object ? {
18
20
  [K in keyof T]: JsonifiedValue<T[K]>;
19
- } : T extends Date ? string : T extends bigint ? string : T extends File ? File : T extends Blob ? Blob : T extends URL ? string : T extends Map<infer K, infer V> ? JsonifiedArray<[K, V][]> : T extends Set<infer U> ? JsonifiedArray<U[]> : T extends AsyncIteratorClass<infer U, infer V> ? AsyncIteratorClass<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncGenerator<infer U, infer V> ? AsyncGenerator<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncIteratorObject<infer U, infer V> ? AsyncIteratorObject<JsonifiedValue<U>, JsonifiedValue<V>> : unknown;
20
- type JsonifiedArray<T extends Array<unknown>> = T extends readonly [] ? [] : T extends readonly [infer U, ...infer V] ? [U extends undefined ? null : JsonifiedValue<U>, ...JsonifiedArray<V>] : T extends Array<infer U> ? Array<JsonifiedValue<U>> : unknown;
21
+ } : unknown;
22
+ type JsonifiedArray<T extends ReadonlyArray<unknown>> = T extends readonly [] ? [] : T extends readonly [infer U, ...infer V] ? [U extends undefined ? null : JsonifiedValue<U>, ...JsonifiedArray<V>] : T extends ReadonlyArray<infer U> ? Array<JsonifiedValue<U>> : unknown;
21
23
  type JsonifiedClientError<T> = T extends ORPCError<infer UCode, infer UData> ? ORPCError<UCode, JsonifiedValue<UData>> : T;
22
24
  /**
23
25
  * Client type whose outputs and error data replace types JSON cannot represent with their JSON equivalents.
@@ -1,4 +1,6 @@
1
- import { OpenAPIV3_0, OpenAPIV3_1, OpenAPIV3_2 } from '@openapi-spec/types';
1
+ import * as OpenAPIV3_0 from '@openapi-spec/types/v3.0';
2
+ import * as OpenAPIV3_1 from '@openapi-spec/types/v3.1';
3
+ import * as OpenAPIV3_2 from '@openapi-spec/types/v3.2';
2
4
  import { AnyNestedClient, Client, ORPCError } from '@orpc/client';
3
5
  import { AsyncIteratorClass } from '@orpc/shared';
4
6
 
@@ -14,10 +16,10 @@ type OpenAPIVersion = `3.0.${number}` | `3.1.${number}` | `3.2.${number}`;
14
16
  * @see {@link https://orpc.dev/docs/openapi/specification#openapi-version | OpenAPI Specification - OpenAPI Version}
15
17
  */
16
18
  type OpenAPIDocument<TVersion extends OpenAPIVersion> = TVersion extends `3.0.${string}` ? OpenAPIV3_0.OpenAPIObject : TVersion extends `3.1.${string}` ? OpenAPIV3_1.OpenAPIObject : OpenAPIV3_2.OpenAPIObject;
17
- type JsonifiedValue<T> = T extends string ? T : T extends number ? T : T extends boolean ? T : T extends null ? T : T extends undefined ? T : T extends Array<unknown> ? JsonifiedArray<T> : T extends Record<string, unknown> ? {
19
+ type JsonifiedValue<T> = T extends string | number | boolean | null | undefined ? T : T extends Date | bigint | URL ? string : T extends ReadonlyArray<unknown> ? JsonifiedArray<T> : T extends Blob | ReadonlyMap<any, any> | ReadonlySet<any> | AsyncIteratorObject<any, any, any> | Function ? T extends File ? File : T extends Blob ? Blob : T extends ReadonlyMap<infer K, infer V> ? JsonifiedArray<[K, V][]> : T extends ReadonlySet<infer U> ? JsonifiedArray<U[]> : T extends AsyncIteratorClass<infer U, infer V> ? AsyncIteratorClass<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncGenerator<infer U, infer V> ? AsyncGenerator<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncIteratorObject<infer U, infer V> ? AsyncIteratorObject<JsonifiedValue<U>, JsonifiedValue<V>> : unknown : T extends object ? {
18
20
  [K in keyof T]: JsonifiedValue<T[K]>;
19
- } : T extends Date ? string : T extends bigint ? string : T extends File ? File : T extends Blob ? Blob : T extends URL ? string : T extends Map<infer K, infer V> ? JsonifiedArray<[K, V][]> : T extends Set<infer U> ? JsonifiedArray<U[]> : T extends AsyncIteratorClass<infer U, infer V> ? AsyncIteratorClass<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncGenerator<infer U, infer V> ? AsyncGenerator<JsonifiedValue<U>, JsonifiedValue<V>> : T extends AsyncIteratorObject<infer U, infer V> ? AsyncIteratorObject<JsonifiedValue<U>, JsonifiedValue<V>> : unknown;
20
- type JsonifiedArray<T extends Array<unknown>> = T extends readonly [] ? [] : T extends readonly [infer U, ...infer V] ? [U extends undefined ? null : JsonifiedValue<U>, ...JsonifiedArray<V>] : T extends Array<infer U> ? Array<JsonifiedValue<U>> : unknown;
21
+ } : unknown;
22
+ type JsonifiedArray<T extends ReadonlyArray<unknown>> = T extends readonly [] ? [] : T extends readonly [infer U, ...infer V] ? [U extends undefined ? null : JsonifiedValue<U>, ...JsonifiedArray<V>] : T extends ReadonlyArray<infer U> ? Array<JsonifiedValue<U>> : unknown;
21
23
  type JsonifiedClientError<T> = T extends ORPCError<infer UCode, infer UData> ? ORPCError<UCode, JsonifiedValue<UData>> : T;
22
24
  /**
23
25
  * Client type whose outputs and error data replace types JSON cannot represent with their JSON equivalents.
@@ -48,6 +48,15 @@ const DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS = {
48
48
  },
49
49
  isTerminal: true
50
50
  },
51
+ infinity: {
52
+ condition(data) {
53
+ return data === Number.POSITIVE_INFINITY || data === Number.NEGATIVE_INFINITY;
54
+ },
55
+ serialize() {
56
+ return null;
57
+ },
58
+ isTerminal: true
59
+ },
51
60
  url: {
52
61
  condition(data) {
53
62
  return data instanceof URL;
@@ -125,7 +134,7 @@ class OpenAPIJsonSerializer {
125
134
  case "boolean":
126
135
  return data;
127
136
  case "number":
128
- return Number.isNaN(data) ? null : data;
137
+ return Number.isFinite(data) ? data : null;
129
138
  case "undefined":
130
139
  return null;
131
140
  case "bigint":
@@ -84,7 +84,7 @@ interface OpenAPIJsonSerializerOptions {
84
84
  * handlers: { url: undefined }
85
85
  * ```
86
86
  *
87
- * Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `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
  /**
@@ -84,7 +84,7 @@ interface OpenAPIJsonSerializerOptions {
84
84
  * handlers: { url: undefined }
85
85
  * ```
86
86
  *
87
- * Built-in type keys: `undefined`, `bigint`, `date`, `nan`, `url`, `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
  /**
@@ -3,7 +3,7 @@ import { StandardLinkCodec, StandardLinkCodecDecodedResponse } from '@orpc/clien
3
3
  import { RouterContract } from '@orpc/contract';
4
4
  import { Value, Promisable, Public } from '@orpc/shared';
5
5
  import { StandardUrl, StandardHeaders, StandardLazyResponse, StandardRequest } from '@standard-server/core';
6
- import { O as OpenAPISerializer } from './openapi.Dl3gew1x.mjs';
6
+ import { O as OpenAPISerializer } from './openapi.C2LayTNZ.mjs';
7
7
 
8
8
  interface OpenAPILinkCodecOptions<T extends ClientContext> {
9
9
  /**
@@ -4,7 +4,7 @@ import { StandardHandlerCodec, ResolvedStandardHandlerHandleOptions, StandardHan
4
4
  import { Value, Public, Promisable } from '@orpc/shared';
5
5
  import { StandardLazyRequest, StandardResponse } from '@standard-server/core';
6
6
  import { AnyProcedureContract } from '@orpc/contract';
7
- import { O as OpenAPISerializer } from './openapi.Dl3gew1x.js';
7
+ import { O as OpenAPISerializer } from './openapi.C2LayTNZ.js';
8
8
 
9
9
  interface OpenAPIMatcherOptions {
10
10
  /**
@@ -26,6 +26,7 @@ declare class OpenAPIMatcher {
26
26
  procedure: AnyProcedure;
27
27
  params?: Record<string, string> | undefined;
28
28
  } | undefined>;
29
+ private findMatch;
29
30
  private resolvePendingLazyRouters;
30
31
  private loadPendingLazyRouters;
31
32
  private loadPendingLazyRouter;
@@ -3,7 +3,7 @@ import { StandardLinkCodec, StandardLinkCodecDecodedResponse } from '@orpc/clien
3
3
  import { RouterContract } from '@orpc/contract';
4
4
  import { Value, Promisable, Public } from '@orpc/shared';
5
5
  import { StandardUrl, StandardHeaders, StandardLazyResponse, StandardRequest } from '@standard-server/core';
6
- import { O as OpenAPISerializer } from './openapi.Dl3gew1x.js';
6
+ import { O as OpenAPISerializer } from './openapi.C2LayTNZ.js';
7
7
 
8
8
  interface OpenAPILinkCodecOptions<T extends ClientContext> {
9
9
  /**
@@ -4,11 +4,12 @@ import { unlazy } from '@orpc/server';
4
4
  import { value, pathToHttpPath, mergeHttpPath, isTypescriptObject, stringifyJSON, safeEncodeURIComponent } from '@orpc/shared';
5
5
  import { mergeStandardHeaders, parseStandardUrl } from '@standard-server/core';
6
6
  import { toStandardHeaders } from '@standard-server/fetch';
7
- import { O as OpenAPISerializer, D as DEFAULT_OPENAPI_METHOD, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, g as getDynamicPathParams, i as isBodylessMethod, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.B1LWf28E.mjs';
7
+ import { O as OpenAPISerializer, D as DEFAULT_OPENAPI_METHOD, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, g as getDynamicPathParams, i as isBodylessMethod, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.Bu_PfTtX.mjs';
8
8
  import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
9
- import { s as serializeHeaders } from './openapi.wQKxWEI2.mjs';
9
+ import { s as serializeHeaders } from './openapi.BJRea9Uu.mjs';
10
10
 
11
11
  const END_SLASH_REGEX = /\/$/;
12
+ const DOT_SEGMENT_REGEX = /(?:^|\/)\.{1,2}(?:\/|$)/;
12
13
  class OpenAPILinkCodec {
13
14
  constructor(router, options = {}) {
14
15
  this.router = router;
@@ -145,6 +146,9 @@ class OpenAPILinkCodec {
145
146
  if (!encoded) {
146
147
  throw new TypeError(`Path param "${param.parameterName}" cannot be empty in call to procedure (${path.join(".")}).`);
147
148
  }
149
+ if (DOT_SEGMENT_REGEX.test(encoded)) {
150
+ throw new TypeError(`Path param "${param.parameterName}" cannot contain "." or ".." segments in call to procedure (${path.join(".")}).`);
151
+ }
148
152
  return encoded;
149
153
  }
150
154
  serializeQueryString(data, queryStyles) {
@@ -339,7 +343,7 @@ function encodeDelimitedArray(serializedValues, encodedDelimiter) {
339
343
  return strings.map(encodeURLSearchParamComponent).join(encodedDelimiter);
340
344
  }
341
345
  function encodeDelimitedObject(entries, encodedDelimiter) {
342
- const strings = entries.filter(([v]) => v !== null && v !== void 0).map(([k, v]) => [k, String(v)]);
346
+ const strings = entries.filter(([, v]) => v !== null && v !== void 0).map(([k, v]) => [k, String(v)]);
343
347
  if (!strings.length) {
344
348
  return void 0;
345
349
  }
@@ -2,7 +2,7 @@ import { AnySchema, ErrorMap, MetaPlugin, AnyProcedureContract } from '@orpc/con
2
2
  import { Lazy } from '@orpc/server';
3
3
  import { Value } from '@orpc/shared';
4
4
  import { StandardBodyHint } from '@standard-server/core';
5
- import { OpenAPIV3_2 } from '@openapi-spec/types';
5
+ import * as OpenAPIV3_2 from '@openapi-spec/types/v3.2';
6
6
 
7
7
  interface OpenAPIMeta {
8
8
  /**
@@ -2,7 +2,7 @@ import { AnySchema, ErrorMap, MetaPlugin, AnyProcedureContract } from '@orpc/con
2
2
  import { Lazy } from '@orpc/server';
3
3
  import { Value } from '@orpc/shared';
4
4
  import { StandardBodyHint } from '@standard-server/core';
5
- import { OpenAPIV3_2 } from '@openapi-spec/types';
5
+ import * as OpenAPIV3_2 from '@openapi-spec/types/v3.2';
6
6
 
7
7
  interface OpenAPIMeta {
8
8
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@orpc/openapi",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.40",
4
+ "version": "2.0.0-beta.42",
5
5
  "description": "Generate OpenAPI specs from oRPC routers and serve OpenAPI-compliant APIs with end-to-end type safety",
6
6
  "license": "MIT",
7
7
  "funding": [
@@ -97,20 +97,20 @@
97
97
  }
98
98
  },
99
99
  "dependencies": {
100
- "@openapi-spec/downgrader": "~0.1.0",
101
- "@openapi-spec/types": "~0.1.0",
102
- "@orpc/client": "2.0.0-beta.40",
103
- "@orpc/contract": "2.0.0-beta.40",
104
- "@orpc/json-schema": "2.0.0-beta.40",
105
- "@orpc/server": "2.0.0-beta.40",
106
- "@orpc/shared": "2.0.0-beta.40",
107
- "@standard-server/core": "~0.9.2",
108
- "@standard-server/fetch": "~0.9.2",
109
- "rou3": "^0.9.1"
100
+ "@openapi-spec/downgrader": "~0.3.0",
101
+ "@openapi-spec/types": "~0.3.0",
102
+ "@orpc/client": "2.0.0-beta.42",
103
+ "@orpc/contract": "2.0.0-beta.42",
104
+ "@orpc/json-schema": "2.0.0-beta.42",
105
+ "@orpc/server": "2.0.0-beta.42",
106
+ "@orpc/shared": "2.0.0-beta.42",
107
+ "@standard-server/core": "~0.10.1",
108
+ "@standard-server/fetch": "~0.10.1",
109
+ "rou3": "^1.0.0"
110
110
  },
111
111
  "devDependencies": {
112
112
  "@scalar/api-reference": "^1.65.1",
113
- "@standard-server/aws-lambda": "~0.9.2",
113
+ "@standard-server/aws-lambda": "~0.10.1",
114
114
  "@types/swagger-ui": "^5.32.0",
115
115
  "fastify": "^5.12.1",
116
116
  "swagger-ui": "^5.32.14",