@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
package/dist/index.mjs CHANGED
@@ -1,13 +1,13 @@
1
- export { B as BracketNotationSerializer } from './shared/openapi.Bt87OzTt.mjs';
1
+ export { B as BracketNotationSerializer } from './shared/openapi.s_p5sN-P.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.zZH_UksW.mjs';
4
- export { d as OpenAPIJsonSerializer } from './shared/openapi.zZH_UksW.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.0yE-t1W-.mjs';
4
+ export { d as OpenAPIJsonSerializer } from './shared/openapi.0yE-t1W-.mjs';
5
5
  import { g as getOpenAPIMeta, o as openapi } from './shared/openapi.B9PQzqBn.mjs';
6
6
  import { COMMON_ERROR_STATUS_MAP } from '@orpc/client';
7
7
  export { COMMON_ERROR_STATUS_MAP } from '@orpc/client';
8
- import { encodeJsonPointerSegment, ensureJsonSchemaObject, mapJsonSchemaRefs, visitJsonSchemaRefs, decodeJsonPointerSegment, isUnconstrainedSchema, combineJsonSchemasWithComposition, extractJsonObjectSchemaEntries, combineJsonObjectSchemaEntries, flattenJsonUnionSchema, isJsonPrimitiveSchema, matchArrayableJsonSchema, isJsonFileSchema, DelegatingJsonSchemaConverter, StandardJsonSchemaConverter } from '@orpc/json-schema';
8
+ import { encodeJsonPointerSegment, ensureJsonSchemaObject, mapJsonSchemaRefs, decodeJsonPointerSegment, isUnconstrainedSchema, combineJsonSchemasWithComposition, extractJsonObjectSchemaEntries, combineJsonObjectSchemaEntries, flattenJsonUnionSchema, isJsonPrimitiveSchema, matchArrayableJsonSchema, isJsonFileSchema, DelegatingJsonSchemaConverter, StandardJsonSchemaConverter } from '@orpc/json-schema';
9
9
  import { DEFAULT_SUCCESS_STATUS, DEFAULT_ERROR_STATUS, walkProcedureContractsAsync } from '@orpc/server';
10
- import { value, isDeepEqual, findDeepMatches, isPlainObject, stringifyJSON, toArray, clone, pathToHttpPath, mergeHttpPath, isTypescriptObject } from '@orpc/shared';
10
+ import { isDeepEqual, value, findDeepMatches, isPlainObject, stringifyJSON, toArray, clone, pathToHttpPath, mergeHttpPath, isTypescriptObject } from '@orpc/shared';
11
11
  import '@standardserver/core';
12
12
 
