@rvoh/psychic 0.36.0-beta.1 → 0.37.0-beta.3
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/dist/cjs/src/controller/index.js +18 -12
- package/dist/cjs/src/openapi-renderer/app.js +16 -15
- package/dist/cjs/src/openapi-renderer/body-segment.js +3 -6
- package/dist/cjs/src/openapi-renderer/endpoint.js +56 -103
- package/dist/cjs/src/openapi-renderer/helpers/{suppressResponseEnums.js → suppressResponseEnumsConfig.js} +2 -2
- package/dist/cjs/src/psychic-app/index.js +0 -1
- package/dist/cjs/src/server/index.js +1 -35
- package/dist/esm/src/controller/index.js +19 -13
- package/dist/esm/src/openapi-renderer/app.js +17 -16
- package/dist/esm/src/openapi-renderer/body-segment.js +3 -6
- package/dist/esm/src/openapi-renderer/endpoint.js +57 -104
- package/dist/esm/src/openapi-renderer/helpers/{suppressResponseEnums.js → suppressResponseEnumsConfig.js} +1 -1
- package/dist/esm/src/psychic-app/index.js +0 -1
- package/dist/esm/src/server/index.js +1 -35
- package/dist/types/src/controller/index.d.ts +3 -1
- package/dist/types/src/openapi-renderer/body-segment.d.ts +4 -7
- package/dist/types/src/openapi-renderer/endpoint.d.ts +17 -21
- package/dist/types/src/openapi-renderer/helpers/{schemaDelimiter.d.ts → suppressResponseEnumsConfig.d.ts} +1 -1
- package/dist/types/src/psychic-app/index.d.ts +0 -53
- package/dist/types/src/server/index.d.ts +0 -1
- package/package.json +2 -5
- package/dist/cjs/src/openapi-renderer/helpers/schemaDelimiter.js +0 -13
- package/dist/esm/src/openapi-renderer/helpers/schemaDelimiter.js +0 -7
- package/dist/types/src/openapi-renderer/helpers/suppressResponseEnums.d.ts +0 -4
|
@@ -193,12 +193,20 @@ class PsychicController {
|
|
|
193
193
|
session;
|
|
194
194
|
config;
|
|
195
195
|
action;
|
|
196
|
+
renderOpts;
|
|
196
197
|
constructor(req, res, { config, action, }) {
|
|
197
198
|
this.req = req;
|
|
198
199
|
this.res = res;
|
|
199
200
|
this.config = config;
|
|
200
201
|
this.session = new index_js_1.default(req, res);
|
|
201
202
|
this.action = action;
|
|
203
|
+
// TODO: read casing from Dream app config
|
|
204
|
+
this.renderOpts = {
|
|
205
|
+
casing: 'camel',
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
get headers() {
|
|
209
|
+
return this.req.headers;
|
|
202
210
|
}
|
|
203
211
|
get params() {
|
|
204
212
|
const params = {
|
|
@@ -262,24 +270,25 @@ class PsychicController {
|
|
|
262
270
|
return data;
|
|
263
271
|
const dreamApp = dream_1.DreamApp.getOrFail();
|
|
264
272
|
const psychicControllerClass = this.constructor;
|
|
273
|
+
// if we already have a serializer, let's just render it
|
|
274
|
+
if (data instanceof dream_1.DreamSerializerBuilder || data instanceof dream_1.ObjectSerializerBuilder) {
|
|
275
|
+
return data.render(this.defaultSerializerPassthrough, this.renderOpts);
|
|
276
|
+
}
|
|
265
277
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access
|
|
266
278
|
const lookup = exports.controllerSerializerIndex.lookupModel(this.constructor, data.constructor);
|
|
267
279
|
if (lookup?.length) {
|
|
268
280
|
const serializer = lookup?.[1];
|
|
269
281
|
if ((0, dream_1.isDreamSerializer)(serializer)) {
|
|
270
|
-
return new dream_1.SerializerRenderer(
|
|
271
282
|
// passthrough data going into the serializer is the argument that gets
|
|
272
283
|
// used in the custom attribute callback function
|
|
273
|
-
serializer(data, this.defaultSerializerPassthrough)
|
|
274
|
-
// passthrough data must be passed both into the serializer and
|
|
284
|
+
return serializer(data, this.defaultSerializerPassthrough).render(
|
|
285
|
+
// passthrough data must be passed both into the serializer and render
|
|
275
286
|
// because, if the serializer does accept passthrough data, then passing it in is how
|
|
276
287
|
// it gets into the serializer, but if it does not accept passthrough data, and therefore
|
|
277
288
|
// does not pass it into the call to DreamSerializer/ObjectSerializer,
|
|
278
289
|
// then it would be lost to serializers rendered via rendersOne/Many, and SerializerRenderer
|
|
279
290
|
// handles passing its passthrough data into those
|
|
280
|
-
this.defaultSerializerPassthrough,
|
|
281
|
-
casing: 'camel',
|
|
282
|
-
}).render();
|
|
291
|
+
this.defaultSerializerPassthrough, this.renderOpts);
|
|
283
292
|
}
|
|
284
293
|
}
|
|
285
294
|
else {
|
|
@@ -291,19 +300,16 @@ class PsychicController {
|
|
|
291
300
|
if (serializerKey && Object.prototype.hasOwnProperty.call(dreamApp.serializers, serializerKey)) {
|
|
292
301
|
const serializer = dreamApp.serializers[serializerKey];
|
|
293
302
|
if (serializer && (0, dream_1.isDreamSerializer)(serializer)) {
|
|
294
|
-
return new dream_1.SerializerRenderer(
|
|
295
303
|
// passthrough data going into the serializer is the argument that gets
|
|
296
304
|
// used in the custom attribute callback function
|
|
297
|
-
serializer(data, this.defaultSerializerPassthrough)
|
|
298
|
-
// passthrough data must be passed both into the serializer and
|
|
305
|
+
return serializer(data, this.defaultSerializerPassthrough).render(
|
|
306
|
+
// passthrough data must be passed both into the serializer and render
|
|
299
307
|
// because, if the serializer does accept passthrough data, then passing it in is how
|
|
300
308
|
// it gets into the serializer, but if it does not accept passthrough data, and therefore
|
|
301
309
|
// does not pass it into the call to DreamSerializer/ObjectSerializer,
|
|
302
310
|
// then it would be lost to serializers rendered via rendersOne/Many, and SerializerRenderer
|
|
303
311
|
// handles passing its passthrough data into those
|
|
304
|
-
this.defaultSerializerPassthrough,
|
|
305
|
-
casing: 'camel',
|
|
306
|
-
}).render();
|
|
312
|
+
this.defaultSerializerPassthrough, this.renderOpts);
|
|
307
313
|
}
|
|
308
314
|
else {
|
|
309
315
|
throw new Error(`
|
|
@@ -27,7 +27,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
const dream_1 = require("@rvoh/dream");
|
|
30
|
-
const lodash_es_1 = require("lodash-es");
|
|
31
30
|
const fs = __importStar(require("node:fs/promises"));
|
|
32
31
|
const node_util_1 = require("node:util");
|
|
33
32
|
const UnexpectedUndefined_js_1 = __importDefault(require("../error/UnexpectedUndefined.js"));
|
|
@@ -36,8 +35,7 @@ const index_js_1 = __importDefault(require("../psychic-app/index.js"));
|
|
|
36
35
|
const types_js_1 = require("../router/types.js");
|
|
37
36
|
const index_js_2 = __importDefault(require("../server/index.js"));
|
|
38
37
|
const defaults_js_1 = require("./defaults.js");
|
|
39
|
-
const
|
|
40
|
-
const suppressResponseEnums_js_1 = __importDefault(require("./helpers/suppressResponseEnums.js"));
|
|
38
|
+
const suppressResponseEnumsConfig_js_1 = __importDefault(require("./helpers/suppressResponseEnumsConfig.js"));
|
|
41
39
|
const debugEnabled = (0, node_util_1.debuglog)('psychic').enabled;
|
|
42
40
|
class OpenapiAppRenderer {
|
|
43
41
|
/**
|
|
@@ -76,13 +74,12 @@ class OpenapiAppRenderer {
|
|
|
76
74
|
return output;
|
|
77
75
|
}
|
|
78
76
|
static _toObject(routes, openapiName) {
|
|
79
|
-
const
|
|
80
|
-
openapiName,
|
|
77
|
+
const renderOpts = {
|
|
81
78
|
casing: 'camel',
|
|
82
|
-
|
|
83
|
-
suppressResponseEnums: (0, suppressResponseEnums_js_1.default)(openapiName),
|
|
79
|
+
suppressResponseEnums: (0, suppressResponseEnumsConfig_js_1.default)(openapiName),
|
|
84
80
|
};
|
|
85
|
-
|
|
81
|
+
const alreadyExtractedDescendantSerializers = {};
|
|
82
|
+
const renderedSchemasOpenapi = {};
|
|
86
83
|
const psychicApp = index_js_1.default.getOrFail();
|
|
87
84
|
const controllers = psychicApp.controllers;
|
|
88
85
|
const openapiConfig = psychicApp.openapi?.[openapiName];
|
|
@@ -127,7 +124,10 @@ class OpenapiAppRenderer {
|
|
|
127
124
|
const renderer = controller.openapi[key];
|
|
128
125
|
if (renderer === undefined)
|
|
129
126
|
throw new UnexpectedUndefined_js_1.default();
|
|
130
|
-
const endpointPayloadAndReferencedSerializers = renderer.toPathObject(routes,
|
|
127
|
+
const endpointPayloadAndReferencedSerializers = renderer.toPathObject(routes, {
|
|
128
|
+
openapiName,
|
|
129
|
+
renderOpts,
|
|
130
|
+
});
|
|
131
131
|
const serializersAppearingInHandWrittenOpenapi = endpointPayloadAndReferencedSerializers.referencedSerializers;
|
|
132
132
|
const endpointPayload = endpointPayloadAndReferencedSerializers.openapi;
|
|
133
133
|
if (endpointPayload === undefined)
|
|
@@ -148,15 +148,16 @@ class OpenapiAppRenderer {
|
|
|
148
148
|
...finalPathObject.parameters,
|
|
149
149
|
...endpointPayloadPath.parameters,
|
|
150
150
|
]);
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
renderer.toSchemaObject({
|
|
152
|
+
openapiName,
|
|
153
|
+
renderOpts,
|
|
154
|
+
renderedSchemasOpenapi,
|
|
155
|
+
alreadyExtractedDescendantSerializers,
|
|
154
156
|
serializersAppearingInHandWrittenOpenapi,
|
|
155
157
|
});
|
|
156
|
-
processedSchemas = { ...processedSchemas, ...schemaRenderingResults.processedSchemas };
|
|
157
158
|
finalOutput.components.schemas = {
|
|
158
159
|
...finalOutput.components.schemas,
|
|
159
|
-
...
|
|
160
|
+
...renderedSchemasOpenapi,
|
|
160
161
|
};
|
|
161
162
|
}
|
|
162
163
|
}
|
|
@@ -168,7 +169,7 @@ class OpenapiAppRenderer {
|
|
|
168
169
|
return finalOutput;
|
|
169
170
|
}
|
|
170
171
|
static combineParameters(parameters) {
|
|
171
|
-
const groupedParams = (0,
|
|
172
|
+
const groupedParams = (0, dream_1.groupBy)(parameters, obj => obj.name);
|
|
172
173
|
return (0, dream_1.compact)(Object.keys(groupedParams).map(paramName => {
|
|
173
174
|
const identicalParams = groupedParams[paramName] || [];
|
|
174
175
|
return identicalParams.reduce((compositeParam, param) => {
|
|
@@ -12,7 +12,6 @@ const primitiveOpenapiStatementToOpenapi_js_1 = __importDefault(require("./helpe
|
|
|
12
12
|
const schemaToRef_js_1 = __importDefault(require("./helpers/schemaToRef.js"));
|
|
13
13
|
class OpenapiBodySegmentRenderer {
|
|
14
14
|
bodySegment;
|
|
15
|
-
schemaDelimiter;
|
|
16
15
|
casing;
|
|
17
16
|
suppressResponseEnums;
|
|
18
17
|
target;
|
|
@@ -23,12 +22,11 @@ class OpenapiBodySegmentRenderer {
|
|
|
23
22
|
* Used to recursively parse nested object structures
|
|
24
23
|
* within nested openapi objects
|
|
25
24
|
*/
|
|
26
|
-
constructor(bodySegment, { openapiName,
|
|
25
|
+
constructor(bodySegment, { openapiName, renderOpts, target }) {
|
|
27
26
|
this.openapiName = openapiName;
|
|
28
27
|
this.bodySegment = bodySegment;
|
|
29
|
-
this.
|
|
30
|
-
this.
|
|
31
|
-
this.suppressResponseEnums = suppressResponseEnums;
|
|
28
|
+
this.casing = renderOpts.casing;
|
|
29
|
+
this.suppressResponseEnums = renderOpts.suppressResponseEnums;
|
|
32
30
|
this.target = target;
|
|
33
31
|
}
|
|
34
32
|
/**
|
|
@@ -390,7 +388,6 @@ The following values will be allowed:
|
|
|
390
388
|
throw new NonSerializerSuppliedToSerializerBodySegment_js_1.default(this.bodySegment, serializer);
|
|
391
389
|
const serializerRef = new dream_1.SerializerOpenapiRenderer(serializer, {
|
|
392
390
|
casing: this.casing,
|
|
393
|
-
schemaDelimiter: this.schemaDelimiter,
|
|
394
391
|
suppressResponseEnums: this.suppressResponseEnums,
|
|
395
392
|
}).serializerRef;
|
|
396
393
|
if (serializerRefBodySegment.many) {
|
|
@@ -5,7 +5,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.MissingControllerActionPairingInRoutes = void 0;
|
|
7
7
|
const dream_1 = require("@rvoh/dream");
|
|
8
|
-
const lodash_es_1 = require("lodash-es");
|
|
9
8
|
const FailedToLookupSerializerForEndpoint_js_1 = __importDefault(require("../error/openapi/FailedToLookupSerializerForEndpoint.js"));
|
|
10
9
|
const NonSerializerDerivedInOpenapiEndpointRenderer_js_1 = __importDefault(require("../error/openapi/NonSerializerDerivedInOpenapiEndpointRenderer.js"));
|
|
11
10
|
const NonSerializerDerivedInToSchemaObjects_js_1 = __importDefault(require("../error/openapi/NonSerializerDerivedInToSchemaObjects.js"));
|
|
@@ -21,10 +20,6 @@ class OpenapiEndpointRenderer {
|
|
|
21
20
|
dreamsOrSerializers;
|
|
22
21
|
controllerClass;
|
|
23
22
|
action;
|
|
24
|
-
openapiName;
|
|
25
|
-
casing;
|
|
26
|
-
schemaDelimiter;
|
|
27
|
-
suppressResponseEnums;
|
|
28
23
|
many;
|
|
29
24
|
paginate;
|
|
30
25
|
responses;
|
|
@@ -96,18 +91,18 @@ class OpenapiEndpointRenderer {
|
|
|
96
91
|
* `#toPathObject` specifically builds the `paths` portion of the
|
|
97
92
|
* final openapi.json output
|
|
98
93
|
*/
|
|
99
|
-
toPathObject(routes, { openapiName,
|
|
100
|
-
this.openapiName = openapiName;
|
|
101
|
-
this.casing = casing;
|
|
102
|
-
this.schemaDelimiter = schemaDelimiter;
|
|
103
|
-
this.suppressResponseEnums = suppressResponseEnums;
|
|
94
|
+
toPathObject(routes, { openapiName, renderOpts }) {
|
|
104
95
|
const path = this.computedPath(routes);
|
|
105
96
|
const method = this.computedMethod(routes);
|
|
106
|
-
const requestBody = this.computedRequestBody(routes);
|
|
107
|
-
const responsesAndReferencedSerializers = this.parseResponses();
|
|
97
|
+
const requestBody = this.computedRequestBody(routes, { openapiName, renderOpts });
|
|
98
|
+
const responsesAndReferencedSerializers = this.parseResponses({ openapiName, renderOpts });
|
|
108
99
|
const output = {
|
|
109
100
|
[path]: {
|
|
110
|
-
parameters: [
|
|
101
|
+
parameters: [
|
|
102
|
+
...this.headersArray({ openapiName }),
|
|
103
|
+
...this.pathParamsArray(routes),
|
|
104
|
+
...this.queryArray({ openapiName, renderOpts }),
|
|
105
|
+
],
|
|
111
106
|
[method]: {
|
|
112
107
|
tags: this.tags || [],
|
|
113
108
|
},
|
|
@@ -149,18 +144,13 @@ class OpenapiEndpointRenderer {
|
|
|
149
144
|
* final openapi.json output, adding any relevant entries that were uncovered
|
|
150
145
|
* while parsing the responses and provided callback function.
|
|
151
146
|
*/
|
|
152
|
-
toSchemaObject({ openapiName,
|
|
153
|
-
this.openapiName = openapiName;
|
|
154
|
-
this.casing = casing;
|
|
155
|
-
this.schemaDelimiter = schemaDelimiter;
|
|
156
|
-
this.suppressResponseEnums = suppressResponseEnums;
|
|
147
|
+
toSchemaObject({ openapiName, renderOpts, alreadyExtractedDescendantSerializers, renderedSchemasOpenapi, serializersAppearingInHandWrittenOpenapi, }) {
|
|
157
148
|
const serializers = this.getSerializerClasses() ?? [];
|
|
158
|
-
|
|
159
|
-
openapiName
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
processedSchemas,
|
|
149
|
+
serializersToSchemaObjects(this.controllerClass, this.action, [...serializers, ...serializersAppearingInHandWrittenOpenapi], {
|
|
150
|
+
openapiName,
|
|
151
|
+
renderOpts,
|
|
152
|
+
alreadyExtractedDescendantSerializers,
|
|
153
|
+
renderedSchemasOpenapi,
|
|
164
154
|
});
|
|
165
155
|
}
|
|
166
156
|
/**
|
|
@@ -264,10 +254,8 @@ class OpenapiEndpointRenderer {
|
|
|
264
254
|
* Generates the header portion of the openapi payload's
|
|
265
255
|
* "parameters" field for a single endpoint.
|
|
266
256
|
*/
|
|
267
|
-
headersArray() {
|
|
268
|
-
const defaultHeaders = this.omitDefaultHeaders
|
|
269
|
-
? {}
|
|
270
|
-
: (0, openapiOpts_js_1.default)(this.openapiName)?.defaults?.headers || {};
|
|
257
|
+
headersArray({ openapiName }) {
|
|
258
|
+
const defaultHeaders = this.omitDefaultHeaders ? {} : (0, openapiOpts_js_1.default)(openapiName)?.defaults?.headers || {};
|
|
271
259
|
const headers = { ...defaultHeaders, ...(this.headers || []) };
|
|
272
260
|
return ((0, dream_1.compact)(Object.keys(headers).map((headerName) => {
|
|
273
261
|
const header = headers[headerName];
|
|
@@ -294,7 +282,7 @@ class OpenapiEndpointRenderer {
|
|
|
294
282
|
* Generates the header portion of the openapi payload's
|
|
295
283
|
* "parameters" field for a single endpoint.
|
|
296
284
|
*/
|
|
297
|
-
queryArray() {
|
|
285
|
+
queryArray({ openapiName, renderOpts, }) {
|
|
298
286
|
const queryParams = Object.keys(this.query || {}).map((queryName) => {
|
|
299
287
|
const queryParam = this.query[queryName];
|
|
300
288
|
let output = {
|
|
@@ -318,10 +306,8 @@ class OpenapiEndpointRenderer {
|
|
|
318
306
|
...output,
|
|
319
307
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
320
308
|
schema: new body_segment_js_1.default(queryParam.schema, {
|
|
321
|
-
openapiName
|
|
322
|
-
|
|
323
|
-
casing: this.casing,
|
|
324
|
-
suppressResponseEnums: this.suppressResponseEnums,
|
|
309
|
+
openapiName,
|
|
310
|
+
renderOpts,
|
|
325
311
|
target: 'request',
|
|
326
312
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
327
313
|
}).render().openapi,
|
|
@@ -349,7 +335,7 @@ class OpenapiEndpointRenderer {
|
|
|
349
335
|
*
|
|
350
336
|
* Generates the requestBody portion of the endpoint
|
|
351
337
|
*/
|
|
352
|
-
computedRequestBody(routes) {
|
|
338
|
+
computedRequestBody(routes, { openapiName, renderOpts, }) {
|
|
353
339
|
const method = this.computedMethod(routes);
|
|
354
340
|
if (this.requestBody === null)
|
|
355
341
|
return this.defaultRequestBody();
|
|
@@ -357,13 +343,11 @@ class OpenapiEndpointRenderer {
|
|
|
357
343
|
if (!httpMethodsThatAllowBody.includes(method))
|
|
358
344
|
return this.defaultRequestBody();
|
|
359
345
|
if (this.shouldAutogenerateBody()) {
|
|
360
|
-
return this.generateRequestBodyForModel();
|
|
346
|
+
return this.generateRequestBodyForModel({ openapiName, renderOpts });
|
|
361
347
|
}
|
|
362
348
|
let schema = new body_segment_js_1.default(this.requestBody, {
|
|
363
|
-
openapiName
|
|
364
|
-
|
|
365
|
-
casing: this.casing,
|
|
366
|
-
suppressResponseEnums: this.suppressResponseEnums,
|
|
349
|
+
openapiName,
|
|
350
|
+
renderOpts,
|
|
367
351
|
target: 'request',
|
|
368
352
|
}).render().openapi;
|
|
369
353
|
const bodyPageParam = this.paginate?.body;
|
|
@@ -427,7 +411,7 @@ class OpenapiEndpointRenderer {
|
|
|
427
411
|
* that model that are safe to ingest will be automatically added to
|
|
428
412
|
* the request body.
|
|
429
413
|
*/
|
|
430
|
-
generateRequestBodyForModel() {
|
|
414
|
+
generateRequestBodyForModel({ openapiName, renderOpts, }) {
|
|
431
415
|
const forDreamClass = this.requestBody?.for;
|
|
432
416
|
const dreamClass = forDreamClass || this.getSingleDreamModelClass();
|
|
433
417
|
if (!dreamClass)
|
|
@@ -540,10 +524,8 @@ class OpenapiEndpointRenderer {
|
|
|
540
524
|
paramsShape.properties = {
|
|
541
525
|
...paramsShape.properties,
|
|
542
526
|
[columnName]: new body_segment_js_1.default(metadata.type, {
|
|
543
|
-
openapiName
|
|
544
|
-
|
|
545
|
-
casing: this.casing,
|
|
546
|
-
suppressResponseEnums: this.suppressResponseEnums,
|
|
527
|
+
openapiName,
|
|
528
|
+
renderOpts,
|
|
547
529
|
target: 'request',
|
|
548
530
|
}).render().openapi,
|
|
549
531
|
};
|
|
@@ -587,10 +569,8 @@ class OpenapiEndpointRenderer {
|
|
|
587
569
|
}
|
|
588
570
|
}
|
|
589
571
|
let processedSchema = new body_segment_js_1.default(paramsShape, {
|
|
590
|
-
openapiName
|
|
591
|
-
|
|
592
|
-
casing: this.casing,
|
|
593
|
-
suppressResponseEnums: this.suppressResponseEnums,
|
|
572
|
+
openapiName,
|
|
573
|
+
renderOpts,
|
|
594
574
|
target: 'request',
|
|
595
575
|
}).render().openapi;
|
|
596
576
|
const bodyPageParam = this.paginate?.body;
|
|
@@ -610,13 +590,11 @@ class OpenapiEndpointRenderer {
|
|
|
610
590
|
*
|
|
611
591
|
* Generates the responses portion of the endpoint
|
|
612
592
|
*/
|
|
613
|
-
parseResponses() {
|
|
593
|
+
parseResponses({ openapiName, renderOpts, }) {
|
|
614
594
|
let responseData = {};
|
|
615
595
|
const rendererOpts = {
|
|
616
|
-
openapiName
|
|
617
|
-
|
|
618
|
-
casing: this.casing,
|
|
619
|
-
suppressResponseEnums: this.suppressResponseEnums,
|
|
596
|
+
openapiName,
|
|
597
|
+
renderOpts,
|
|
620
598
|
target: 'response',
|
|
621
599
|
};
|
|
622
600
|
const computedStatus = this.status || this.defaultStatus;
|
|
@@ -632,7 +610,7 @@ class OpenapiEndpointRenderer {
|
|
|
632
610
|
};
|
|
633
611
|
}
|
|
634
612
|
else {
|
|
635
|
-
const parsingResults = this.parseSerializerResponseShape();
|
|
613
|
+
const parsingResults = this.parseSerializerResponseShape({ renderOpts });
|
|
636
614
|
serializersAppearingInHandWrittenOpenapi = [
|
|
637
615
|
...serializersAppearingInHandWrittenOpenapi,
|
|
638
616
|
...parsingResults.referencedSerializers,
|
|
@@ -647,7 +625,7 @@ class OpenapiEndpointRenderer {
|
|
|
647
625
|
}
|
|
648
626
|
Object.keys(this.responses || {}).forEach(statusCode => {
|
|
649
627
|
const statusCodeInt = parseInt(statusCode);
|
|
650
|
-
const response = (0,
|
|
628
|
+
const response = (0, dream_1.cloneDeepSafe)(this.responses[statusCodeInt], obj => obj);
|
|
651
629
|
responseData[statusCodeInt] ||= { description: statusDescription(statusCodeInt) };
|
|
652
630
|
const statusResponse = responseData[statusCodeInt];
|
|
653
631
|
const results = new body_segment_js_1.default(response, rendererOpts).render();
|
|
@@ -663,13 +641,13 @@ class OpenapiEndpointRenderer {
|
|
|
663
641
|
});
|
|
664
642
|
const defaultResponses = this.omitDefaultResponses
|
|
665
643
|
? {}
|
|
666
|
-
: (0, openapiOpts_js_1.default)(
|
|
644
|
+
: (0, openapiOpts_js_1.default)(openapiName)?.defaults?.responses || {};
|
|
667
645
|
const psychicAndConfigLevelDefaults = this.omitDefaultResponses
|
|
668
646
|
? {}
|
|
669
|
-
: (0,
|
|
647
|
+
: (0, dream_1.cloneDeepSafe)({
|
|
670
648
|
...defaults_js_1.DEFAULT_OPENAPI_RESPONSES,
|
|
671
649
|
...defaultResponses,
|
|
672
|
-
});
|
|
650
|
+
}, obj => obj);
|
|
673
651
|
Object.keys(psychicAndConfigLevelDefaults).forEach(key => {
|
|
674
652
|
if (!responseData[key]) {
|
|
675
653
|
const data = psychicAndConfigLevelDefaults[key];
|
|
@@ -708,7 +686,7 @@ class OpenapiEndpointRenderer {
|
|
|
708
686
|
* returns a ref object for the callback passed to the
|
|
709
687
|
* Openapi decorator.
|
|
710
688
|
*/
|
|
711
|
-
parseSerializerResponseShape() {
|
|
689
|
+
parseSerializerResponseShape({ renderOpts, }) {
|
|
712
690
|
const serializerClasses = this.getSerializerClasses();
|
|
713
691
|
if (!serializerClasses)
|
|
714
692
|
return {
|
|
@@ -716,9 +694,9 @@ class OpenapiEndpointRenderer {
|
|
|
716
694
|
openapi: { description: 'no content' },
|
|
717
695
|
};
|
|
718
696
|
if (serializerClasses.length > 1) {
|
|
719
|
-
return this.parseMultiEntitySerializerResponseShape(serializerClasses);
|
|
697
|
+
return this.parseMultiEntitySerializerResponseShape(serializerClasses, { renderOpts });
|
|
720
698
|
}
|
|
721
|
-
return this.parseSingleEntitySerializerResponseShape(serializerClasses[0]);
|
|
699
|
+
return this.parseSingleEntitySerializerResponseShape(serializerClasses[0], { renderOpts });
|
|
722
700
|
}
|
|
723
701
|
/**
|
|
724
702
|
* @internal
|
|
@@ -731,16 +709,14 @@ class OpenapiEndpointRenderer {
|
|
|
731
709
|
* public show() {...}
|
|
732
710
|
* ```
|
|
733
711
|
*/
|
|
734
|
-
parseSingleEntitySerializerResponseShape(serializer) {
|
|
712
|
+
parseSingleEntitySerializerResponseShape(serializer, { renderOpts, }) {
|
|
735
713
|
if (serializer === undefined) {
|
|
736
714
|
throw new FailedToLookupSerializerForEndpoint_js_1.default(this.controllerClass, this.action);
|
|
737
715
|
}
|
|
738
716
|
if (!(0, dream_1.isDreamSerializer)(serializer)) {
|
|
739
717
|
throw new SerializerForEndpointNotAFunction_js_1.default(this.controllerClass, this.action, serializer);
|
|
740
718
|
}
|
|
741
|
-
const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer,
|
|
742
|
-
schemaDelimiter: this.schemaDelimiter,
|
|
743
|
-
});
|
|
719
|
+
const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
|
|
744
720
|
const finalOutput = {
|
|
745
721
|
content: {
|
|
746
722
|
'application/json': {
|
|
@@ -807,18 +783,16 @@ class OpenapiEndpointRenderer {
|
|
|
807
783
|
* public responses() {...}
|
|
808
784
|
* ```
|
|
809
785
|
*/
|
|
810
|
-
parseMultiEntitySerializerResponseShape(serializers) {
|
|
786
|
+
parseMultiEntitySerializerResponseShape(serializers, { renderOpts, }) {
|
|
811
787
|
const anyOf = { anyOf: [] };
|
|
812
788
|
serializers.forEach(serializer => {
|
|
813
789
|
if (!(0, dream_1.isDreamSerializer)(serializer))
|
|
814
790
|
throw new NonSerializerDerivedInOpenapiEndpointRenderer_js_1.default(this.controllerClass, this.action, serializer);
|
|
815
791
|
});
|
|
816
|
-
const sortedSerializerClasses = (0, dream_1.sortBy)(serializers, serializer => new dream_1.SerializerOpenapiRenderer(serializer,
|
|
792
|
+
const sortedSerializerClasses = (0, dream_1.sortBy)(serializers, serializer => new dream_1.SerializerOpenapiRenderer(serializer, renderOpts).openapiName);
|
|
817
793
|
let referencedSerializers = [];
|
|
818
794
|
sortedSerializerClasses.forEach(serializer => {
|
|
819
|
-
const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer,
|
|
820
|
-
schemaDelimiter: this.schemaDelimiter,
|
|
821
|
-
});
|
|
795
|
+
const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
|
|
822
796
|
anyOf.anyOf.push(serializerOpenapiRenderer.serializerRef);
|
|
823
797
|
referencedSerializers = [
|
|
824
798
|
...referencedSerializers,
|
|
@@ -998,55 +972,34 @@ function statusDescription(status) {
|
|
|
998
972
|
return `Status ${status}`;
|
|
999
973
|
}
|
|
1000
974
|
}
|
|
1001
|
-
function serializersToSchemaObjects(controllerClass, actionName, serializers, {
|
|
975
|
+
function serializersToSchemaObjects(controllerClass, actionName, serializers, { renderOpts, openapiName, alreadyExtractedDescendantSerializers, renderedSchemasOpenapi, }) {
|
|
1002
976
|
serializers.forEach(serializer => {
|
|
1003
977
|
if (!(0, dream_1.isDreamSerializer)(serializer))
|
|
1004
978
|
throw new NonSerializerDerivedInToSchemaObjects_js_1.default(controllerClass, actionName, serializer);
|
|
1005
979
|
});
|
|
1006
|
-
serializers = serializers.filter(serializer =>
|
|
1007
|
-
const serializerOpenapiRenderer = new dream_1.SerializerOpenapiRenderer(serializer, {
|
|
1008
|
-
casing,
|
|
1009
|
-
schemaDelimiter,
|
|
1010
|
-
suppressResponseEnums,
|
|
1011
|
-
});
|
|
1012
|
-
return !processedSchemas[serializerOpenapiRenderer.globalName];
|
|
1013
|
-
});
|
|
980
|
+
serializers = serializers.filter(serializer => !renderedSchemasOpenapi[new dream_1.SerializerOpenapiRenderer(serializer, renderOpts).openapiName]);
|
|
1014
981
|
if (!serializers.length)
|
|
1015
|
-
return
|
|
1016
|
-
const renderedSchemas = {};
|
|
982
|
+
return;
|
|
1017
983
|
let dependentOnSerializers = [];
|
|
1018
984
|
serializers.forEach(serializer => {
|
|
1019
|
-
const renderer = new dream_1.SerializerOpenapiRenderer(serializer,
|
|
1020
|
-
|
|
1021
|
-
schemaDelimiter,
|
|
1022
|
-
suppressResponseEnums,
|
|
1023
|
-
});
|
|
1024
|
-
const globalName = renderer.globalName;
|
|
1025
|
-
processedSchemas = { ...processedSchemas, [globalName]: true };
|
|
1026
|
-
const results = renderer.renderedOpenapi(processedSchemas);
|
|
985
|
+
const renderer = new dream_1.SerializerOpenapiRenderer(serializer, renderOpts);
|
|
986
|
+
const results = renderer.renderedOpenapi(alreadyExtractedDescendantSerializers);
|
|
1027
987
|
const segmentRendererResults = new body_segment_js_1.default(results.openapi, {
|
|
1028
988
|
openapiName,
|
|
1029
|
-
|
|
1030
|
-
schemaDelimiter,
|
|
1031
|
-
suppressResponseEnums,
|
|
989
|
+
renderOpts,
|
|
1032
990
|
target: 'response',
|
|
1033
991
|
}).render();
|
|
1034
|
-
|
|
992
|
+
renderedSchemasOpenapi[renderer.openapiName] = segmentRendererResults.openapi;
|
|
1035
993
|
dependentOnSerializers = [
|
|
1036
994
|
...dependentOnSerializers,
|
|
1037
995
|
...results.referencedSerializers,
|
|
1038
|
-
...segmentRendererResults.referencedSerializers,
|
|
996
|
+
...segmentRendererResults.referencedSerializers, // should always be empty
|
|
1039
997
|
];
|
|
1040
998
|
});
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
suppressResponseEnums,
|
|
1044
|
-
schemaDelimiter,
|
|
999
|
+
serializersToSchemaObjects(controllerClass, actionName, dependentOnSerializers, {
|
|
1000
|
+
renderOpts,
|
|
1045
1001
|
openapiName,
|
|
1046
|
-
|
|
1002
|
+
alreadyExtractedDescendantSerializers,
|
|
1003
|
+
renderedSchemasOpenapi,
|
|
1047
1004
|
});
|
|
1048
|
-
return {
|
|
1049
|
-
processedSchemas: { ...processedSchemas, ...recursiveResults.processedSchemas },
|
|
1050
|
-
renderedSchemas: { ...renderedSchemas, ...recursiveResults.renderedSchemas },
|
|
1051
|
-
};
|
|
1052
1005
|
}
|
|
@@ -3,11 +3,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.default =
|
|
6
|
+
exports.default = suppressResponseEnumsConfig;
|
|
7
7
|
const openapiOpts_js_1 = __importDefault(require("./openapiOpts.js"));
|
|
8
8
|
/**
|
|
9
9
|
* returns either the delimiter set in the app config, or else a blank string
|
|
10
10
|
*/
|
|
11
|
-
function
|
|
11
|
+
function suppressResponseEnumsConfig(openapiName) {
|
|
12
12
|
return !!(0, openapiOpts_js_1.default)(openapiName)?.suppressResponseEnums;
|
|
13
13
|
}
|
|
@@ -30,14 +30,10 @@ const dream_1 = require("@rvoh/dream");
|
|
|
30
30
|
const cookieParser = __importStar(require("cookie-parser"));
|
|
31
31
|
const cors = __importStar(require("cors"));
|
|
32
32
|
const express = __importStar(require("express"));
|
|
33
|
-
const OpenApiValidator = __importStar(require("express-openapi-validator"));
|
|
34
|
-
const path = __importStar(require("node:path"));
|
|
35
|
-
const node_util_1 = require("node:util");
|
|
36
|
-
const isOpenapiError_js_1 = __importDefault(require("../helpers/isOpenapiError.js"));
|
|
37
33
|
const index_js_1 = __importDefault(require("../psychic-app/index.js"));
|
|
38
34
|
const index_js_2 = __importDefault(require("../router/index.js"));
|
|
39
35
|
const startPsychicServer_js_1 = __importStar(require("./helpers/startPsychicServer.js"));
|
|
40
|
-
const debugEnabled =
|
|
36
|
+
// const debugEnabled = debuglog('psychic').enabled
|
|
41
37
|
class PsychicServer {
|
|
42
38
|
static async startPsychicServer(opts) {
|
|
43
39
|
return await (0, startPsychicServer_js_1.default)(opts);
|
|
@@ -92,7 +88,6 @@ class PsychicServer {
|
|
|
92
88
|
for (const serverInitAfterMiddlewareHook of this.config.specialHooks.serverInitAfterMiddleware) {
|
|
93
89
|
await serverInitAfterMiddlewareHook(this);
|
|
94
90
|
}
|
|
95
|
-
this.initializeOpenapiValidation();
|
|
96
91
|
await this.buildRoutes();
|
|
97
92
|
for (const afterRoutesHook of this.config.specialHooks.serverInitAfterRoutes) {
|
|
98
93
|
await afterRoutesHook(this);
|
|
@@ -171,35 +166,6 @@ class PsychicServer {
|
|
|
171
166
|
initializeJSON() {
|
|
172
167
|
this.expressApp.use(express.json(this.config.jsonOptions));
|
|
173
168
|
}
|
|
174
|
-
initializeOpenapiValidation() {
|
|
175
|
-
const psychicApp = index_js_1.default.getOrFail();
|
|
176
|
-
for (const openapiName in psychicApp.openapi) {
|
|
177
|
-
const openapiOpts = psychicApp.openapi[openapiName];
|
|
178
|
-
if (openapiOpts?.validation) {
|
|
179
|
-
const opts = openapiOpts.validation;
|
|
180
|
-
opts.apiSpec ||= path.join(psychicApp.apiRoot, 'openapi.json');
|
|
181
|
-
this.expressApp.use(OpenApiValidator.middleware(opts));
|
|
182
|
-
this.expressApp.use((err, req, res, next) => {
|
|
183
|
-
if ((0, isOpenapiError_js_1.default)(err)) {
|
|
184
|
-
if (debugEnabled) {
|
|
185
|
-
index_js_1.default.log((0, node_util_1.inspect)(err));
|
|
186
|
-
console.trace();
|
|
187
|
-
}
|
|
188
|
-
res.status(err.status).json({
|
|
189
|
-
message: err.message,
|
|
190
|
-
errors: err.errors,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
if (debugEnabled) {
|
|
195
|
-
index_js_1.default.logWithLevel('error', err);
|
|
196
|
-
}
|
|
197
|
-
next();
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
169
|
async buildRoutes() {
|
|
204
170
|
const r = new index_js_2.default(this.expressApp, this.config);
|
|
205
171
|
const psychicApp = index_js_1.default.getOrFail();
|