@orpc/openapi 2.0.0-beta.35 → 2.0.0-beta.36

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.
package/README.md CHANGED
@@ -46,29 +46,30 @@ You can read the documentation [here](https://orpc.dev).
46
46
 
47
47
  **Built-in features**
48
48
 
49
- | Package | Purpose | Docs |
50
- | -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
51
- | [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher) | Pub/Sub with memory, Redis, and Upstash adapters. | [Publisher](https://orpc.dev/docs/helpers/publisher) |
52
- | [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit) | Rate limiting with memory, Redis, and Upstash adapters. | [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
53
- | [@orpc/hibernation](https://www.npmjs.com/package/@orpc/hibernation) | Leverage Hibernation APIs like [Cloudflare's Hibernation WebSocket](https://developers.cloudflare.com/durable-objects/best-practices/websockets/#durable-objects-hibernation-websocket-api). | [Hibernation](https://orpc.dev/docs/integrations/hibernation) |
54
- | [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema) | Smart coercion for OpenAPI requests. | [Smart Coercion](https://orpc.dev/docs/plugins/smart-coercion) |
49
+ | Package | Purpose | Docs |
50
+ | -------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
51
+ | [@orpc/publisher](https://www.npmjs.com/package/@orpc/publisher) | Pub/Sub with memory, Redis, and Upstash adapters. | [Publisher](https://orpc.dev/docs/helpers/publisher) |
52
+ | [@orpc/ratelimit](https://www.npmjs.com/package/@orpc/ratelimit) | Rate limiting with memory, Redis, and Upstash adapters. | [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
53
+ | [@orpc/experimental-lock](https://www.npmjs.com/package/@orpc/experimental-lock) | Locking with memory, Redis, and Upstash adapters. | [Lock](https://orpc.dev/docs/helpers/lock) |
54
+ | [@orpc/hibernation](https://www.npmjs.com/package/@orpc/hibernation) | Leverage Hibernation APIs like [Cloudflare's Hibernation WebSocket](https://developers.cloudflare.com/durable-objects/best-practices/websockets/#durable-objects-hibernation-websocket-api). | [Hibernation](https://orpc.dev/docs/integrations/hibernation) |
55
+ | [@orpc/json-schema](https://www.npmjs.com/package/@orpc/json-schema) | Smart coercion for OpenAPI requests. | [Smart Coercion](https://orpc.dev/docs/plugins/smart-coercion) |
55
56
 
56
57
  **Framework & ecosystem integrations**
57
58
 
58
- | Package | Purpose | Docs |
59
- | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
60
- | [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
61
- | [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
62
- | [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
63
- | [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
64
- | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
65
- | [@orpc/experimental-msw](https://www.npmjs.com/package/@orpc/experimental-msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
66
- | [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
67
- | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
68
- | [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
69
- | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit) |
70
- | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare Workers](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Traces](https://orpc.dev/docs/integrations/cloudflare-traces) |
71
- | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
59
+ | Package | Purpose | Docs |
60
+ | ------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
61
+ | [@orpc/next](https://www.npmjs.com/package/@orpc/next) | Integrate with [Next.js Server Functions](https://nextjs.org/docs/app/getting-started/mutating-data). | [Next.js](https://orpc.dev/docs/integrations/next) |
62
+ | [@orpc/ai-sdk](https://www.npmjs.com/package/@orpc/ai-sdk) | Turn contracts and procedures into [AI SDK](https://ai-sdk.dev/) tools. | [AI SDK](https://orpc.dev/docs/integrations/ai-sdk) |
63
+ | [@orpc/tanstack-query](https://www.npmjs.com/package/@orpc/tanstack-query) | Integrate with [TanStack Query](https://tanstack.com/query/latest). | [TanStack Query](https://orpc.dev/docs/integrations/tanstack-query) |
64
+ | [@orpc/pinia-colada](https://www.npmjs.com/package/@orpc/pinia-colada) | Integrate with [Pinia Colada](https://pinia-colada.esm.dev/). | [Pinia Colada](https://orpc.dev/docs/integrations/pinia-colada) |
65
+ | [@orpc/swr](https://www.npmjs.com/package/@orpc/swr) | Integrate with [SWR](https://swr.vercel.app/). | [SWR](https://orpc.dev/docs/integrations/swr) |
66
+ | [@orpc/experimental-msw](https://www.npmjs.com/package/@orpc/experimental-msw) | Mock procedures with [Mock Service Worker](https://mswjs.io/). | [MSW](https://orpc.dev/docs/integrations/msw) |
67
+ | [@orpc/experimental-effect](https://www.npmjs.com/package/@orpc/experimental-effect) | Integrate with [Effect](https://effect.website/). | [Effect](https://orpc.dev/docs/integrations/effect) |
68
+ | [@orpc/nest](https://www.npmjs.com/package/@orpc/nest) | Implement your contract with [NestJS](https://nestjs.com/). | [NestJS](https://orpc.dev/docs/integrations/nest) |
69
+ | [@orpc/node](https://www.npmjs.com/package/@orpc/node) | [Node.js](https://nodejs.org/) plugins for static file serving and large uploads. | [Static File](https://orpc.dev/docs/plugins/static-file), [Tmp File Upload](https://orpc.dev/docs/plugins/tmp-file-upload), [Batch Response Compression](https://orpc.dev/docs/plugins/batch-response-compression) |
70
+ | [@orpc/bun](https://www.npmjs.com/package/@orpc/bun) | Adapters for [Bun's Redis](https://bun.sh/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock) |
71
+ | [@orpc/cloudflare](https://www.npmjs.com/package/@orpc/cloudflare) | Adapters for [Cloudflare Workers](https://developers.cloudflare.com/workers/). | [Publisher](https://orpc.dev/docs/helpers/publisher), [Rate Limit](https://orpc.dev/docs/helpers/ratelimit), [Lock](https://orpc.dev/docs/helpers/lock), [Traces](https://orpc.dev/docs/integrations/cloudflare-traces) |
72
+ | [@orpc/trpc](https://www.npmjs.com/package/@orpc/trpc) | Reuse existing [tRPC](https://trpc.io/) routers within oRPC. | [tRPC](https://orpc.dev/docs/integrations/trpc) |
72
73
 
73
74
  **Observability**
74
75
 
@@ -94,6 +95,14 @@ Like what we build over at [middleapi](https://github.com/middleapi)? You can he
94
95
  </tr>
95
96
  </table>
96
97
 
98
+ ### Special Sponsors
99
+
100
+ <table>
101
+ <tr>
102
+ <td align="center"><a href="http://twitter.com/rauchg?ref=middleapi&amp;utm_source=middleapi&amp;utm_medium=sponsor" target="_blank" rel="noopener sponsored" title="Guillermo Rauch"><img src="https://avatars.githubusercontent.com/u/13041?u=1ee8d111657cdd02ff6d253df00978d17ee6d722&amp;v=4" width="279" alt="Guillermo Rauch"/><br />Guillermo Rauch</a></td>
103
+ </tr>
104
+ </table>
105
+
97
106
  ### Organization Sponsors
98
107
 
99
108
  <table>
@@ -1,12 +1,12 @@
1
1
  import { AwsLambdaHandler } from '@orpc/server/aws-lambda';
2
2
  import { StandardHandler } from '@orpc/server/standard';
3
- import { O as OpenAPIHandlerCodec } from '../../shared/openapi.Dxn8HAW0.mjs';
3
+ import { O as OpenAPIHandlerCodec } from '../../shared/openapi.C64UQjVf.mjs';
4
4
  import '@orpc/client';
5
5
  import '@orpc/server';
6
6
  import '@orpc/shared';
7
7
  import '@standard-server/core';
8
- import '../../shared/openapi.Cz2PauNH.mjs';
9
- import '../../shared/openapi.s_p5sN-P.mjs';
8
+ import '../../shared/openapi.DzAO6T0h.mjs';
9
+ import '../../shared/openapi.D0kVKdNv.mjs';
10
10
  import '../../shared/openapi.B9PQzqBn.mjs';
11
11
  import 'rou3';
12
12
 
@@ -1,12 +1,12 @@
1
1
  import { FastifyHandler } from '@orpc/server/fastify';
2
2
  import { StandardHandler } from '@orpc/server/standard';
3
- import { O as OpenAPIHandlerCodec } from '../../shared/openapi.Dxn8HAW0.mjs';
3
+ import { O as OpenAPIHandlerCodec } from '../../shared/openapi.C64UQjVf.mjs';
4
4
  import '@orpc/client';
5
5
  import '@orpc/server';
6
6
  import '@orpc/shared';
7
7
  import '@standard-server/core';
8
- import '../../shared/openapi.Cz2PauNH.mjs';
9
- import '../../shared/openapi.s_p5sN-P.mjs';
8
+ import '../../shared/openapi.DzAO6T0h.mjs';
9
+ import '../../shared/openapi.D0kVKdNv.mjs';
10
10
  import '../../shared/openapi.B9PQzqBn.mjs';
11
11
  import 'rou3';
12
12
 
@@ -1,15 +1,15 @@
1
1
  import { FetchHandler } from '@orpc/server/fetch';
2
2
  import { StandardHandler } from '@orpc/server/standard';
3
- import { O as OpenAPIHandlerCodec } from '../../shared/openapi.Dxn8HAW0.mjs';
3
+ import { O as OpenAPIHandlerCodec } from '../../shared/openapi.C64UQjVf.mjs';
4
4
  import { FetchLinkTransport } from '@orpc/client/fetch';
5
5
  import { StandardLink } from '@orpc/client/standard';
6
- import { O as OpenAPILinkCodec } from '../../shared/openapi.0Vlm07ar.mjs';
6
+ import { O as OpenAPILinkCodec } from '../../shared/openapi.D3CTgGrh.mjs';
7
7
  import '@orpc/client';
8
8
  import '@orpc/server';
9
9
  import '@orpc/shared';
10
10
  import '@standard-server/core';
11
- import '../../shared/openapi.Cz2PauNH.mjs';
12
- import '../../shared/openapi.s_p5sN-P.mjs';
11
+ import '../../shared/openapi.DzAO6T0h.mjs';
12
+ import '../../shared/openapi.D0kVKdNv.mjs';
13
13
  import '../../shared/openapi.B9PQzqBn.mjs';
14
14
  import 'rou3';
15
15
  import '@orpc/contract';
@@ -1,12 +1,12 @@
1
1
  import { NodeHttpHandler } from '@orpc/server/node';
2
2
  import { StandardHandler } from '@orpc/server/standard';
3
- import { O as OpenAPIHandlerCodec } from '../../shared/openapi.Dxn8HAW0.mjs';
3
+ import { O as OpenAPIHandlerCodec } from '../../shared/openapi.C64UQjVf.mjs';
4
4
  import '@orpc/client';
5
5
  import '@orpc/server';
6
6
  import '@orpc/shared';
7
7
  import '@standard-server/core';
8
- import '../../shared/openapi.Cz2PauNH.mjs';
9
- import '../../shared/openapi.s_p5sN-P.mjs';
8
+ import '../../shared/openapi.DzAO6T0h.mjs';
9
+ import '../../shared/openapi.D0kVKdNv.mjs';
10
10
  import '../../shared/openapi.B9PQzqBn.mjs';
11
11
  import 'rou3';
12
12
 
@@ -1,4 +1,4 @@
1
- export { a as OpenAPIHandlerCodec, b as OpenAPIHandlerCodecCore, c as OpenAPIHandlerCodecCoreOptions, O as OpenAPIHandlerCodecOptions, d as OpenAPIMatcher, e as OpenAPIMatcherOptions } from '../../shared/openapi.BO2OB-Y9.mjs';
1
+ export { a as OpenAPIHandlerCodec, b as OpenAPIHandlerCodecCore, c as OpenAPIHandlerCodecCoreOptions, O as OpenAPIHandlerCodecOptions, d as OpenAPIMatcher, e as OpenAPIMatcherOptions } from '../../shared/openapi.Lnem4498.mjs';
2
2
  export { a as OpenAPILinkCodec, O as OpenAPILinkCodecOptions } from '../../shared/openapi.D3yXvICd.mjs';
3
3
  import { StandardHeaders } from '@standard-server/core';
4
4
  import { OpenAPISerializer } from '../../index.mjs';
@@ -1,4 +1,4 @@
1
- export { a as OpenAPIHandlerCodec, b as OpenAPIHandlerCodecCore, c as OpenAPIHandlerCodecCoreOptions, O as OpenAPIHandlerCodecOptions, d as OpenAPIMatcher, e as OpenAPIMatcherOptions } from '../../shared/openapi.DsnjJWwQ.js';
1
+ export { a as OpenAPIHandlerCodec, b as OpenAPIHandlerCodecCore, c as OpenAPIHandlerCodecCoreOptions, O as OpenAPIHandlerCodecOptions, d as OpenAPIMatcher, e as OpenAPIMatcherOptions } from '../../shared/openapi.MZg83xkY.js';
2
2
  export { a as OpenAPILinkCodec, O as OpenAPILinkCodecOptions } from '../../shared/openapi.DOy27J9v.js';
3
3
  import { StandardHeaders } from '@standard-server/core';
4
4
  import { OpenAPISerializer } from '../../index.js';
@@ -1,11 +1,11 @@
1
- export { O as OpenAPIHandlerCodec, a as OpenAPIHandlerCodecCore, b as OpenAPIMatcher, s as serializeHeaders } from '../../shared/openapi.Dxn8HAW0.mjs';
2
- export { O as OpenAPILinkCodec } from '../../shared/openapi.0Vlm07ar.mjs';
1
+ export { O as OpenAPIHandlerCodec, a as OpenAPIHandlerCodecCore, b as OpenAPIMatcher, s as serializeHeaders } from '../../shared/openapi.C64UQjVf.mjs';
2
+ export { O as OpenAPILinkCodec } from '../../shared/openapi.D3CTgGrh.mjs';
3
3
  import '@orpc/client';
4
4
  import '@orpc/server';
5
5
  import '@orpc/shared';
6
6
  import '@standard-server/core';
7
- import '../../shared/openapi.Cz2PauNH.mjs';
8
- import '../../shared/openapi.s_p5sN-P.mjs';
7
+ import '../../shared/openapi.DzAO6T0h.mjs';
8
+ import '../../shared/openapi.D0kVKdNv.mjs';
9
9
  import '../../shared/openapi.B9PQzqBn.mjs';
10
10
  import 'rou3';
11
11
  import '@orpc/contract';
@@ -1,6 +1,6 @@
1
1
  import { isSchemaIssue } from '@orpc/contract';
2
2
  import { isTypescriptObject } from '@orpc/shared';
3
- import { B as BracketNotationSerializer } from '../shared/openapi.s_p5sN-P.mjs';
3
+ import { B as BracketNotationSerializer } from '../shared/openapi.D0kVKdNv.mjs';
4
4
 
5
5
  function parseFormData(form) {
6
6
  const serializer = new BracketNotationSerializer();
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
- export { B as BracketNotationSerializer } from './shared/openapi.s_p5sN-P.mjs';
1
+ export { B as BracketNotationSerializer } from './shared/openapi.D0kVKdNv.mjs';
2
2
  import { createContractClientFactory, getAsyncIteratorObjectSchemaDetails, ProcedureContract, resolveMetaPlugins } from '@orpc/contract';
3
- import { D as DEFAULT_OPENAPI_METHOD, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, c as DEFAULT_OPENAPI_SUCCESS_DESCRIPTION, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE, i as isBodylessMethod, O as OpenAPISerializer, g as getDynamicPathParams } from './shared/openapi.Cz2PauNH.mjs';
4
- export { d as OpenAPIJsonSerializer } from './shared/openapi.Cz2PauNH.mjs';
3
+ import { D as DEFAULT_OPENAPI_METHOD, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, c as DEFAULT_OPENAPI_SUCCESS_DESCRIPTION, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE, i as isBodylessMethod, O as OpenAPISerializer, g as getDynamicPathParams } from './shared/openapi.DzAO6T0h.mjs';
4
+ export { d as OpenAPIJsonSerializer } from './shared/openapi.DzAO6T0h.mjs';
5
5
  import { g as getOpenAPIMeta, o as openapi } from './shared/openapi.B9PQzqBn.mjs';
6
6
  import { downgradeSpecV32ToV31, downgradeSpecV31ToV30 } from '@openapi-spec/downgrader';
7
7
  import { COMMON_ERROR_STATUS_MAP } from '@orpc/client';
@@ -581,8 +581,7 @@ function extractDetailedResponseParts(schema, defaultStatus) {
581
581
  }
582
582
  function buildErrorResponse(ctx, operation, def) {
583
583
  const definitionsByStatus = /* @__PURE__ */ new Map();
584
- for (const code in def.errorMap) {
585
- const config = def.errorMap[code];
584
+ for (const [code, config] of Object.entries(def.errorMap)) {
586
585
  if (!config) {
587
586
  continue;
588
587
  }
@@ -864,7 +863,7 @@ function populateRouterContractOpenAPIPaths(router, options = {}) {
864
863
  return router;
865
864
  }
866
865
  const populated = {};
867
- for (const key in router) {
866
+ for (const key of Object.keys(router)) {
868
867
  populated[key] = populateRouterContractOpenAPIPaths(
869
868
  router[key],
870
869
  { ...options, path: [...path, key] }
@@ -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, NullProtoObj, isTypescriptObject, isPlainObject, stringifyJSON, getOwn, parseEmptyableJSON } from '@orpc/shared';
3
+ import { value, pathToHttpPath, mergeHttpPath, normalizeHttpPath, 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.Cz2PauNH.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.DzAO6T0h.mjs';
6
6
  import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
7
7
  import { createRouter, addRoute, findRoute, routeToRegExp } from 'rou3';
8
8
 
@@ -135,7 +135,7 @@ function toRou3PrefixMatcher(path) {
135
135
  return routeToRegExp(pattern === "/" ? "/**" : `${pattern}/**`);
136
136
  }
137
137
  function decodeParams(params) {
138
- 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
139
  }
140
140
 
141
141
  function serializeHeaders(headers, serializer) {
@@ -1,4 +1,4 @@
1
- import { isPlainObject, NullProtoObj } from '@orpc/shared';
1
+ import { isPlainObject, NullProtoObj, getOwn, setOwn } from '@orpc/shared';
2
2
 
3
3
  class BracketNotationSerializer {
4
4
  maxExplicitDeserializingArrayIndex;
@@ -16,70 +16,57 @@ class BracketNotationSerializer {
16
16
  this.internalSerialize(item, isRoot ? i.toString() : `${path}[${i}]`, false, result);
17
17
  });
18
18
  } else if (isPlainObject(data)) {
19
- for (const key in data) {
20
- this.internalSerialize(data[key], isRoot ? key : `${path}[${key}]`, false, result);
19
+ for (const [key, value] of Object.entries(data)) {
20
+ this.internalSerialize(value, isRoot ? key : `${path}[${key}]`, false, result);
21
21
  }
22
22
  } else {
23
23
  result.push([path, data]);
24
24
  }
25
25
  }
26
26
  deserialize(serialized) {
27
- if (serialized.length === 0) {
28
- return new NullProtoObj();
29
- }
30
27
  const arrayPushStyles = /* @__PURE__ */ new WeakSet();
31
- const ref = { value: new NullProtoObj() };
28
+ const root = new NullProtoObj();
32
29
  for (const [path, value] of serialized) {
33
30
  const segments = this.parsePath(path);
34
- let currentRef = ref;
35
- let nextSegment = "value";
36
- for (let i = 0; i < segments.length; i++) {
31
+ let currentRef = root;
32
+ let nextSegment = segments[0];
33
+ for (let i = 1; i < segments.length; i++) {
37
34
  const segment = segments[i];
38
- if (!Array.isArray(currentRef[nextSegment]) && !isPlainObject(currentRef[nextSegment])) {
39
- currentRef[nextSegment] = [];
35
+ const isLast = i === segments.length - 1;
36
+ const existing = getOwn(currentRef, nextSegment);
37
+ let child = existing;
38
+ if (!Array.isArray(child) && !isPlainObject(child)) {
39
+ child = [];
40
40
  }
41
- if (i !== segments.length - 1) {
42
- if (Array.isArray(currentRef[nextSegment]) && !internalIsValidArrayIndex(segment, this.maxExplicitDeserializingArrayIndex)) {
43
- if (arrayPushStyles.has(currentRef[nextSegment])) {
44
- arrayPushStyles.delete(currentRef[nextSegment]);
45
- currentRef[nextSegment] = internalPushStyleArrayToObject(currentRef[nextSegment]);
46
- } else {
47
- currentRef[nextSegment] = internalArrayToObject(currentRef[nextSegment]);
48
- }
49
- }
50
- } else {
51
- if (Array.isArray(currentRef[nextSegment])) {
52
- if (segment === "") {
53
- if (currentRef[nextSegment].length && !arrayPushStyles.has(currentRef[nextSegment])) {
54
- currentRef[nextSegment] = internalArrayToObject(currentRef[nextSegment]);
55
- }
56
- } else {
57
- if (arrayPushStyles.has(currentRef[nextSegment])) {
58
- arrayPushStyles.delete(currentRef[nextSegment]);
59
- currentRef[nextSegment] = internalPushStyleArrayToObject(currentRef[nextSegment]);
60
- } else if (!internalIsValidArrayIndex(segment, this.maxExplicitDeserializingArrayIndex)) {
61
- currentRef[nextSegment] = internalArrayToObject(currentRef[nextSegment]);
62
- }
63
- }
41
+ if (Array.isArray(child)) {
42
+ const isPushStyle = arrayPushStyles.has(child);
43
+ const canStayArray = segment === "" ? isLast && (isPushStyle || child.length === 0) : internalIsValidArrayIndex(segment, this.maxExplicitDeserializingArrayIndex) && !(isLast && isPushStyle);
44
+ if (!canStayArray) {
45
+ arrayPushStyles.delete(child);
46
+ child = isPushStyle ? internalPushStyleArrayToObject(child) : internalArrayToObject(child);
64
47
  }
65
48
  }
66
- currentRef = currentRef[nextSegment];
49
+ if (child !== existing) {
50
+ setOwn(currentRef, nextSegment, child);
51
+ }
52
+ currentRef = child;
67
53
  nextSegment = segment;
68
54
  }
69
55
  if (Array.isArray(currentRef) && nextSegment === "") {
70
56
  arrayPushStyles.add(currentRef);
71
57
  currentRef.push(value);
72
- } else if (nextSegment in currentRef) {
73
- if (Array.isArray(currentRef[nextSegment])) {
74
- currentRef[nextSegment].push(value);
58
+ } else if (Object.hasOwn(currentRef, nextSegment)) {
59
+ const current = currentRef[nextSegment];
60
+ if (Array.isArray(current)) {
61
+ current.push(value);
75
62
  } else {
76
- currentRef[nextSegment] = [currentRef[nextSegment], value];
63
+ setOwn(currentRef, nextSegment, [current, value]);
77
64
  }
78
65
  } else {
79
- currentRef[nextSegment] = value;
66
+ setOwn(currentRef, nextSegment, value);
80
67
  }
81
68
  }
82
- return ref.value;
69
+ return root;
83
70
  }
84
71
  stringifyPath(segments) {
85
72
  if (segments.length === 0) {
@@ -1,12 +1,12 @@
1
1
  import { createORPCErrorFromMalformedResponse, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
2
  import { getRouterContract, ProcedureContract } from '@orpc/contract';
3
3
  import { unlazy } from '@orpc/server';
4
- import { value, pathToHttpPath, mergeHttpPath, isTypescriptObject, stringifyJSON } from '@orpc/shared';
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.Cz2PauNH.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.DzAO6T0h.mjs';
8
8
  import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
9
- import { s as serializeHeaders } from './openapi.Dxn8HAW0.mjs';
9
+ import { s as serializeHeaders } from './openapi.C64UQjVf.mjs';
10
10
 
11
11
  const END_SLASH_REGEX = /\/$/;
12
12
  class OpenAPILinkCodec {
@@ -129,16 +129,16 @@ class OpenAPILinkCodec {
129
129
  encodePathParam(val, param, style, path) {
130
130
  let encoded;
131
131
  if (style === "comma-delimited-array" && Array.isArray(val)) {
132
- encoded = val.map((val2) => this.serializer.serialize(val2)).filter((val2) => val2 !== void 0 && val2 !== null).map((val2) => encodeURIComponent(String(val2))).join(",");
132
+ encoded = val.map((val2) => this.serializer.serialize(val2)).filter((val2) => val2 !== void 0 && val2 !== null).map((val2) => safeEncodeURIComponent(String(val2))).join(",");
133
133
  } else if (style === "comma-delimited-object" && isTypescriptObject(val)) {
134
- encoded = Object.entries(val).map(([key, val2]) => [key, this.serializer.serialize(val2)]).filter(([, val2]) => val2 !== void 0 && val2 !== null).map(([key, val2]) => `${encodeURIComponent(String(key))},${encodeURIComponent(String(val2))}`).join(",");
134
+ encoded = Object.entries(val).map(([key, val2]) => [key, this.serializer.serialize(val2)]).filter(([, val2]) => val2 !== void 0 && val2 !== null).map(([key, val2]) => `${safeEncodeURIComponent(String(key))},${safeEncodeURIComponent(String(val2))}`).join(",");
135
135
  } else {
136
136
  const serialized = this.serializer.serialize(val);
137
137
  if (serialized !== void 0 && serialized !== null) {
138
138
  if (param.allowsSlash) {
139
- encoded = String(serialized).split("/").map(encodeURIComponent).join("/");
139
+ encoded = String(serialized).split("/").map(safeEncodeURIComponent).join("/");
140
140
  } else {
141
- encoded = encodeURIComponent(String(serialized));
141
+ encoded = safeEncodeURIComponent(String(serialized));
142
142
  }
143
143
  }
144
144
  }
@@ -1,7 +1,7 @@
1
1
  import { wrapAsyncIteratorPreservingEventMeta, toORPCError, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
2
  import { isPlainObject, NullProtoObj, isAsyncIteratorObject } from '@orpc/shared';
3
3
  import { ErrorEvent } from '@standard-server/core';
4
- import { B as BracketNotationSerializer } from './openapi.s_p5sN-P.mjs';
4
+ import { B as BracketNotationSerializer } from './openapi.D0kVKdNv.mjs';
5
5
 
6
6
  const DEFAULT_OPENAPI_METHOD = "POST";
7
7
  const DEFAULT_OPENAPI_SUCCESS_DESCRIPTION = "OK";
@@ -96,8 +96,7 @@ class OpenAPIJsonSerializer {
96
96
  }
97
97
  let inlineBuiltInHandlers = true;
98
98
  let handlerEntries = [];
99
- for (const key in customHandlers) {
100
- const handler = customHandlers[key];
99
+ for (const [key, handler] of Object.entries(customHandlers)) {
101
100
  if (inlineBuiltInHandlers && key in DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS) {
102
101
  inlineBuiltInHandlers = false;
103
102
  break;
@@ -194,8 +193,7 @@ class OpenAPIJsonSerializer {
194
193
  }
195
194
  if (isPlainObject(data)) {
196
195
  const json = new NullProtoObj();
197
- for (const k in data) {
198
- const v = data[k];
196
+ for (const [k, v] of Object.entries(data)) {
199
197
  if (k === "toJSON" && typeof v === "function") {
200
198
  continue;
201
199
  }
@@ -253,12 +251,10 @@ class OpenAPISerializer {
253
251
  }
254
252
  return { done: result.done, value: this.serializeValue(result.value, false, false) };
255
253
  },
256
- mapError: (e) => {
257
- return new ErrorEvent({
258
- data: this.serializeValue(toORPCError(e).toJSON(), false, false),
259
- cause: e
260
- });
261
- }
254
+ mapError: (e) => new ErrorEvent(
255
+ this.serializeValue(toORPCError(e).toJSON(), false, false),
256
+ { cause: e }
257
+ )
262
258
  });
263
259
  }
264
260
  }
@@ -1,6 +1,6 @@
1
1
  import { AnyORPCError } from '@orpc/client';
2
2
  import { AnyProcedure, AnyRouter, Context } from '@orpc/server';
3
- import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
3
+ import { StandardHandlerCodec, ResolvedStandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
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';
@@ -78,7 +78,7 @@ interface OpenAPIHandlerCodecOptions<T extends Context> extends OpenAPIHandlerCo
78
78
  declare class OpenAPIHandlerCodec<T extends Context> extends OpenAPIHandlerCodecCore<T> implements StandardHandlerCodec<T> {
79
79
  private readonly matcher;
80
80
  constructor(router: AnyRouter, options?: OpenAPIHandlerCodecOptions<T>);
81
- resolveProcedure(request: StandardLazyRequest, options: StandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
81
+ resolveProcedure(request: StandardLazyRequest, options: ResolvedStandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
82
82
  }
83
83
 
84
84
  export { OpenAPIHandlerCodec as a, OpenAPIHandlerCodecCore as b, OpenAPIMatcher as d };
@@ -1,6 +1,6 @@
1
1
  import { AnyORPCError } from '@orpc/client';
2
2
  import { AnyProcedure, AnyRouter, Context } from '@orpc/server';
3
- import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
3
+ import { StandardHandlerCodec, ResolvedStandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
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';
@@ -78,7 +78,7 @@ interface OpenAPIHandlerCodecOptions<T extends Context> extends OpenAPIHandlerCo
78
78
  declare class OpenAPIHandlerCodec<T extends Context> extends OpenAPIHandlerCodecCore<T> implements StandardHandlerCodec<T> {
79
79
  private readonly matcher;
80
80
  constructor(router: AnyRouter, options?: OpenAPIHandlerCodecOptions<T>);
81
- resolveProcedure(request: StandardLazyRequest, options: StandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
81
+ resolveProcedure(request: StandardLazyRequest, options: ResolvedStandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
82
82
  }
83
83
 
84
84
  export { OpenAPIHandlerCodec as a, OpenAPIHandlerCodecCore as b, OpenAPIMatcher as d };
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.35",
4
+ "version": "2.0.0-beta.36",
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": [
@@ -99,11 +99,11 @@
99
99
  "dependencies": {
100
100
  "@openapi-spec/downgrader": "~0.1.0",
101
101
  "@openapi-spec/types": "~0.1.0",
102
- "@orpc/client": "2.0.0-beta.35",
103
- "@orpc/contract": "2.0.0-beta.35",
104
- "@orpc/json-schema": "2.0.0-beta.35",
105
- "@orpc/server": "2.0.0-beta.35",
106
- "@orpc/shared": "2.0.0-beta.35",
102
+ "@orpc/client": "2.0.0-beta.36",
103
+ "@orpc/contract": "2.0.0-beta.36",
104
+ "@orpc/json-schema": "2.0.0-beta.36",
105
+ "@orpc/server": "2.0.0-beta.36",
106
+ "@orpc/shared": "2.0.0-beta.36",
107
107
  "@standard-server/core": "~0.9.0",
108
108
  "@standard-server/fetch": "~0.9.0",
109
109
  "rou3": "^0.9.1"