@orpc/openapi 2.0.0-beta.20 → 2.0.0-beta.22

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 (33) hide show
  1. package/README.md +5 -5
  2. package/dist/adapters/fetch/index.d.mts +3 -3
  3. package/dist/adapters/fetch/index.d.ts +3 -3
  4. package/dist/adapters/fetch/index.mjs +4 -4
  5. package/dist/adapters/node/index.d.mts +2 -2
  6. package/dist/adapters/node/index.d.ts +2 -2
  7. package/dist/adapters/node/index.mjs +3 -3
  8. package/dist/adapters/standard/index.d.mts +10 -46
  9. package/dist/adapters/standard/index.d.ts +10 -46
  10. package/dist/adapters/standard/index.mjs +4 -4
  11. package/dist/extensions/route.d.mts +2 -2
  12. package/dist/extensions/route.d.ts +2 -2
  13. package/dist/helpers/index.mjs +1 -1
  14. package/dist/index.d.mts +13 -8
  15. package/dist/index.d.ts +13 -8
  16. package/dist/index.mjs +43 -106
  17. package/dist/plugins/index.d.mts +1 -1
  18. package/dist/plugins/index.d.ts +1 -1
  19. package/dist/shared/{openapi.zZH_UksW.mjs → openapi.0yE-t1W-.mjs} +113 -38
  20. package/dist/shared/{openapi.C-p_Q2lb.mjs → openapi.B48raJ3F.mjs} +6 -5
  21. package/dist/shared/openapi.BWJ1qv3c.d.ts +47 -0
  22. package/dist/shared/{openapi.CVgUshDP.mjs → openapi.BaqI61Xi.mjs} +88 -39
  23. package/dist/shared/{openapi.ByT4oUeY.d.mts → openapi.Bsz7d8xx.d.mts} +1 -1
  24. package/dist/shared/{openapi.ByT4oUeY.d.ts → openapi.Bsz7d8xx.d.ts} +1 -1
  25. package/dist/shared/{openapi.hg_rhZ4x.d.mts → openapi.COG_72WY.d.mts} +1 -1
  26. package/dist/shared/openapi.CTxN9oam.d.mts +47 -0
  27. package/dist/shared/{openapi.B6hEbRyF.d.ts → openapi.D7Fpk6aV.d.ts} +5 -3
  28. package/dist/shared/{openapi.BOOA-bde.d.mts → openapi.DBFXInk5.d.mts} +6 -1
  29. package/dist/shared/{openapi.BOOA-bde.d.ts → openapi.DBFXInk5.d.ts} +6 -1
  30. package/dist/shared/{openapi.BafbB3uM.d.mts → openapi.Dam82YDK.d.mts} +5 -3
  31. package/dist/shared/{openapi.DNNo0V-l.d.ts → openapi.Du7gMjyF.d.ts} +1 -1
  32. package/dist/shared/{openapi.Bt87OzTt.mjs → openapi.s_p5sN-P.mjs} +20 -15
  33. package/package.json +10 -10
@@ -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, i as isBodylessMethod, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.zZH_UksW.mjs';
3
+ import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, tryDecodeURIComponent, NullProtoObj, isTypescriptObject, isPlainObject, stringifyJSON, parseEmptyableJSON } from '@orpc/shared';
4
+ import { parseStandardUrl } from '@standardserver/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.0yE-t1W-.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(
@@ -124,6 +138,41 @@ function decodeParams(params) {
124
138
  return Object.fromEntries(Object.entries(params).map(([key, val]) => [key, tryDecodeURIComponent(val)]));
125
139
  }
