@rvoh/psychic 3.0.0-alpha.2 → 3.0.0-alpha.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 +14 -5
- package/dist/cjs/src/openapi-renderer/SerializerOpenapiRenderer.js +16 -4
- package/dist/cjs/src/server/index.js +2 -2
- package/dist/esm/src/controller/index.js +14 -5
- package/dist/esm/src/openapi-renderer/SerializerOpenapiRenderer.js +16 -4
- package/dist/esm/src/server/index.js +2 -2
- package/package.json +4 -5
|
@@ -2,6 +2,7 @@ import { Dream, DreamApp } from '@rvoh/dream';
|
|
|
2
2
|
import { GlobalNameNotSet } from '@rvoh/dream/errors';
|
|
3
3
|
import { DreamSerializerBuilder, ObjectSerializerBuilder } from '@rvoh/dream/system';
|
|
4
4
|
import fastJsonStringify from 'fast-json-stringify';
|
|
5
|
+
import { debuglog } from 'node:util';
|
|
5
6
|
import ParamValidationError from '../error/controller/ParamValidationError.js';
|
|
6
7
|
import HttpStatusBadGateway from '../error/http/BadGateway.js';
|
|
7
8
|
import HttpStatusBadRequest from '../error/http/BadRequest.js';
|
|
@@ -646,15 +647,23 @@ export default class PsychicController {
|
|
|
646
647
|
const schemaWithComponents = validator.getResponseSchemaWithComponents(statusCode);
|
|
647
648
|
if (!schemaWithComponents)
|
|
648
649
|
continue;
|
|
649
|
-
// Generate cache key
|
|
650
650
|
const cacheKey = `${controllerClass.globalName}#${this.action}|${openapiName}|${statusCode}`;
|
|
651
|
-
// Check cache first
|
|
652
651
|
const cachedStringify = getCachedStringify(cacheKey);
|
|
653
652
|
if (cachedStringify)
|
|
654
653
|
return cachedStringify;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
654
|
+
let stringifyFn;
|
|
655
|
+
if (debuglog('json').enabled) {
|
|
656
|
+
const result = fastJsonStringify(schemaWithComponents, {
|
|
657
|
+
mode: 'debug',
|
|
658
|
+
ajv: { validateFormats: false },
|
|
659
|
+
});
|
|
660
|
+
PsychicApp.log('fast-json-stringify code:', result.code);
|
|
661
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
662
|
+
stringifyFn = fastJsonStringify.restore(result);
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
stringifyFn = fastJsonStringify(schemaWithComponents, { ajv: { validateFormats: false } });
|
|
666
|
+
}
|
|
658
667
|
cacheStringify(cacheKey, stringifyFn);
|
|
659
668
|
return stringifyFn;
|
|
660
669
|
}
|
|
@@ -166,8 +166,8 @@ export default class SerializerOpenapiRenderer {
|
|
|
166
166
|
// rendersOnes //
|
|
167
167
|
//////////////////
|
|
168
168
|
case 'rendersOne': {
|
|
169
|
+
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
169
170
|
try {
|
|
170
|
-
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
171
171
|
const { associationOpts, referencedSerializersAndOpenapiSchemaBodyShorthand } = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers);
|
|
172
172
|
const optional = attribute.options.optional ?? associationOpts.optional;
|
|
173
173
|
newlyReferencedSerializers =
|
|
@@ -193,8 +193,14 @@ export default class SerializerOpenapiRenderer {
|
|
|
193
193
|
return accumulator;
|
|
194
194
|
}
|
|
195
195
|
catch (error) {
|
|
196
|
-
if (error instanceof CallingSerializersThrewError)
|
|
196
|
+
if (error instanceof CallingSerializersThrewError) {
|
|
197
|
+
accumulator[outputAttributeName] = {
|
|
198
|
+
type: 'object',
|
|
199
|
+
additionalProperties: true,
|
|
200
|
+
description: `Serializer ${this.serializer['globalName']} includes a rendersOne "${outputAttributeName}" with an OpenAPI shape that cannot be defined. This will break fast-json-stringify. Define the OpenAPI shape or disableFastJson on the endpoint.`,
|
|
201
|
+
};
|
|
197
202
|
return accumulator;
|
|
203
|
+
}
|
|
198
204
|
if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer)
|
|
199
205
|
throw new ExpectedSerializerForRendersOneOrManyOption('rendersOne', this.globalName, attribute);
|
|
200
206
|
throw error;
|
|
@@ -207,8 +213,8 @@ export default class SerializerOpenapiRenderer {
|
|
|
207
213
|
// rendersManys //
|
|
208
214
|
///////////////////
|
|
209
215
|
case 'rendersMany': {
|
|
216
|
+
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
210
217
|
try {
|
|
211
|
-
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
212
218
|
const { referencedSerializersAndOpenapiSchemaBodyShorthand } = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers);
|
|
213
219
|
newlyReferencedSerializers =
|
|
214
220
|
referencedSerializersAndOpenapiSchemaBodyShorthand.referencedSerializers;
|
|
@@ -219,8 +225,14 @@ export default class SerializerOpenapiRenderer {
|
|
|
219
225
|
return accumulator;
|
|
220
226
|
}
|
|
221
227
|
catch (error) {
|
|
222
|
-
if (error instanceof CallingSerializersThrewError)
|
|
228
|
+
if (error instanceof CallingSerializersThrewError) {
|
|
229
|
+
accumulator[outputAttributeName] = {
|
|
230
|
+
type: 'array',
|
|
231
|
+
items: { type: 'object', additionalProperties: true },
|
|
232
|
+
description: `Serializer ${this.serializer['globalName']} includes a rendersMany "${outputAttributeName}" with an OpenAPI shape that cannot be defined. This will break fast-json-stringify. Define the OpenAPI shape or disableFastJson on the endpoint.`,
|
|
233
|
+
};
|
|
223
234
|
return accumulator;
|
|
235
|
+
}
|
|
224
236
|
if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer)
|
|
225
237
|
throw new ExpectedSerializerForRendersOneOrManyOption('rendersMany', this.globalName, attribute);
|
|
226
238
|
throw error;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
2
1
|
import cors from '@koa/cors';
|
|
2
|
+
import etag from '@koa/etag';
|
|
3
|
+
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
3
4
|
import Koa from 'koa';
|
|
4
5
|
import koaBodyparser from 'koa-bodyparser';
|
|
5
6
|
import conditional from 'koa-conditional-get';
|
|
6
|
-
import etag from 'koa-etag';
|
|
7
7
|
import logIfDevelopment from '../controller/helpers/logIfDevelopment.js';
|
|
8
8
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
9
9
|
import PsychicApp from '../psychic-app/index.js';
|
|
@@ -2,6 +2,7 @@ import { Dream, DreamApp } from '@rvoh/dream';
|
|
|
2
2
|
import { GlobalNameNotSet } from '@rvoh/dream/errors';
|
|
3
3
|
import { DreamSerializerBuilder, ObjectSerializerBuilder } from '@rvoh/dream/system';
|
|
4
4
|
import fastJsonStringify from 'fast-json-stringify';
|
|
5
|
+
import { debuglog } from 'node:util';
|
|
5
6
|
import ParamValidationError from '../error/controller/ParamValidationError.js';
|
|
6
7
|
import HttpStatusBadGateway from '../error/http/BadGateway.js';
|
|
7
8
|
import HttpStatusBadRequest from '../error/http/BadRequest.js';
|
|
@@ -646,15 +647,23 @@ export default class PsychicController {
|
|
|
646
647
|
const schemaWithComponents = validator.getResponseSchemaWithComponents(statusCode);
|
|
647
648
|
if (!schemaWithComponents)
|
|
648
649
|
continue;
|
|
649
|
-
// Generate cache key
|
|
650
650
|
const cacheKey = `${controllerClass.globalName}#${this.action}|${openapiName}|${statusCode}`;
|
|
651
|
-
// Check cache first
|
|
652
651
|
const cachedStringify = getCachedStringify(cacheKey);
|
|
653
652
|
if (cachedStringify)
|
|
654
653
|
return cachedStringify;
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
654
|
+
let stringifyFn;
|
|
655
|
+
if (debuglog('json').enabled) {
|
|
656
|
+
const result = fastJsonStringify(schemaWithComponents, {
|
|
657
|
+
mode: 'debug',
|
|
658
|
+
ajv: { validateFormats: false },
|
|
659
|
+
});
|
|
660
|
+
PsychicApp.log('fast-json-stringify code:', result.code);
|
|
661
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-explicit-any
|
|
662
|
+
stringifyFn = fastJsonStringify.restore(result);
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
stringifyFn = fastJsonStringify(schemaWithComponents, { ajv: { validateFormats: false } });
|
|
666
|
+
}
|
|
658
667
|
cacheStringify(cacheKey, stringifyFn);
|
|
659
668
|
return stringifyFn;
|
|
660
669
|
}
|
|
@@ -166,8 +166,8 @@ export default class SerializerOpenapiRenderer {
|
|
|
166
166
|
// rendersOnes //
|
|
167
167
|
//////////////////
|
|
168
168
|
case 'rendersOne': {
|
|
169
|
+
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
169
170
|
try {
|
|
170
|
-
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
171
171
|
const { associationOpts, referencedSerializersAndOpenapiSchemaBodyShorthand } = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers);
|
|
172
172
|
const optional = attribute.options.optional ?? associationOpts.optional;
|
|
173
173
|
newlyReferencedSerializers =
|
|
@@ -193,8 +193,14 @@ export default class SerializerOpenapiRenderer {
|
|
|
193
193
|
return accumulator;
|
|
194
194
|
}
|
|
195
195
|
catch (error) {
|
|
196
|
-
if (error instanceof CallingSerializersThrewError)
|
|
196
|
+
if (error instanceof CallingSerializersThrewError) {
|
|
197
|
+
accumulator[outputAttributeName] = {
|
|
198
|
+
type: 'object',
|
|
199
|
+
additionalProperties: true,
|
|
200
|
+
description: `Serializer ${this.serializer['globalName']} includes a rendersOne "${outputAttributeName}" with an OpenAPI shape that cannot be defined. This will break fast-json-stringify. Define the OpenAPI shape or disableFastJson on the endpoint.`,
|
|
201
|
+
};
|
|
197
202
|
return accumulator;
|
|
203
|
+
}
|
|
198
204
|
if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer)
|
|
199
205
|
throw new ExpectedSerializerForRendersOneOrManyOption('rendersOne', this.globalName, attribute);
|
|
200
206
|
throw error;
|
|
@@ -207,8 +213,8 @@ export default class SerializerOpenapiRenderer {
|
|
|
207
213
|
// rendersManys //
|
|
208
214
|
///////////////////
|
|
209
215
|
case 'rendersMany': {
|
|
216
|
+
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
210
217
|
try {
|
|
211
|
-
const outputAttributeName = this.setCase(attribute.options.as ?? attribute.name);
|
|
212
218
|
const { referencedSerializersAndOpenapiSchemaBodyShorthand } = associationOpenapi(attribute, DataTypeForOpenapi, alreadyExtractedDescendantSerializers);
|
|
213
219
|
newlyReferencedSerializers =
|
|
214
220
|
referencedSerializersAndOpenapiSchemaBodyShorthand.referencedSerializers;
|
|
@@ -219,8 +225,14 @@ export default class SerializerOpenapiRenderer {
|
|
|
219
225
|
return accumulator;
|
|
220
226
|
}
|
|
221
227
|
catch (error) {
|
|
222
|
-
if (error instanceof CallingSerializersThrewError)
|
|
228
|
+
if (error instanceof CallingSerializersThrewError) {
|
|
229
|
+
accumulator[outputAttributeName] = {
|
|
230
|
+
type: 'array',
|
|
231
|
+
items: { type: 'object', additionalProperties: true },
|
|
232
|
+
description: `Serializer ${this.serializer['globalName']} includes a rendersMany "${outputAttributeName}" with an OpenAPI shape that cannot be defined. This will break fast-json-stringify. Define the OpenAPI shape or disableFastJson on the endpoint.`,
|
|
233
|
+
};
|
|
223
234
|
return accumulator;
|
|
235
|
+
}
|
|
224
236
|
if (error instanceof AttemptedToDeriveDescendentSerializersFromNonSerializer)
|
|
225
237
|
throw new ExpectedSerializerForRendersOneOrManyOption('rendersMany', this.globalName, attribute);
|
|
226
238
|
throw error;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
2
1
|
import cors from '@koa/cors';
|
|
2
|
+
import etag from '@koa/etag';
|
|
3
|
+
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
3
4
|
import Koa from 'koa';
|
|
4
5
|
import koaBodyparser from 'koa-bodyparser';
|
|
5
6
|
import conditional from 'koa-conditional-get';
|
|
6
|
-
import etag from 'koa-etag';
|
|
7
7
|
import logIfDevelopment from '../controller/helpers/logIfDevelopment.js';
|
|
8
8
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
9
9
|
import PsychicApp from '../psychic-app/index.js';
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@rvoh/psychic",
|
|
4
4
|
"description": "Typescript web framework",
|
|
5
|
-
"version": "3.0.0-alpha.
|
|
5
|
+
"version": "3.0.0-alpha.3",
|
|
6
6
|
"author": "RVOHealth",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -66,6 +66,7 @@
|
|
|
66
66
|
"prepack": "pnpm build"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
|
+
"@koa/etag": "^5.0.2",
|
|
69
70
|
"ajv": "^8.17.1",
|
|
70
71
|
"ajv-formats": "^3.0.1",
|
|
71
72
|
"commander": "^12.1.0",
|
|
@@ -84,7 +85,6 @@
|
|
|
84
85
|
"koa": "^2.15.3",
|
|
85
86
|
"koa-bodyparser": "^4.4.1",
|
|
86
87
|
"koa-conditional-get": "^3.0.0",
|
|
87
|
-
"koa-etag": "^5.0.0",
|
|
88
88
|
"openapi-typescript": "^7.8.0"
|
|
89
89
|
},
|
|
90
90
|
"devDependencies": {
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"@rvoh/dream": "^2.3.1",
|
|
95
95
|
"@rvoh/dream-spec-helpers": "^2.1.1",
|
|
96
96
|
"@rvoh/psychic-spec-helpers": "^3.0.0-alpha.1",
|
|
97
|
-
"@types/koa": "^
|
|
97
|
+
"@types/koa": "^3.0.1",
|
|
98
98
|
"@types/koa-bodyparser": "^4.3.12",
|
|
99
99
|
"@types/koa-conditional-get": "^2.0.3",
|
|
100
100
|
"@types/koa-etag": "^3.0.3",
|
|
@@ -110,10 +110,9 @@
|
|
|
110
110
|
"@typescript/analyze-trace": "^0.10.1",
|
|
111
111
|
"eslint": "^9.39.1",
|
|
112
112
|
"jsdom": "^26.1.0",
|
|
113
|
-
"koa": "^
|
|
113
|
+
"koa": "^3.1.1",
|
|
114
114
|
"koa-bodyparser": "^4.4.1",
|
|
115
115
|
"koa-conditional-get": "^3.0.0",
|
|
116
|
-
"koa-etag": "^4.0.0",
|
|
117
116
|
"koa-passport": "^6.0.0",
|
|
118
117
|
"koa-session": "^7.0.2",
|
|
119
118
|
"kysely": "^0.28.5",
|