13
13
  function createContractJsonifiedClientFactory(link, options = {}) {
@@ -15,14 +15,13 @@ function createContractJsonifiedClientFactory(link, options = {}) {
15
15
  }
16
16
 
17
17
  class OpenAPIComponentRegistry {
18
- constructor(doc, shouldHoistDef) {
18
+ constructor(doc, customComponentName) {
19
19
  this.doc = doc;
20
- this.shouldHoistDef = shouldHoistDef;
20
+ this.customComponentName = customComponentName;
21
21
  }
22
22
  /**
23
23
  * Registers `schema` as a component under `preferredName` (or an equivalent/postfixed name)
24
- * and returns a `$ref` to it. When hoisting is declined via `shouldHoistDef`, the schema is
25
- * returned in its local `$defs` form instead.
24
+ * and returns a `$ref` to it.
26
25
  */
27
26
  register(preferredName, schema) {
28
27
  const { $defs, ...body } = schema;
@@ -39,59 +38,53 @@ class OpenAPIComponentRegistry {
39
38
  }
40
39
  /**
41
40
  * Moves a schema's root-level `$defs` into `doc.components.schemas` and rewrites
42
- * its refs accordingly. Defs declined by `shouldHoistDef` stay local unless a
43
- * hoisted def references them.
41
+ * its refs accordingly.
44
42
  */
45
43
  hoistDefs(schema, direction) {
46
44
  if (typeof schema !== "object" || !schema.$defs) {
47
45
  return schema;
48
46
  }
49
47
  const { $defs, ...rest } = schema;
50
- const localDefs = {};
51
- const hoistedDefs = {};
48
+ const defs = {};
49
+ const preferredNames = {};
52
50
  for (const defName of Object.keys($defs)) {
53
51
  const defSchema = $defs[defName];
54
52
  if (defSchema === void 0) {
55
53
  continue;
56
54
  }
57
55
  const normalized = ensureJsonSchemaObject(defSchema);
58
- if (value(this.shouldHoistDef, defName, normalized) !== false) {
59
- hoistedDefs[defName] = normalized;
60
- } else {
61
- localDefs[defName] = normalized;
62
- }
56
+ defs[defName] = normalized;
57
+ preferredNames[defName] = this.customComponentName?.(defName, normalized) ?? defName;
63
58
  }
64
- hoistReferencedLocalDefs(hoistedDefs, localDefs);
65
- if (Object.keys(hoistedDefs).length === 0) {
59
+ const defNames = Object.keys(defs);
60
+ if (defNames.length === 0) {
66
61
  return schema;
67
62
  }
68
63
  this.doc.components ??= {};
69
64
  this.doc.components.schemas ??= {};
70
65
  const componentsSchemas = this.doc.components.schemas;
71
66
  const identityRenameMap = Object.fromEntries(
72
- Object.keys(hoistedDefs).map((defName) => [defName, defName])
67
+ defNames.map((defName) => [defName, preferredNames[defName]])
73
68
  );
74
69
  const renameMap = {};
75
70
  const pendingSchemas = [];
76
- for (const defName of Object.keys(hoistedDefs)) {
77
- const cleanSchema = hoistedDefs[defName];
71
+ for (const defName of defNames) {
72
+ const cleanSchema = defs[defName];
78
73
  const candidateSchemas = Object.fromEntries(
79
- Object.keys(hoistedDefs).map((currentDefName) => [
80
- currentDefName,
81
- rewriteComponentSchemaRefs(
82
- withReferencedLocalDefs(hoistedDefs[currentDefName], localDefs),
83
- {
84
- ...identityRenameMap,
85
- ...renameMap
86
- }
87
- )
74
+ defNames.map((currentDefName) => [
75
+ preferredNames[currentDefName],
76
+ rewriteComponentSchemaRefs(defs[currentDefName], {
77
+ ...identityRenameMap,
78
+ ...renameMap
79
+ })
88
80
  ])
89
81
  );
90
- const prelimSchema = candidateSchemas[defName];
82
+ const preferredName = preferredNames[defName];
83
+ const prelimSchema = candidateSchemas[preferredName];
91
84
  const [componentName, reuseExisting] = resolveComponentName(
92
85
  componentsSchemas,
93
86
  new Set(Object.values(renameMap)),
94
- defName,
87
+ preferredName,
95
88
  prelimSchema,
96
89
  candidateSchemas,
97
90
  direction
@@ -103,77 +96,20 @@ class OpenAPIComponentRegistry {
103
96
  }
104
97
  for (const { cleanSchema, componentName } of pendingSchemas) {
105
98
  componentsSchemas[componentName] = rewriteComponentSchemaRefs(
106
- withReferencedLocalDefs(cleanSchema, localDefs),
99
+ cleanSchema,
107
100
  renameMap
108
101
  );
109
102
  }
110
- return rewriteComponentSchemaRefs(withReferencedLocalDefs(rest, localDefs), renameMap);
103
+ return rewriteComponentSchemaRefs(rest, renameMap);
111
104
  }
112
105
  toOpenAPISchema(schema, direction) {
113
106
  return ensureJsonSchemaObject(this.hoistDefs(schema, direction));
114
107
  }
115
108
  }
116
- function visitLocalDefRefs(schema, onRef) {
117
- visitJsonSchemaRefs(schema, (ref) => {
118
- const refName = parseLocalDefRefName(ref);
119
- if (refName !== void 0) {
120
- onRef(refName);
121
- }
122
- });
123
- }
124
- function hoistReferencedLocalDefs(hoistedDefs, localDefs) {
125
- const queue = Object.values(hoistedDefs);
126
- while (queue.length > 0) {
127
- const current = queue.shift();
128
- visitLocalDefRefs(current, (refName) => {
129
- const referenced = localDefs[refName];
130
- if (referenced === void 0) {
131
- return;
132
- }
133
- hoistedDefs[refName] = referenced;
134
- delete localDefs[refName];
135
- queue.push(referenced);
136
- });
137
- }
138
- }
139
- function withReferencedLocalDefs(schema, localDefs) {
140
- const referencedLocalDefs = collectReferencedLocalDefNames(schema, localDefs);
141
- if (referencedLocalDefs.length === 0) {
142
- return schema;
143
- }
144
- const mergedDefs = {
145
- ...schema.$defs
146
- };
147
- for (const defName of referencedLocalDefs) {
148
- mergedDefs[defName] = localDefs[defName];
149
- }
150
- return {
151
- ...schema,
152
- $defs: mergedDefs
153
- };
154
- }
155
- function collectReferencedLocalDefNames(schema, localDefs) {
156
- if (Object.keys(localDefs).length === 0) {
157
- return [];
158
- }
159
- const referenced = /* @__PURE__ */ new Set();
160
- const queue = [schema];
161
- while (queue.length > 0) {
162
- const current = queue.shift();
163
- visitLocalDefRefs(current, (refName) => {
164
- if (localDefs[refName] === void 0 || referenced.has(refName)) {
165
- return;
166
- }
167
- referenced.add(refName);
168
- queue.push(localDefs[refName]);
169
- });
170
- }
171
- return [...referenced];
172
- }
173
- function resolveComponentName(componentsSchemas, claimedNames, defName, schema, candidateSchemas, direction) {
109
+ function resolveComponentName(componentsSchemas, claimedNames, preferredName, schema, candidateSchemas, direction) {
174
110
  let mintName;
175
111
  for (let i = 1; ; i++) {
176
- const [componentName, mintable, tail] = componentNameCandidate(defName, direction, i);
112
+ const [componentName, mintable, tail] = componentNameCandidate(preferredName, direction, i);
177
113
  const existingSchema = componentsSchemas[componentName];
178
114
  if (existingSchema === void 0) {
179
115
  if (mintable && !claimedNames.has(componentName)) {
@@ -191,27 +127,27 @@ function resolveComponentName(componentsSchemas, claimedNames, defName, schema,
191
127
  existingSchema,
192
128
  candidateSchemas,
193
129
  componentsSchemas,
194
- /* @__PURE__ */ new Map([[defName, componentName]]),
195
- /* @__PURE__ */ new Map([[componentName, defName]])
130
+ /* @__PURE__ */ new Map([[preferredName, componentName]]),
131
+ /* @__PURE__ */ new Map([[componentName, preferredName]])
196
132
  )) {
197
133
  return [componentName, true];
198
134
  }
199
135
  }
200
136
  }
201
- function componentNameCandidate(defName, direction, attempt) {
137
+ function componentNameCandidate(preferredName, direction, attempt) {
202
138
  if (attempt === 1) {
203
- return [defName, true, false];
139
+ return [preferredName, true, false];
204
140
  }
205
141
  if (direction !== void 0) {
206
142
  if (attempt === 2) {
207
- return [`${defName}${direction === "input" ? "Input" : "Output"}`, true, false];
143
+ return [`${preferredName}${direction === "input" ? "Input" : "Output"}`, true, false];
208
144
  }
209
145
  if (attempt === 3) {
210
- return [`${defName}${direction === "input" ? "Output" : "Input"}`, false, false];
146
+ return [`${preferredName}${direction === "input" ? "Output" : "Input"}`, false, false];
211
147
  }
212
- return [`${defName}${attempt - 2}`, true, true];
148
+ return [`${preferredName}${attempt - 2}`, true, true];
213
149
  }
214
- return [`${defName}${attempt}`, true, true];
150
+ return [`${preferredName}${attempt}`, true, true];
215
151
  }
216
152
  function definedKeysOf(object) {
217
153
  return Object.keys(object).filter((key) => object[key] !== void 0).sort();
@@ -678,13 +614,14 @@ function buildErrorResponse(ctx, operation, def) {
678
614
  status
679
615
  );
680
616
  const responseSchema = customBodySchema ?? combineJsonSchemasWithComposition("oneOf", [
681
- ...definitions.map(({ code, dataJsonSchema, dataOptional, defaultMessage }) => {
617
+ ...definitions.map(({ code, dataJsonSchema, dataOptional }) => {
682
618
  return ctx.registry.register(toErrorComponentName(code), combineJsonObjectSchemaEntries([
683
619
  ["defined", { const: true }, false],
684
620
  ["inferable", { type: "boolean" }, false],
685
621
  ["code", { const: code }, false],
686
622
  ["status", { const: status }, false],
687
- ["message", { type: "string", default: defaultMessage }, false],
623
+ // avoid using the defaultMessage here to improve component reusability
624
+ ["message", { type: "string" }, false],
688
625
  ["data", ctx.registry.hoistDefs(dataJsonSchema, "output"), dataOptional]
689
626
  ]));
690
627
  }),
@@ -811,7 +748,7 @@ class OpenAPIGenerator {
811
748
  info: options.base?.info ?? { title: "API Reference", version: "0.0.0" }
812
749
  };
813
750
  const ctx = {
814
- registry: new OpenAPIComponentRegistry(doc, options.shouldHoistDef),
751
+ registry: new OpenAPIComponentRegistry(doc, options.customComponentName),
815
752
  convertSchemas: (schemas, direction) => this.convertSchemas(schemas, direction),
816
753
  errorStatusMap: options.errorStatusMap ?? COMMON_ERROR_STATUS_MAP,
817
754
  customErrorResponseBodySchema: options.customErrorResponseBodySchema
@@ -4,7 +4,7 @@ import { Value, Promisable } from '@orpc/shared';
4
4
  import { ApiReferenceConfiguration } from '@scalar/api-reference';
5
5
  import { StandardUrl } from '@standardserver/core';
6
6
  import { SwaggerUIOptions } from 'swagger-ui';
7
- import { a as OpenAPIDocument } from '../shared/openapi.ByT4oUeY.mjs';
7
+ import { O as OpenAPIDocument } from '../shared/openapi.Bsz7d8xx.mjs';
8
8
  import '@hey-api/spec-types';
9
9
  import '@orpc/client';
10
10
 
@@ -4,7 +4,7 @@ import { Value, Promisable } from '@orpc/shared';
4
4
  import { ApiReferenceConfiguration } from '@scalar/api-reference';
5
5
  import { StandardUrl } from '@standardserver/core';
6
6
  import { SwaggerUIOptions } from 'swagger-ui';
7
- import { a as OpenAPIDocument } from '../shared/openapi.ByT4oUeY.js';
7
+ import { O as OpenAPIDocument } from '../shared/openapi.Bsz7d8xx.js';
8
8
  import '@hey-api/spec-types';
9
9
  import '@orpc/client';
10
10
 
@@ -1,7 +1,7 @@
1
1
  import { wrapAsyncIteratorPreservingEventMeta, toORPCError, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
- import { isPlainObject, isAsyncIteratorObject } from '@orpc/shared';
2
+ import { isPlainObject, NullProtoObj, isAsyncIteratorObject } from '@orpc/shared';
3
3
  import { ErrorEvent } from '@standardserver/core';
4
- import { B as BracketNotationSerializer } from './openapi.Bt87OzTt.mjs';
4
+ import { B as BracketNotationSerializer } from './openapi.s_p5sN-P.mjs';
5
5
 
6
6
  const DEFAULT_OPENAPI_METHOD = "POST";
7
7
  const DEFAULT_OPENAPI_SUCCESS_DESCRIPTION = "OK";
@@ -84,44 +84,116 @@ 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 in 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.isNaN(data) ? null : data;
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 RegExp) {
153
+ return data.toString();
154
+ }
155
+ if (data instanceof Set) {
156
+ return this.serializeValue(Array.from(data), segments, maps, blobs);
157
+ }
158
+ if (data instanceof Map) {
159
+ return this.serializeValue(Array.from(data.entries()), segments, maps, blobs);
160
+ }
161
+ }
162
+ }
163
+ }
164
+ const handlerEntries = this.handlerEntries;
165
+ if (handlerEntries) {
166
+ for (let i = 0; i < handlerEntries.length; i++) {
167
+ const handler = handlerEntries[i];
168
+ if (handler.condition(data)) {
169
+ const serialized = handler.serialize(data);
170
+ if (handler.isTerminal) {
171
+ if (serialized instanceof Blob) {
172
+ maps.push(segments.slice());
173
+ blobs.push(serialized);
174
+ }
175
+ return serialized;
176
+ }
177
+ return this.serializeValue(serialized, segments, maps, blobs);
107
178
  }
108
- const result = this.serializeValue(serialized, segments, maps, blobs);
109
- return result;
110
179
  }
111
180
  }
112
181
  if (data instanceof Blob) {
113
- maps.push(segments);
182
+ maps.push(segments.slice());
114
183
  blobs.push(data);
115
- return [data, maps, blobs];
184
+ return data;
116
185
  }
117
186
  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];
187
+ const json = [];
188
+ for (let i = 0; i < data.length; i++) {
189
+ segments.push(i);
190
+ json.push(this.serializeValue(data[i], segments, maps, blobs));
191
+ segments.pop();
192
+ }
193
+ return json;
122
194
  }
123
195
  if (isPlainObject(data)) {
124
- const json = {};
196
+ const json = new NullProtoObj();
125
197
  for (const k in data) {
126
198
  const v = data[k];
127
199
  if (k === "toJSON" && typeof v === "function") {
@@ -130,27 +202,30 @@ class OpenAPIJsonSerializer {
130
202
  if (v === void 0 && this.omitUndefinedProperties) {
131
203
  continue;
132
204
  }
133
- json[k] = this.serializeValue(v, [...segments, k], maps, blobs)[0];
205
+ segments.push(k);
206
+ json[k] = this.serializeValue(v, segments, maps, blobs);
207
+ segments.pop();
134
208
  }
135
- return [json, maps, blobs];
209
+ return json;
136
210
  }
137
- return [data, maps, blobs];
211
+ return data;
138
212
  }
139
213
  deserialize(serialized) {
140
214
  const ref = { data: serialized.json };
141
215
  if (serialized.blobs?.length) {
142
- serialized.maps.forEach((segments, i) => {
216
+ for (let i = 0; i < serialized.maps.length; i++) {
217
+ const segments = serialized.maps[i];
143
218
  let currentRef = ref;
144
219
  let preSegment = "data";
145
- segments.forEach((segment) => {
220
+ for (let j = 0; j < segments.length; j++) {
146
221
  currentRef = currentRef[preSegment];
147
- preSegment = segment;
222
+ preSegment = segments[j];
148
223
  if (!Object.hasOwn(currentRef, preSegment)) {
149
224
  throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
150
225
  }
151
- });
226
+ }
152
227
  currentRef[preSegment] = serialized.blobs[i];
153
- });
228
+ }
154
229
  }
155
230
  return ref.data;
156
231
  }
@@ -166,8 +241,6 @@ class OpenAPISerializer {
166
241
  this.defaultSerializeOptions = serialize;
167
242
  }
168
243
  serialize(data, options = {}) {
169
- const useFormDataForBlobFields = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
170
- const asFormData = options.asFormData ?? this.defaultSerializeOptions?.asFormData ?? false;
171
244
  if (!options.asFormData) {
172
245
  if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
173
246
  return data;
@@ -178,22 +251,24 @@ class OpenAPISerializer {
178
251
  if (result.value === void 0) {
179
252
  return result;
180
253
  }
181
- return { done: result.done, value: this.serializeValue(result.value, { asFormData: false, useFormDataForBlobFields: false }) };
254
+ return { done: result.done, value: this.serializeValue(result.value, false, false) };
182
255
  },
183
256
  mapError: (e) => {
184
257
  return new ErrorEvent({
185
- data: this.serializeValue(toORPCError(e).toJSON(), { asFormData: false, useFormDataForBlobFields: false }),
258
+ data: this.serializeValue(toORPCError(e).toJSON(), false, false),
186
259
  cause: e
187
260
  });
188
261
  }
189
262
  });
190
263
  }
191
264
  }
192
- return this.serializeValue(data, { useFormDataForBlobFields, asFormData });
265
+ const useFormDataForBlobFields = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
266
+ const asFormData = options.asFormData ?? this.defaultSerializeOptions?.asFormData ?? false;
267
+ return this.serializeValue(data, useFormDataForBlobFields, asFormData);
193
268
  }
194
- serializeValue(value, options) {
269
+ serializeValue(value, useFormDataForBlobFields, asFormData) {
195
270
  const { json, blobs } = this.jsonSerializer.serialize(value);
196
- if (!options.asFormData && (json instanceof Blob || json === void 0 || !blobs?.length || !options.useFormDataForBlobFields)) {
271
+ if (!asFormData && (json instanceof Blob || json === void 0 || !blobs?.length || !useFormDataForBlobFields)) {
197
272
  return json;
198
273
  }
199
274
  const form = new FormData();
@@ -2,10 +2,11 @@ import { isORPCErrorJson, createORPCErrorFromJson, ORPCError } from '@orpc/clien
2
2
  import { getRouterContract, ProcedureContract } from '@orpc/contract';
3
3
  import { unlazy } from '@orpc/server';
4
4
  import { value, pathToHttpPath, mergeHttpPath, isTypescriptObject, stringifyJSON } from '@orpc/shared';
5
- import { mergeStandardHeaders, parseStandardUrl, isStandardHeaders } from '@standardserver/core';
5
+ import { mergeStandardHeaders, parseStandardUrl } from '@standardserver/core';
6
6
  import { toStandardHeaders } from '@standardserver/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.zZH_UksW.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.0yE-t1W-.mjs';
8
8
  import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
9
+ import { s as serializeHeaders } from './openapi.BaqI61Xi.mjs';
9
10
 
10
11
  class OpenAPILinkCodecError extends TypeError {
11
12
  }
@@ -83,7 +84,7 @@ class OpenAPILinkCodec {
83
84
  \u2022 Expected an object or undefined with optional properties:
84
85
  - params (object, required when the path has dynamic params)
85
86
  - query (object)
86
- - headers (Record<string, string | string[] | undefined>)
87
+ - headers (object)
87
88
  - body (any)
88
89
 
89
90
  Actual value:
@@ -104,7 +105,7 @@ class OpenAPILinkCodec {
104
105
  }
105
106
  }
106
107
  if (input?.headers) {
107
- headers = mergeStandardHeaders(headers, input.headers);
108
+ headers = mergeStandardHeaders(headers, serializeHeaders(input.headers, this.serializer));
108
109
  }
109
110
  pathname = `${basePathname.replace(END_SLASH_REGEX, "")}${pathname}`;
110
111
  const queryString = this.serializeQueryString(input?.query, meta?.queryStyles);
@@ -324,7 +325,7 @@ function isValidDetailedInput(input) {
324
325
  if (input.query !== void 0 && !isTypescriptObject(input.query)) {
325
326
  return false;
326
327
  }
327
- if (input.headers !== void 0 && !isStandardHeaders(input.headers)) {
328
+ if (input.headers !== void 0 && !isTypescriptObject(input.headers)) {
328
329
  return false;
329
330
  }
330
331
  return true;
@@ -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.js';
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 };