@orpc/openapi 1.14.5 → 2.0.0-beta.1

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 (48) hide show
  1. package/README.md +75 -109
  2. package/dist/adapters/fetch/index.d.mts +20 -16
  3. package/dist/adapters/fetch/index.d.ts +20 -16
  4. package/dist/adapters/fetch/index.mjs +24 -8
  5. package/dist/adapters/node/index.d.mts +8 -13
  6. package/dist/adapters/node/index.d.ts +8 -13
  7. package/dist/adapters/node/index.mjs +10 -7
  8. package/dist/adapters/standard/index.d.mts +46 -16
  9. package/dist/adapters/standard/index.d.ts +46 -16
  10. package/dist/adapters/standard/index.mjs +9 -6
  11. package/dist/extensions/route.d.mts +43 -0
  12. package/dist/extensions/route.d.ts +43 -0
  13. package/dist/extensions/route.mjs +14 -0
  14. package/dist/helpers/index.d.mts +51 -0
  15. package/dist/helpers/index.d.ts +51 -0
  16. package/dist/helpers/index.mjs +39 -0
  17. package/dist/index.d.mts +92 -111
  18. package/dist/index.d.ts +92 -111
  19. package/dist/index.mjs +894 -34
  20. package/dist/plugins/index.d.mts +55 -51
  21. package/dist/plugins/index.d.ts +55 -51
  22. package/dist/plugins/index.mjs +147 -142
  23. package/dist/shared/openapi.B2SK0ZAr.mjs +359 -0
  24. package/dist/shared/openapi.B9PQzqBn.mjs +49 -0
  25. package/dist/shared/openapi.BQzzr4-4.d.ts +299 -0
  26. package/dist/shared/openapi.BcEtAxQj.d.mts +299 -0
  27. package/dist/shared/openapi.Bt87OzTt.mjs +131 -0
  28. package/dist/shared/openapi.C7m7NAmH.d.mts +142 -0
  29. package/dist/shared/openapi.C7m7NAmH.d.ts +142 -0
  30. package/dist/shared/openapi.C9Olbxd5.d.ts +75 -0
  31. package/dist/shared/openapi.CYgMBSUF.d.mts +18 -0
  32. package/dist/shared/openapi.CYgMBSUF.d.ts +18 -0
  33. package/dist/shared/openapi.CcyUEuTs.mjs +313 -0
  34. package/dist/shared/openapi.DmAa7YPO.mjs +275 -0
  35. package/dist/shared/openapi.Drd1OtzG.d.mts +75 -0
  36. package/package.json +29 -23
  37. package/dist/adapters/aws-lambda/index.d.mts +0 -20
  38. package/dist/adapters/aws-lambda/index.d.ts +0 -20
  39. package/dist/adapters/aws-lambda/index.mjs +0 -18
  40. package/dist/adapters/fastify/index.d.mts +0 -23
  41. package/dist/adapters/fastify/index.d.ts +0 -23
  42. package/dist/adapters/fastify/index.mjs +0 -18
  43. package/dist/shared/openapi.BB-W-NKv.mjs +0 -204
  44. package/dist/shared/openapi.BGy4N6eR.d.mts +0 -120
  45. package/dist/shared/openapi.BGy4N6eR.d.ts +0 -120
  46. package/dist/shared/openapi.BwdtJjDu.mjs +0 -878
  47. package/dist/shared/openapi.DwaweYRb.d.mts +0 -54
  48. package/dist/shared/openapi.DwaweYRb.d.ts +0 -54