126
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;
174
+ }
175
+
127
176
  class OpenAPIHandlerCodecCore {
128
177
  serializer;
129
178
  errorStatusMap;
@@ -180,8 +229,8 @@ class OpenAPIHandlerCodecCore {
180
229
  throw new TypeError(`
181
230
  Invalid "detailed" output structure returned by procedure (${path.join(".")}):
182
231
  \u2022 Expected an object with optional properties:
183
- - status (number 200-399)
184
- - headers (Record<string, string | string[] | undefined>)
232
+ - status (number <400)
233
+ - headers (object)
185
234
  - body (any)
186
235
  \u2022 No extra keys allowed.
187
236
 
@@ -191,7 +240,7 @@ class OpenAPIHandlerCodecCore {
191
240
  }
192
241
  return {
193
242
  status: output.status ?? successStatus,
194
- headers: output.headers ?? {},
243
+ headers: output.headers !== void 0 ? serializeHeaders(output.headers, this.serializer) : {},
195
244
  body: this.serializer.serialize(output.body)
196
245
  };
197
246
  }
@@ -288,10 +337,10 @@ function isValidDetailedOutput(output) {
288
337
  if (Object.keys(output).some((key) => key !== "status" && key !== "headers" && key !== "body")) {
289
338
  return false;
290
339
  }
291
- if (output.status !== void 0 && (typeof output.status !== "number" || !Number.isInteger(output.status) || output.status < 200 || output.status > 399)) {
340
+ if (output.status !== void 0 && (typeof output.status !== "number" || !Number.isInteger(output.status) || output.status > 399)) {
292
341
  return false;
293
342
  }
294
- if (output.headers !== void 0 && !isStandardHeaders(output.headers)) {
343
+ if (output.headers !== void 0 && !isTypescriptObject(output.headers)) {
295
344
  return false;
296
345
  }
297
346
  return true;
@@ -315,4 +364,4 @@ function decodeDelimitedObject(value, delimiter) {
315
364
  return obj;
316
365
  }
317
366
 
318
- export { OpenAPIHandlerCodec as O, OpenAPIHandlerCodecCore as a, OpenAPIMatcher as b };
367
+ export { OpenAPIHandlerCodec as O, OpenAPIHandlerCodecCore as a, OpenAPIMatcher as b, serializeHeaders as s };
@@ -15,4 +15,4 @@ type JsonifiedClient<T extends AnyNestedClient> = T extends Client<infer UClient
15
15
  [K in keyof T]: T[K] extends AnyNestedClient ? JsonifiedClient<T[K]> : T[K];
16
16
  };
17
17
 
18
- export type { JsonifiedClient as J, OpenAPIOperationObject as O, OpenAPIDocument as a, JsonifiedArray as b, JsonifiedClientError as c, JsonifiedValue as d };
18
+ export type { JsonifiedClient as J, OpenAPIDocument as O, JsonifiedArray as a, JsonifiedClientError as b, JsonifiedValue as c, OpenAPIOperationObject as d };
@@ -15,4 +15,4 @@ type JsonifiedClient<T extends AnyNestedClient> = T extends Client<infer UClient
15
15
  [K in keyof T]: T[K] extends AnyNestedClient ? JsonifiedClient<T[K]> : T[K];
16
16
  };
17
17
 
18
- export type { JsonifiedClient as J, OpenAPIOperationObject as O, OpenAPIDocument as a, JsonifiedArray as b, JsonifiedClientError as c, JsonifiedValue as d };
18
+ export type { JsonifiedClient as J, OpenAPIDocument as O, JsonifiedArray as a, JsonifiedClientError as b, JsonifiedValue as c, OpenAPIOperationObject as d };
@@ -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 '@standardserver/core';
5
- import { O as OpenAPIOperationObject } from './openapi.ByT4oUeY.mjs';
5
+ import { d as OpenAPIOperationObject } from './openapi.Bsz7d8xx.mjs';
6
6
 
7
7
  interface OpenAPIMeta {
8
8
  /**
@@ -0,0 +1,47 @@
1
+ import { ClientContext, ClientOptions, AnyORPCError } from '@orpc/client';
2
+ import { StandardLinkCodec, StandardLinkCodecDecodedResponse } from '@orpc/client/standard';
3
+ import { RouterContract } from '@orpc/contract';
4
+ import { Value, Promisable } from '@orpc/shared';
5
+ import { StandardUrl, StandardHeaders, StandardLazyResponse, StandardRequest } from '@standardserver/core';
6
+ import { O as OpenAPISerializer } from './openapi.DBFXInk5.mjs';
7
+
8
+ declare class OpenAPILinkCodecError extends TypeError {
9
+ }
10
+ interface OpenAPILinkCodecOptions<T extends ClientContext> {
11
+ /**
12
+ * Base URL for all requests, without origin. Should match the OpenAPI handler mount path.
13
+ *
14
+ * @example '/api'
15
+ * @default '/'
16
+ */
17
+ url?: Value<Promisable<StandardUrl>, [options: ClientOptions<T>, path: string[], input: unknown]>;
18
+ /**
19
+ * Inject headers into the request.
20
+ */
21
+ headers?: Value<Promisable<StandardHeaders | Headers>, [options: ClientOptions<T>, path: string[], input: unknown]>;
22
+ /**
23
+ * Override the default OpenAPI serializer.
24
+ */
25
+ serializer?: Pick<OpenAPISerializer, keyof OpenAPISerializer>;
26
+ /**
27
+ * Customize how an error response body is converted into an ORPC error.
28
+ * Return `null` or `undefined` to fall back to the default decoding behavior.
29
+ */
30
+ customErrorResponseBodyDecoder?: (deserializedBody: unknown, response: StandardLazyResponse) => AnyORPCError | null | undefined;
31
+ }
32
+ declare class OpenAPILinkCodec<T extends ClientContext> implements StandardLinkCodec<T> {
33
+ private readonly router;
34
+ private readonly baseUrl;
35
+ private readonly headers;
36
+ private readonly serializer;
37
+ private readonly customErrorResponseBodyDecoder;
38
+ constructor(router: RouterContract, options?: OpenAPILinkCodecOptions<T>);
39
+ encodeInput(input: unknown, path: string[], options: ClientOptions<T>): Promise<StandardRequest>;
40
+ private encodePathParam;
41
+ private serializeQueryString;
42
+ decodeResponse(response: StandardLazyResponse, path: string[], _options: ClientOptions<T>): Promise<StandardLinkCodecDecodedResponse>;
43
+ private resolveProcedure;
44
+ }
45
+
46
+ export { OpenAPILinkCodec as a, OpenAPILinkCodecError as b };
47
+ export type { OpenAPILinkCodecOptions as O };
@@ -4,7 +4,7 @@ import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCode
4
4
  import { Value, Promisable } from '@orpc/shared';
5
5
  import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
6
6
  import { AnyProcedureContract } from '@orpc/contract';
7
- import { O as OpenAPISerializer } from './openapi.BOOA-bde.js';
7
+ import { O as OpenAPISerializer } from './openapi.DBFXInk5.js';
8
8
 
9
9
  interface OpenAPIMatcherOptions {
10
10
  /**
@@ -18,7 +18,7 @@ declare class OpenAPIMatcher {
18
18
  private readonly filter;
19
19
  private readonly rootRouter;
20
20
  private readonly tree;
21
- private pendingLazyRouters;
21
+ private readonly pendingLazyRouters;
22
22
  constructor(router: AnyRouter, options?: OpenAPIMatcherOptions);
23
23
  private index;
24
24
  match(method: string, pathname: `/${string}`, prefix: `/${string}` | undefined): Promise<{
@@ -26,8 +26,10 @@ declare class OpenAPIMatcher {
26
26
  procedure: AnyProcedure;
27
27
  params?: Record<string, string> | undefined;
28
28
  } | undefined>;
29
- private matchPathname;
30
29
  private resolvePendingLazyRouters;
30
+ private loadPendingLazyRouters;
31
+ private loadPendingLazyRouter;
32
+ private indexPendingLazyRouter;
31
33
  private resolveProcedure;
32
34
  }
33
35
 
@@ -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
  }
@@ -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
  }
@@ -4,7 +4,7 @@ import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCode
4
4
  import { Value, Promisable } from '@orpc/shared';
5
5
  import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
6
6
  import { AnyProcedureContract } from '@orpc/contract';
7
- import { O as OpenAPISerializer } from './openapi.BOOA-bde.mjs';
7
+ import { O as OpenAPISerializer } from './openapi.DBFXInk5.mjs';
8
8
 
9
9
  interface OpenAPIMatcherOptions {
10
10
  /**
@@ -18,7 +18,7 @@ declare class OpenAPIMatcher {
18
18
  private readonly filter;
19
19
  private readonly rootRouter;
20
20
  private readonly tree;
21
- private pendingLazyRouters;
21
+ private readonly pendingLazyRouters;
22
22
  constructor(router: AnyRouter, options?: OpenAPIMatcherOptions);
23
23
  private index;
24
24
  match(method: string, pathname: `/${string}`, prefix: `/${string}` | undefined): Promise<{
@@ -26,8 +26,10 @@ declare class OpenAPIMatcher {
26
26
  procedure: AnyProcedure;
27
27
  params?: Record<string, string> | undefined;
28
28
  } | undefined>;
29
- private matchPathname;
30
29
  private resolvePendingLazyRouters;
30
+ private loadPendingLazyRouters;
31
+ private loadPendingLazyRouter;
32
+ private indexPendingLazyRouter;
31
33
  private resolveProcedure;
32
34
  }
33
35
 
@@ -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 '@standardserver/core';
5
- import { O as OpenAPIOperationObject } from './openapi.ByT4oUeY.js';
5
+ import { d as OpenAPIOperationObject } from './openapi.Bsz7d8xx.js';
6
6
 
7
7
  interface OpenAPIMeta {
8
8
  /**
@@ -6,21 +6,22 @@ class BracketNotationSerializer {
6
6
  this.maxExplicitDeserializingArrayIndex = options.maxExplicitDeserializingArrayIndex ?? 999;
7
7
  }
8
8
  serialize(data) {
9
- return this.internalSerialize(data, [], []);
9
+ const result = [];
10
+ this.internalSerialize(data, "", true, result);
11
+ return result;
10
12
  }
11
- internalSerialize(data, segments, result) {
13
+ internalSerialize(data, path, isRoot, result) {
12
14
  if (Array.isArray(data)) {
13
15
  data.forEach((item, i) => {
14
- this.internalSerialize(item, [...segments, i], result);
16
+ this.internalSerialize(item, isRoot ? i.toString() : `${path}[${i}]`, false, result);
15
17
  });
16
18
  } else if (isPlainObject(data)) {
17
19
  for (const key in data) {
18
- this.internalSerialize(data[key], [...segments, key], result);
20
+ this.internalSerialize(data[key], isRoot ? key : `${path}[${key}]`, false, result);
19
21
  }
20
22
  } else {
21
- result.push([this.stringifyPath(segments), data]);
23
+ result.push([path, data]);
22
24
  }
23
- return result;
24
25
  }
25
26
  deserialize(serialized) {
26
27
  if (serialized.length === 0) {
@@ -32,7 +33,8 @@ class BracketNotationSerializer {
32
33
  const segments = this.parsePath(path);
33
34
  let currentRef = ref;
34
35
  let nextSegment = "value";
35
- segments.forEach((segment, i) => {
36
+ for (let i = 0; i < segments.length; i++) {
37
+ const segment = segments[i];
36
38
  if (!Array.isArray(currentRef[nextSegment]) && !isPlainObject(currentRef[nextSegment])) {
37
39
  currentRef[nextSegment] = [];
38
40
  }
@@ -63,7 +65,7 @@ class BracketNotationSerializer {
63
65
  }
64
66
  currentRef = currentRef[nextSegment];
65
67
  nextSegment = segment;
66
- });
68
+ }
67
69
  if (Array.isArray(currentRef) && nextSegment === "") {
68
70
  arrayPushStyles.add(currentRef);
69
71
  currentRef.push(value);
@@ -80,12 +82,14 @@ class BracketNotationSerializer {
80
82
  return ref.value;
81
83
  }
82
84
  stringifyPath(segments) {
83
- return segments.reduce((result, segment, i) => {
84
- if (i === 0) {
85
- return segment.toString();
86
- }
87
- return `${result}[${segment}]`;
88
- }, "");
85
+ if (segments.length === 0) {
86
+ return "";
87
+ }
88
+ let result = segments[0].toString();
89
+ for (let i = 1; i < segments.length; i++) {
90
+ result += `[${segments[i]}]`;
91
+ }
92
+ return result;
89
93
  }
90
94
  parsePath(path) {
91
95
  const segments = [];
@@ -112,8 +116,9 @@ class BracketNotationSerializer {
112
116
  return inBrackets || segments.length === 0 ? [path] : segments;
113
117
  }
114
118
  }
119
+ const INTEGER_PATTERN = /^0$|^[1-9]\d*$/;
115
120
  function internalIsValidArrayIndex(value, maxIndex) {
116
- return /^0$|^[1-9]\d*$/.test(value) && Number(value) <= maxIndex;
121
+ return INTEGER_PATTERN.test(value) && Number(value) <= maxIndex;
117
122
  }
118
123
  function internalArrayToObject(array) {
119
124
  const obj = new NullProtoObj();
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.20",
4
+ "version": "2.0.0-beta.22",
5
5
  "license": "MIT",
6
6
  "homepage": "https://orpc.dev",
7
7
  "repository": {
@@ -75,20 +75,20 @@
75
75
  },
76
76
  "dependencies": {
77
77
  "@hey-api/spec-types": "0.0.0-next-20260408030107",
78
- "@standardserver/core": "^0.5.0",
79
- "@standardserver/fetch": "^0.5.0",
78
+ "@standardserver/core": "^0.6.0",
79
+ "@standardserver/fetch": "^0.6.0",
80
80
  "rou3": "^0.9.1",
81
- "@orpc/client": "2.0.0-beta.20",
82
- "@orpc/contract": "2.0.0-beta.20",
83
- "@orpc/server": "2.0.0-beta.20",
84
- "@orpc/shared": "2.0.0-beta.20",
85
- "@orpc/json-schema": "2.0.0-beta.20"
81
+ "@orpc/client": "2.0.0-beta.22",
82
+ "@orpc/contract": "2.0.0-beta.22",
83
+ "@orpc/shared": "2.0.0-beta.22",
84
+ "@orpc/server": "2.0.0-beta.22",
85
+ "@orpc/json-schema": "2.0.0-beta.22"
86
86
  },
87
87
  "devDependencies": {
88
- "@scalar/api-reference": "^1.57.2",
88
+ "@scalar/api-reference": "^1.63.0",
89
89
  "@types/swagger-ui": "^5.32.0",
90
90
  "fastify": "^5.8.5",
91
- "swagger-ui": "^5.32.6",
91
+ "swagger-ui": "^5.32.11",
92
92
  "zod": "^4.4.3"
93
93
  },
94
94
  "scripts": {