@orpc/openapi 2.0.0-beta.21 → 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.
- package/README.md +5 -5
- package/dist/adapters/fetch/index.d.mts +3 -3
- package/dist/adapters/fetch/index.d.ts +3 -3
- package/dist/adapters/fetch/index.mjs +4 -4
- package/dist/adapters/node/index.d.mts +2 -2
- package/dist/adapters/node/index.d.ts +2 -2
- package/dist/adapters/node/index.mjs +3 -3
- package/dist/adapters/standard/index.d.mts +10 -46
- package/dist/adapters/standard/index.d.ts +10 -46
- package/dist/adapters/standard/index.mjs +4 -4
- package/dist/extensions/route.d.mts +2 -2
- package/dist/extensions/route.d.ts +2 -2
- package/dist/helpers/index.mjs +1 -1
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/plugins/index.d.mts +1 -1
- package/dist/plugins/index.d.ts +1 -1
- package/dist/shared/{openapi.zZH_UksW.mjs → openapi.0yE-t1W-.mjs} +113 -38
- package/dist/shared/{openapi.C-p_Q2lb.mjs → openapi.B48raJ3F.mjs} +6 -5
- package/dist/shared/openapi.BWJ1qv3c.d.ts +47 -0
- package/dist/shared/{openapi.CVgUshDP.mjs → openapi.BaqI61Xi.mjs} +88 -39
- package/dist/shared/{openapi.ByT4oUeY.d.mts → openapi.Bsz7d8xx.d.mts} +1 -1
- package/dist/shared/{openapi.ByT4oUeY.d.ts → openapi.Bsz7d8xx.d.ts} +1 -1
- package/dist/shared/{openapi.hg_rhZ4x.d.mts → openapi.COG_72WY.d.mts} +1 -1
- package/dist/shared/openapi.CTxN9oam.d.mts +47 -0
- package/dist/shared/{openapi.B6hEbRyF.d.ts → openapi.D7Fpk6aV.d.ts} +5 -3
- package/dist/shared/{openapi.BOOA-bde.d.mts → openapi.DBFXInk5.d.mts} +6 -1
- package/dist/shared/{openapi.BOOA-bde.d.ts → openapi.DBFXInk5.d.ts} +6 -1
- package/dist/shared/{openapi.BafbB3uM.d.mts → openapi.Dam82YDK.d.mts} +5 -3
- package/dist/shared/{openapi.DNNo0V-l.d.ts → openapi.Du7gMjyF.d.ts} +1 -1
- package/dist/shared/{openapi.Bt87OzTt.mjs → openapi.s_p5sN-P.mjs} +20 -15
- package/package.json +8 -8
|
@@ -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.
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
|
184
|
+
return data;
|
|
116
185
|
}
|
|
117
186
|
if (Array.isArray(data)) {
|
|
118
|
-
const json =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
-
|
|
205
|
+
segments.push(k);
|
|
206
|
+
json[k] = this.serializeValue(v, segments, maps, blobs);
|
|
207
|
+
segments.pop();
|
|
134
208
|
}
|
|
135
|
-
return
|
|
209
|
+
return json;
|
|
136
210
|
}
|
|
137
|
-
return
|
|
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.
|
|
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.
|
|
220
|
+
for (let j = 0; j < segments.length; j++) {
|
|
146
221
|
currentRef = currentRef[preSegment];
|
|
147
|
-
preSegment =
|
|
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,
|
|
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(),
|
|
258
|
+
data: this.serializeValue(toORPCError(e).toJSON(), false, false),
|
|
186
259
|
cause: e
|
|
187
260
|
});
|
|
188
261
|
}
|
|
189
262
|
});
|
|
190
263
|
}
|
|
191
264
|
}
|
|
192
|
-
|
|
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,
|
|
269
|
+
serializeValue(value, useFormDataForBlobFields, asFormData) {
|
|
195
270
|
const { json, blobs } = this.jsonSerializer.serialize(value);
|
|
196
|
-
if (!
|
|
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
|
|
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.
|
|
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 (
|
|
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 && !
|
|
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 };
|
|
@@ -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,
|
|
4
|
-
import { parseStandardUrl
|
|
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.
|
|
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
|
-
|
|
35
|
+
for (const result of lazyResults) {
|
|
36
36
|
const prefix = getOpenAPIMeta(result.router)?.prefix;
|
|
37
|
-
|
|
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
|
|
60
|
-
if (
|
|
61
|
-
|
|
59
|
+
const loading = this.resolvePendingLazyRouters(pathname);
|
|
60
|
+
if (loading !== void 0) {
|
|
61
|
+
await loading;
|
|
62
62
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
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
|
|
75
|
+
const entry = match.data;
|
|
72
76
|
return {
|
|
73
|
-
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
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
|
-
|
|
88
|
+
}
|
|
89
|
+
async loadPendingLazyRouters(pathname) {
|
|
83
90
|
for (const pending of this.pendingLazyRouters) {
|
|
84
|
-
if (
|
|
85
|
-
|
|
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
|
-
|
|
94
|
-
if (
|
|
95
|
-
|
|
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
|
|
184
|
-
- headers (
|
|
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
|
|
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 && !
|
|
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,
|
|
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,
|
|
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 {
|
|
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.
|
|
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
|
|
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
|
|
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
|
}
|