@@ -0,0 +1,313 @@
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, tryDecodeURIComponent, isPlainObject, stringifyJSON, parseEmptyableJSON, isTypescriptObject, NullProtoObj } from '@orpc/shared';
4
+ import { parseStandardUrl, isStandardHeaders } from '@standardserver/core';
5
+ import { D as DEFAULT_OPENAPI_METHOD, g as getDynamicPathParams, O as OpenAPISerializer, a as DEFAULT_OPENAPI_INPUT_STRUCTURE, b as DEFAULT_OPENAPI_OUTPUT_STRUCTURE } from './openapi.DmAa7YPO.mjs';
6
+ import { g as getOpenAPIMeta } from './openapi.B9PQzqBn.mjs';
7
+ import { createRouter, addRoute, findRoute, routeToRegExp } from 'rou3';
8
+
9
+ class OpenAPIMatcher {
10
+ filter;
11
+ rootRouter;
12
+ tree = createRouter();
13
+ pendingLazyRouters = [];
14
+ constructor(router, options = {}) {
15
+ this.filter = options.filter ?? true;
16
+ this.rootRouter = router;
17
+ this.index(router);
18
+ }
19
+ index(router, path = []) {
20
+ const lazyResults = walkProcedureContractsSync(router, (contract, path2) => {
21
+ if (!value(this.filter, contract, path2)) {
22
+ return;
23
+ }
24
+ const meta = getOpenAPIMeta(contract);
25
+ const method = meta?.method ?? DEFAULT_OPENAPI_METHOD;
26
+ const postHttpPath = meta?.path ?? pathToHttpPath(path2);
27
+ 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
33
+ });
34
+ }, path);
35
+ this.pendingLazyRouters.push(...lazyResults.map((result) => {
36
+ const prefix = getOpenAPIMeta(result.router)?.prefix;
37
+ return {
38
+ ...result,
39
+ matcher: prefix ? toRou3PrefixMatcher(prefix) : void 0
40
+ };
41
+ }));
42
+ }
43
+ async match(method, pathname, prefix) {
44
+ if (prefix) {
45
+ if (!pathname.startsWith(prefix)) {
46
+ return void 0;
47
+ }
48
+ const charAfterPrefix = pathname[prefix.length];
49
+ if (charAfterPrefix === "/") {
50
+ pathname = pathname.slice(prefix.length);
51
+ } else if (charAfterPrefix === void 0) {
52
+ pathname = "/";
53
+ } else if (prefix[prefix.length - 1] === "/") {
54
+ pathname = pathname.slice(prefix.length - 1);
55
+ } else {
56
+ return void 0;
57
+ }
58
+ }
59
+ const result = await this.matchPathname(method, pathname);
60
+ if (!result && pathname.includes("%")) {
61
+ return this.matchPathname(method, normalizeHttpPath(pathname));
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) {
69
+ return void 0;
70
+ }
71
+ const procedure = await this.resolveProcedure(match.data);
72
+ return {
73
+ path: match.data.path,
74
+ procedure,
75
+ params: match.params ? decodeParams(match.params) : void 0
76
+ };
77
+ }
78
+ async resolvePendingLazyRouters(pathname) {
79
+ if (!this.pendingLazyRouters.length) {
80
+ return;
81
+ }
82
+ const stillPending = [];
83
+ 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);
89
+ }
90
+ }
91
+ this.pendingLazyRouters = stillPending;
92
+ }
93
+ async resolveProcedure(entry) {
94
+ if (entry.procedure) {
95
+ return entry.procedure;
96
+ }
97
+ const { default: maybeProcedure } = await unlazy(getRouter(this.rootRouter, entry.path));
98
+ if (!(maybeProcedure instanceof Procedure)) {
99
+ throw new TypeError(
100
+ `[Contract-First] Missing or invalid implementation for procedure at path: "${entry.path.join(".")}". Ensure the procedure is correctly implemented and matches its contract.`
101
+ );
102
+ }
103
+ entry.procedure = createContractProcedure(maybeProcedure, entry.contract);
104
+ return entry.procedure;
105
+ }
106
+ }
107
+ function toRou3Pattern(path) {
108
+ const params = getDynamicPathParams(path);
109
+ if (!params?.length) {
110
+ return path;
111
+ }
112
+ for (let i = params.length - 1; i >= 0; i--) {
113
+ const param = params[i];
114
+ const pattern = param.allowsSlash ? `**:${param.parameterName}` : `:${param.parameterName}`;
115
+ path = path.slice(0, param.startIndex) + pattern + path.slice(param.startIndex + param.segment.length);
116
+ }
117
+ return path;
118
+ }
119
+ function toRou3PrefixMatcher(path) {
120
+ const pattern = toRou3Pattern(path);
121
+ return routeToRegExp(pattern === "/" ? "/**" : `${pattern}/**`);
122
+ }
123
+ function decodeParams(params) {
124
+ return Object.fromEntries(Object.entries(params).map(([key, val]) => [key, tryDecodeURIComponent(val)]));
125
+ }
126
+
127
+ class OpenAPIHandlerCodecError extends TypeError {
128
+ }
129
+ class OpenAPIHandlerCodec {
130
+ matcher;
131
+ serializer;
132
+ errorStatusMap;
133
+ customErrorResponseBodySerializer;
134
+ constructor(router, options = {}) {
135
+ this.matcher = new OpenAPIMatcher(router, options);
136
+ this.serializer = options.serializer ?? new OpenAPISerializer();
137
+ this.errorStatusMap = options.errorStatusMap ?? COMMON_ERROR_STATUS_MAP;
138
+ this.customErrorResponseBodySerializer = options.customErrorResponseBodyEncoder;
139
+ }
140
+ async resolveProcedure(request, options) {
141
+ const [pathname, search] = parseStandardUrl(request.url);
142
+ const matched = await this.matcher.match(request.method, pathname, options.prefix);
143
+ if (!matched) {
144
+ return void 0;
145
+ }
146
+ return {
147
+ procedure: matched.procedure,
148
+ path: matched.path,
149
+ decodeInput: async () => {
150
+ const meta = getOpenAPIMeta(matched.procedure);
151
+ const inputStructure = meta?.inputStructure ?? DEFAULT_OPENAPI_INPUT_STRUCTURE;
152
+ const params = this.deserializeParams(matched.params, meta?.paramsStyles);
153
+ const query = this.deserializeQuery(search, meta?.queryStyles);
154
+ if (inputStructure === "compact") {
155
+ const data = request.method === "GET" ? query : this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint));
156
+ if (data === void 0) {
157
+ return params;
158
+ }
159
+ if (!params || Object.keys(params).length < 1) {
160
+ return data;
161
+ }
162
+ if (isPlainObject(data)) {
163
+ return {
164
+ ...params,
165
+ ...data
166
+ };
167
+ }
168
+ return data;
169
+ }
170
+ return {
171
+ params,
172
+ query,
173
+ headers: request.headers,
174
+ body: this.serializer.deserialize(await request.resolveBody(meta?.requestBodyHint))
175
+ };
176
+ }
177
+ };
178
+ }
179
+ /**
180
+ * @throws {Error} If `outputStructure` is "detailed" and the output doesn't match the expected structure.
181
+ */
182
+ encodeOutput(output, procedure, path, _options) {
183
+ const meta = getOpenAPIMeta(procedure);
184
+ const successStatus = meta?.successStatus ?? DEFAULT_SUCCESS_STATUS;
185
+ const outputStructure = meta?.outputStructure ?? DEFAULT_OPENAPI_OUTPUT_STRUCTURE;
186
+ if (outputStructure === "compact") {
187
+ return {
188
+ status: successStatus,
189
+ headers: {},
190
+ body: this.serializer.serialize(output)
191
+ };
192
+ }
193
+ if (!isValidDetailedOutput(output)) {
194
+ throw new OpenAPIHandlerCodecError(`
195
+ Invalid "detailed" output structure returned by procedure (${path.join(".")}):
196
+ \u2022 Expected an object with optional properties:
197
+ - status (number 200-399)
198
+ - headers (Record<string, string | string[] | undefined>)
199
+ - body (any)
200
+ \u2022 No extra keys allowed.
201
+
202
+ Actual value:
203
+ ${stringifyJSON(output)}
204
+ `);
205
+ }
206
+ return {
207
+ status: output.status ?? successStatus,
208
+ headers: output.headers ?? {},
209
+ body: this.serializer.serialize(output.body)
210
+ };
211
+ }
212
+ encodeError(error, _procedure, _path, _options) {
213
+ const status = this.errorStatusMap[error.code] ?? DEFAULT_ERROR_STATUS;
214
+ return {
215
+ status,
216
+ headers: {},
217
+ body: this.serializer.serialize(this.customErrorResponseBodySerializer?.(error) ?? error.toJSON())
218
+ };
219
+ }
220
+ deserializeQuery(search, styles) {
221
+ const searchParams = new URLSearchParams(search);
222
+ const parsed = this.serializer.deserialize(searchParams);
223
+ if (!styles || !isPlainObject(parsed)) {
224
+ return parsed;
225
+ }
226
+ Object.entries(styles).forEach(([key, hint]) => {
227
+ if (hint === void 0) {
228
+ return;
229
+ }
230
+ const values = searchParams.getAll(key);
231
+ let parsedValue;
232
+ if (hint === "primitive") {
233
+ parsedValue = values.at(-1);
234
+ } else if (hint === "array") {
235
+ parsedValue = values;
236
+ } else if (hint === "comma-delimited-array") {
237
+ parsedValue = decodeDelimitedArray(values.at(-1), ",");
238
+ } else if (hint === "comma-delimited-object") {
239
+ parsedValue = decodeDelimitedObject(values.at(-1), ",");
240
+ } else if (hint === "space-delimited-array") {
241
+ parsedValue = decodeDelimitedArray(values.at(-1), " ");
242
+ } else if (hint === "space-delimited-object") {
243
+ parsedValue = decodeDelimitedObject(values.at(-1), " ");
244
+ } else if (hint === "pipe-delimited-array") {
245
+ parsedValue = decodeDelimitedArray(values.at(-1), "|");
246
+ } else if (hint === "pipe-delimited-object") {
247
+ parsedValue = decodeDelimitedObject(values.at(-1), "|");
248
+ } else {
249
+ const last = values.at(-1);
250
+ try {
251
+ parsedValue = parseEmptyableJSON(last);
252
+ } catch {
253
+ parsedValue = last;
254
+ }
255
+ }
256
+ parsed[key] = this.serializer.deserialize(parsedValue);
257
+ });
258
+ return parsed;
259
+ }
260
+ deserializeParams(params, styles) {
261
+ if (!params || !styles) {
262
+ return params;
263
+ }
264
+ const parsed = { ...params };
265
+ Object.entries(styles).forEach(([key, hint]) => {
266
+ if (hint === void 0 || hint === "primitive") {
267
+ return;
268
+ }
269
+ const value = params[key];
270
+ if (hint === "comma-delimited-array") {
271
+ parsed[key] = decodeDelimitedArray(value, ",");
272
+ } else {
273
+ parsed[key] = decodeDelimitedObject(value, ",");
274
+ }
275
+ });
276
+ return parsed;
277
+ }
278
+ }
279
+ function isValidDetailedOutput(output) {
280
+ if (!isTypescriptObject(output)) {
281
+ return false;
282
+ }
283
+ if (Object.keys(output).some((key) => key !== "status" && key !== "headers" && key !== "body")) {
284
+ return false;
285
+ }
286
+ if (output.status !== void 0 && (typeof output.status !== "number" || !Number.isInteger(output.status) || output.status < 200 || output.status > 399)) {
287
+ return false;
288
+ }
289
+ if (output.headers !== void 0 && !isStandardHeaders(output.headers)) {
290
+ return false;
291
+ }
292
+ return true;
293
+ }
294
+ function decodeDelimitedArray(value, delimiter) {
295
+ if (value === void 0) {
296
+ return void 0;
297
+ }
298
+ return value.split(delimiter);
299
+ }
300
+ function decodeDelimitedObject(value, delimiter) {
301
+ if (value === void 0) {
302
+ return void 0;
303
+ }
304
+ const obj = new NullProtoObj();
305
+ const parts = value.split(delimiter);
306
+ for (let i = 0; i < parts.length; i += 2) {
307
+ const key = parts[i];
308
+ obj[key] = parts[i + 1];
309
+ }
310
+ return obj;
311
+ }
312
+
313
+ export { OpenAPIHandlerCodec as O, OpenAPIHandlerCodecError as a, OpenAPIMatcher as b };
@@ -0,0 +1,275 @@
1
+ import { wrapEventIteratorPreservingMeta, toORPCError, isORPCErrorJson, createORPCErrorFromJson } from '@orpc/client';
2
+ import { isPlainObject, isAsyncIteratorObject } from '@orpc/shared';
3
+ import { ErrorEvent } from '@standardserver/core';
4
+ import { B as BracketNotationSerializer } from './openapi.Bt87OzTt.mjs';
5
+
6
+ const DEFAULT_OPENAPI_METHOD = "POST";
7
+ const DEFAULT_OPENAPI_SUCCESS_DESCRIPTION = "OK";
8
+ const DEFAULT_OPENAPI_INPUT_STRUCTURE = "compact";
9
+ const DEFAULT_OPENAPI_OUTPUT_STRUCTURE = "compact";
10
+
11
+ const DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS = {
12
+ undefined: {
13
+ condition(data) {
14
+ return data === void 0;
15
+ },
16
+ serialize() {
17
+ return null;
18
+ },
19
+ isTerminal: true
20
+ },
21
+ bigint: {
22
+ condition(data) {
23
+ return typeof data === "bigint";
24
+ },
25
+ serialize(data) {
26
+ return data.toString();
27
+ },
28
+ isTerminal: true
29
+ },
30
+ date: {
31
+ condition(data) {
32
+ return data instanceof Date;
33
+ },
34
+ serialize(data) {
35
+ if (Number.isNaN(data.getTime())) {
36
+ return null;
37
+ }
38
+ return data.toISOString();
39
+ },
40
+ isTerminal: true
41
+ },
42
+ nan: {
43
+ condition(data) {
44
+ return typeof data === "number" && Number.isNaN(data);
45
+ },
46
+ serialize() {
47
+ return null;
48
+ },
49
+ isTerminal: true
50
+ },
51
+ url: {
52
+ condition(data) {
53
+ return data instanceof URL;
54
+ },
55
+ serialize(data) {
56
+ return data.toString();
57
+ },
58
+ isTerminal: true
59
+ },
60
+ regexp: {
61
+ condition(data) {
62
+ return data instanceof RegExp;
63
+ },
64
+ serialize(data) {
65
+ return data.toString();
66
+ },
67
+ isTerminal: true
68
+ },
69
+ set: {
70
+ condition(data) {
71
+ return data instanceof Set;
72
+ },
73
+ serialize(data) {
74
+ return Array.from(data);
75
+ }
76
+ },
77
+ map: {
78
+ condition(data) {
79
+ return data instanceof Map;
80
+ },
81
+ serialize(data) {
82
+ return Array.from(data.entries());
83
+ }
84
+ }
85
+ };
86
+ class OpenAPIJsonSerializer {
87
+ handlers;
88
+ omitUndefinedProperties;
89
+ constructor(options = {}) {
90
+ this.handlers = {
91
+ ...DEFAULT_OPEN_API_JSON_SERIALIZER_HANDLERS,
92
+ ...options.handlers
93
+ };
94
+ this.omitUndefinedProperties = options.omitUndefinedProperties !== false;
95
+ }
96
+ serialize(data) {
97
+ const [json, maps, blobs] = this.serializeValue(data, [], [], []);
98
+ return { json, maps, blobs };
99
+ }
100
+ 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];
107
+ }
108
+ const result = this.serializeValue(serialized, segments, maps, blobs);
109
+ return result;
110
+ }
111
+ }
112
+ if (data instanceof Blob) {
113
+ maps.push(segments);
114
+ blobs.push(data);
115
+ return [data, maps, blobs];
116
+ }
117
+ 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];
122
+ }
123
+ if (isPlainObject(data)) {
124
+ const json = {};
125
+ for (const k in data) {
126
+ const v = data[k];
127
+ if (k === "toJSON" && typeof v === "function") {
128
+ continue;
129
+ }
130
+ if (v === void 0 && this.omitUndefinedProperties) {
131
+ continue;
132
+ }
133
+ json[k] = this.serializeValue(v, [...segments, k], maps, blobs)[0];
134
+ }
135
+ return [json, maps, blobs];
136
+ }
137
+ return [data, maps, blobs];
138
+ }
139
+ deserialize(serialized) {
140
+ const ref = { data: serialized.json };
141
+ if (serialized.blobs?.length) {
142
+ serialized.maps.forEach((segments, i) => {
143
+ let currentRef = ref;
144
+ let preSegment = "data";
145
+ segments.forEach((segment) => {
146
+ currentRef = currentRef[preSegment];
147
+ preSegment = segment;
148
+ if (!Object.hasOwn(currentRef, preSegment)) {
149
+ throw new Error(`Security error: Invalid serialized data. Segment "${preSegment}" does not exist.`);
150
+ }
151
+ });
152
+ currentRef[preSegment] = serialized.blobs[i];
153
+ });
154
+ }
155
+ return ref.data;
156
+ }
157
+ }
158
+
159
+ class OpenAPISerializer {
160
+ jsonSerializer;
161
+ bracketNotation;
162
+ defaultSerializeOptions;
163
+ constructor({ bracketNotation, serialize, ...options } = {}) {
164
+ this.jsonSerializer = new OpenAPIJsonSerializer(options);
165
+ this.bracketNotation = new BracketNotationSerializer(bracketNotation);
166
+ this.defaultSerializeOptions = serialize;
167
+ }
168
+ serialize(data, options = {}) {
169
+ const useFormDataForBlobFields = options.useFormDataForBlobFields ?? this.defaultSerializeOptions?.useFormDataForBlobFields ?? true;
170
+ const asFormData = options.asFormData ?? this.defaultSerializeOptions?.asFormData ?? false;
171
+ if (!options.asFormData) {
172
+ if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
173
+ return data;
174
+ }
175
+ if (isAsyncIteratorObject(data)) {
176
+ return wrapEventIteratorPreservingMeta(data, {
177
+ mapResult: (result) => {
178
+ if (result.value === void 0) {
179
+ return result;
180
+ }
181
+ return { done: result.done, value: this.serializeValue(result.value, { asFormData: false, useFormDataForBlobFields: false }) };
182
+ },
183
+ mapError: (e) => {
184
+ return new ErrorEvent({
185
+ data: this.serializeValue(toORPCError(e).toJSON(), { asFormData: false, useFormDataForBlobFields: false }),
186
+ cause: e
187
+ });
188
+ }
189
+ });
190
+ }
191
+ }
192
+ return this.serializeValue(data, { useFormDataForBlobFields, asFormData });
193
+ }
194
+ serializeValue(value, options) {
195
+ const { json, blobs } = this.jsonSerializer.serialize(value);
196
+ if (!options.asFormData && (json instanceof Blob || json === void 0 || !blobs?.length || !options.useFormDataForBlobFields)) {
197
+ return json;
198
+ }
199
+ const form = new FormData();
200
+ for (const [path, value2] of this.bracketNotation.serialize(json)) {
201
+ if (value2 instanceof Blob) {
202
+ form.append(path, value2);
203
+ } else if (value2 !== void 0 && value2 !== null) {
204
+ form.append(path, String(value2));
205
+ }
206
+ }
207
+ return form;
208
+ }
209
+ deserialize(data) {
210
+ if (data === void 0 || data instanceof ReadableStream || data instanceof Blob) {
211
+ return data;
212
+ }
213
+ if (isAsyncIteratorObject(data)) {
214
+ return wrapEventIteratorPreservingMeta(data, {
215
+ mapResult: (result) => {
216
+ if (result.value === void 0) {
217
+ return result;
218
+ }
219
+ return { done: result.done, value: this.jsonSerializer.deserialize({ json: result.value }) };
220
+ },
221
+ mapError: (e) => {
222
+ if (e instanceof ErrorEvent) {
223
+ const deserialized = this.jsonSerializer.deserialize({ json: e.data });
224
+ if (isORPCErrorJson(deserialized)) {
225
+ return createORPCErrorFromJson(deserialized, { cause: e });
226
+ }
227
+ }
228
+ return e;
229
+ }
230
+ });
231
+ }
232
+ if (data instanceof URLSearchParams || data instanceof FormData) {
233
+ data = this.bracketNotation.deserialize(Array.from(data.entries()));
234
+ }
235
+ return this.jsonSerializer.deserialize({ json: data });
236
+ }
237
+ }
238
+
239
+ const PARAMETER_NAME_REGEX = /^[\w-]+$/;
240
+ function getDynamicPathParams(path) {
241
+ if (!path.includes("{")) {
242
+ return void 0;
243
+ }
244
+ const len = path.length;
245
+ let params;
246
+ let index = 1;
247
+ while (index < len) {
248
+ const segmentStart = index;
249
+ const slashPos = path.indexOf("/", index);
250
+ const segmentEnd = slashPos === -1 ? len : slashPos;
251
+ if (segmentEnd > segmentStart && path.charCodeAt(segmentStart) === 123 && path.charCodeAt(segmentEnd - 1) === 125) {
252
+ let parameterStart = segmentStart + 1;
253
+ let allowsSlash = false;
254
+ const operator = path.charCodeAt(parameterStart);
255
+ if (operator === 43) {
256
+ allowsSlash = true;
257
+ parameterStart++;
258
+ }
259
+ const parameterName = path.slice(parameterStart, segmentEnd - 1);
260
+ if (PARAMETER_NAME_REGEX.test(parameterName)) {
261
+ params ??= [];
262
+ params.push({
263
+ segment: path.slice(segmentStart, segmentEnd),
264
+ startIndex: segmentStart,
265
+ parameterName,
266
+ allowsSlash
267
+ });
268
+ }
269
+ }
270
+ index = segmentEnd + 1;
271
+ }
272
+ return params;
273
+ }
274
+
275
+ export { DEFAULT_OPENAPI_METHOD as D, OpenAPISerializer as O, DEFAULT_OPENAPI_INPUT_STRUCTURE as a, DEFAULT_OPENAPI_OUTPUT_STRUCTURE as b, DEFAULT_OPENAPI_SUCCESS_DESCRIPTION as c, OpenAPIJsonSerializer as d, getDynamicPathParams as g };
@@ -0,0 +1,75 @@
1
+ import { AnyORPCError } from '@orpc/client';
2
+ import { AnyProcedure, AnyRouter, Context } from '@orpc/server';
3
+ import { StandardHandlerCodec, StandardHandlerHandleOptions, StandardHandlerCodecResolvedProcedure } from '@orpc/server/standard';
4
+ import { Value, Promisable } from '@orpc/shared';
5
+ import { StandardLazyRequest, StandardResponse } from '@standardserver/core';
6
+ import { AnyProcedureContract } from '@orpc/contract';
7
+ import { O as OpenAPISerializer } from './openapi.C7m7NAmH.mjs';
8
+
9
+ interface OpenAPIMatcherOptions {
10
+ /**
11
+ * Filter which procedures are exposed for matching. Return `false` to exclude.
12
+ *
13
+ * @default true
14
+ */
15
+ filter?: Value<boolean, [contract: AnyProcedureContract | AnyProcedure, path: string[]]>;
16
+ }
17
+ declare class OpenAPIMatcher {
18
+ private readonly filter;
19
+ private readonly rootRouter;
20
+ private readonly tree;
21
+ private pendingLazyRouters;
22
+ constructor(router: AnyRouter, options?: OpenAPIMatcherOptions);
23
+ private index;
24
+ match(method: string, pathname: `/${string}`, prefix: `/${string}` | undefined): Promise<{
25
+ path: string[];
26
+ procedure: AnyProcedure;
27
+ params?: Record<string, string> | undefined;
28
+ } | undefined>;
29
+ private matchPathname;
30
+ private resolvePendingLazyRouters;
31
+ private resolveProcedure;
32
+ }
33
+
34
+ declare class OpenAPIHandlerCodecError extends TypeError {
35
+ }
36
+ interface OpenAPIHandlerCodecOptions<_T extends Context> extends OpenAPIMatcherOptions {
37
+ /**
38
+ * Override the default OpenAPI serializer.
39
+ */
40
+ serializer?: Pick<OpenAPISerializer, keyof OpenAPISerializer>;
41
+ /**
42
+ * Mapping ORPCError Code -> HTTP Status Code
43
+ *
44
+ * @default COMMON_ERROR_STATUS_MAP, DEFAULT_ERROR_STATUS
45
+ */
46
+ errorStatusMap?: Record<string, number> | undefined;
47
+ /**
48
+ * Customize how an ORPC error is serialized into a response body.
49
+ * Use this if your API needs a different error output structure.
50
+ *
51
+ * @remarks
52
+ * - Return `null | undefined` to fallback to default behavior
53
+ *
54
+ * @default ((e) => e.toJSON())
55
+ */
56
+ customErrorResponseBodyEncoder?: (error: AnyORPCError) => unknown;
57
+ }
58
+ declare class OpenAPIHandlerCodec<T extends Context> implements StandardHandlerCodec<T> {
59
+ private readonly matcher;
60
+ private readonly serializer;
61
+ private readonly errorStatusMap;
62
+ private readonly customErrorResponseBodySerializer;
63
+ constructor(router: AnyRouter, options?: OpenAPIHandlerCodecOptions<T>);
64
+ resolveProcedure(request: StandardLazyRequest, options: StandardHandlerHandleOptions<T>): Promise<StandardHandlerCodecResolvedProcedure | undefined>;
65
+ /**
66
+ * @throws {Error} If `outputStructure` is "detailed" and the output doesn't match the expected structure.
67
+ */
68
+ encodeOutput(output: unknown, procedure: AnyProcedure, path: string[], _options: StandardHandlerHandleOptions<T>): Promisable<StandardResponse>;
69
+ encodeError(error: AnyORPCError, _procedure: AnyProcedure, _path: string[], _options: StandardHandlerHandleOptions<T>): Promisable<StandardResponse>;
70
+ private deserializeQuery;
71
+ private deserializeParams;
72
+ }
73
+
74
+ export { OpenAPIHandlerCodec as a, OpenAPIHandlerCodecError as b, OpenAPIMatcher as c };
75
+ export type { OpenAPIHandlerCodecOptions as O, OpenAPIMatcherOptions as d };