@rvoh/psychic 3.5.0 → 3.7.0
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/cli/index.js +4 -3
- package/dist/cjs/src/generate/helpers/generateControllerContent.js +5 -3
- package/dist/cjs/src/generate/helpers/generateResourceControllerSpecContent.js +1 -1
- package/dist/cjs/src/psychic-app/index.js +2 -2
- package/dist/cjs/src/server/index.js +2 -2
- package/dist/esm/src/cli/index.js +4 -3
- package/dist/esm/src/generate/helpers/generateControllerContent.js +5 -3
- package/dist/esm/src/generate/helpers/generateResourceControllerSpecContent.js +1 -1
- package/dist/esm/src/psychic-app/index.js +2 -2
- package/dist/esm/src/server/index.js +2 -2
- package/dist/types/src/package-exports/types.d.ts +1 -1
- package/dist/types/src/psychic-app/index.d.ts +10 -5
- package/package.json +3 -7
|
@@ -132,8 +132,9 @@ ${INDENT} pnpm psy g:sti-child --model-name=House Rental/House extends Rental
|
|
|
132
132
|
${INDENT} pnpm psy g:sti-child --model-name=Condo Rental/Condo extends Rental`, false)
|
|
133
133
|
.option('--owning-model <modelName>', `The model class that owns this resource. The generated controller will use \`associationQuery\` and \`createAssociation\` on the owning model to scope queries and create records.
|
|
134
134
|
${INDENT}
|
|
135
|
-
${INDENT}Defaults to \`this.currentUser\` for non-admin
|
|
136
|
-
${INDENT}Defaults to \`
|
|
135
|
+
${INDENT}Defaults to \`this.currentUser\` for non-admin routes (e.g., \`this.currentUser.associationQuery('posts').findOrFail(this.castParam('id', 'uuid'))\`).
|
|
136
|
+
${INDENT}Defaults to \`this.currentInternalUser\` for internal namespaced controllers (e.g., \`this.currentInternalUser.associationQuery('posts').findOrFail(this.castParam('id', 'uuid'))\`).
|
|
137
|
+
${INDENT}Defaults to \`null\` for admin namespaced controllers (e.g., \`Post.findOrFail(this.castParam('id', 'uuid'))\`).
|
|
137
138
|
${INDENT}Supplying an owning-modle changes the the generated code in the controller to be relative to the owning model.
|
|
138
139
|
${INDENT}
|
|
139
140
|
${INDENT}Example:
|
|
@@ -152,7 +153,7 @@ ${INDENT} # model is named GroupDanceLesson instead of LessonDanceGroup`)
|
|
|
152
153
|
.option('--no-soft-delete', `skip generating the @SoftDelete() decorator and the corresponding nullable \`deleted_at\` column. By default, generated models use soft-delete semantics (rows are marked deleted via \`deleted_at\` instead of being removed from the database). Pass this flag when you want records to be hard-deleted.`)
|
|
153
154
|
.argument('<path>', `The URL path for this resource's routes, relative to the root domain. Use \`\\{\\}\` as a placeholder for a parent resource's ID parameter when nesting.
|
|
154
155
|
${INDENT}
|
|
155
|
-
${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "
|
|
156
|
+
${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "internal" scope queries to \`this.currentInternalUser\` instead of \`this.currentUser\`. Paths that begin with "admin" remove owner scoping of queries entirely (\`--owning-model\` may be provided to apply query scoping). Each segment maps to a directory level in the controllers folder.
|
|
156
157
|
${INDENT}
|
|
157
158
|
${INDENT}Examples:
|
|
158
159
|
${INDENT} v1/posts # /v1/posts, /v1/posts/:id
|
|
@@ -13,8 +13,10 @@ export default function generateControllerContent({ ancestorName, ancestorImport
|
|
|
13
13
|
fullyQualifiedControllerName = DreamApp.system.standardizeFullyQualifiedModelName(fullyQualifiedControllerName);
|
|
14
14
|
const additionalImports = [];
|
|
15
15
|
const controllerClassName = DreamApp.system.globalClassNameFromFullyQualifiedModelName(fullyQualifiedControllerName);
|
|
16
|
-
// Determine user model variables
|
|
17
|
-
|
|
16
|
+
// Determine user model variables. Internal-namespaced controllers scope to
|
|
17
|
+
// the current internal user the same way default controllers scope to the
|
|
18
|
+
// current user; only the Admin namespace bypasses owner scoping entirely.
|
|
19
|
+
const actualOwningModel = owningModel || (forInternal ? 'InternalUser' : 'User');
|
|
18
20
|
const owningModelClassName = DreamApp.system.globalClassNameFromFullyQualifiedModelName(actualOwningModel);
|
|
19
21
|
const owningModelProperty = `current${owningModelClassName}`;
|
|
20
22
|
let modelClassName;
|
|
@@ -34,7 +36,7 @@ export default function generateControllerContent({ ancestorName, ancestorImport
|
|
|
34
36
|
? `
|
|
35
37
|
serializerKey: 'internal',`
|
|
36
38
|
: '';
|
|
37
|
-
const useDirectModelAccess =
|
|
39
|
+
const useDirectModelAccess = forAdmin && !owningModel;
|
|
38
40
|
const loadQueryBase = useDirectModelAccess
|
|
39
41
|
? (modelClassName ?? 'no-class-name')
|
|
40
42
|
: `this.${owningModelProperty}.associationQuery('${pluralizedModelAttributeName}')`;
|
|
@@ -31,7 +31,7 @@ function createModelConfiguration(options) {
|
|
|
31
31
|
const owningModelVariableName = options.owningModel
|
|
32
32
|
? camelize(DreamApp.system.standardizeFullyQualifiedModelName(options.owningModel).split('/').pop())
|
|
33
33
|
: userVariableName;
|
|
34
|
-
const useDirectModelAccess =
|
|
34
|
+
const useDirectModelAccess = options.forAdmin && !options.owningModel;
|
|
35
35
|
const simpleCreationCommand = `const ${modelVariableName} = await create${modelClassName}(${useDirectModelAccess ? '' : `{ ${owningModelVariableName} }`})`;
|
|
36
36
|
return {
|
|
37
37
|
fullyQualifiedModelName,
|
|
@@ -277,7 +277,7 @@ Try setting it to something valid, like:
|
|
|
277
277
|
}
|
|
278
278
|
_jsonOptions;
|
|
279
279
|
/**
|
|
280
|
-
* Options passed through to
|
|
280
|
+
* Options passed through to `@koa/bodyparser`. When unset, the upstream
|
|
281
281
|
* defaults apply — notably `jsonLimit: '1mb'` and `formLimit: '56kb'`,
|
|
282
282
|
* which cap request-body size at the framework boundary and defend against
|
|
283
283
|
* unbounded-payload memory DoS even when no edge (WAF / API Gateway)
|
|
@@ -288,7 +288,7 @@ Try setting it to something valid, like:
|
|
|
288
288
|
*
|
|
289
289
|
* See https://github.com/koajs/bodyparser for the full option list
|
|
290
290
|
* (`jsonLimit`, `formLimit`, `textLimit`, `xmlLimit`, `enableTypes`,
|
|
291
|
-
* `
|
|
291
|
+
* `jsonStrict`, `detectJSON`, etc.).
|
|
292
292
|
*/
|
|
293
293
|
get jsonOptions() {
|
|
294
294
|
return this._jsonOptions;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { bodyParser } from '@koa/bodyparser';
|
|
1
2
|
import cors from '@koa/cors';
|
|
2
3
|
import etag from '@koa/etag';
|
|
3
4
|
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
4
5
|
import Koa from 'koa';
|
|
5
|
-
import koaBodyparser from 'koa-bodyparser';
|
|
6
6
|
import conditional from 'koa-conditional-get';
|
|
7
7
|
import logIfDevelopment from '../controller/helpers/logIfDevelopment.js';
|
|
8
8
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
@@ -200,7 +200,7 @@ export default class PsychicServer {
|
|
|
200
200
|
this.koaApp.use(cors(corsOptions));
|
|
201
201
|
}
|
|
202
202
|
initializeJSON() {
|
|
203
|
-
this.koaApp.use(
|
|
203
|
+
this.koaApp.use(bodyParser(PsychicApp.getOrFail().jsonOptions));
|
|
204
204
|
}
|
|
205
205
|
async buildRoutes() {
|
|
206
206
|
const r = new PsychicRouter(this.koaApp);
|
|
@@ -132,8 +132,9 @@ ${INDENT} pnpm psy g:sti-child --model-name=House Rental/House extends Rental
|
|
|
132
132
|
${INDENT} pnpm psy g:sti-child --model-name=Condo Rental/Condo extends Rental`, false)
|
|
133
133
|
.option('--owning-model <modelName>', `The model class that owns this resource. The generated controller will use \`associationQuery\` and \`createAssociation\` on the owning model to scope queries and create records.
|
|
134
134
|
${INDENT}
|
|
135
|
-
${INDENT}Defaults to \`this.currentUser\` for non-admin
|
|
136
|
-
${INDENT}Defaults to \`
|
|
135
|
+
${INDENT}Defaults to \`this.currentUser\` for non-admin routes (e.g., \`this.currentUser.associationQuery('posts').findOrFail(this.castParam('id', 'uuid'))\`).
|
|
136
|
+
${INDENT}Defaults to \`this.currentInternalUser\` for internal namespaced controllers (e.g., \`this.currentInternalUser.associationQuery('posts').findOrFail(this.castParam('id', 'uuid'))\`).
|
|
137
|
+
${INDENT}Defaults to \`null\` for admin namespaced controllers (e.g., \`Post.findOrFail(this.castParam('id', 'uuid'))\`).
|
|
137
138
|
${INDENT}Supplying an owning-modle changes the the generated code in the controller to be relative to the owning model.
|
|
138
139
|
${INDENT}
|
|
139
140
|
${INDENT}Example:
|
|
@@ -152,7 +153,7 @@ ${INDENT} # model is named GroupDanceLesson instead of LessonDanceGroup`)
|
|
|
152
153
|
.option('--no-soft-delete', `skip generating the @SoftDelete() decorator and the corresponding nullable \`deleted_at\` column. By default, generated models use soft-delete semantics (rows are marked deleted via \`deleted_at\` instead of being removed from the database). Pass this flag when you want records to be hard-deleted.`)
|
|
153
154
|
.argument('<path>', `The URL path for this resource's routes, relative to the root domain. Use \`\\{\\}\` as a placeholder for a parent resource's ID parameter when nesting.
|
|
154
155
|
${INDENT}
|
|
155
|
-
${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "
|
|
156
|
+
${INDENT}The path determines the controller namespace hierarchy. Paths that begin with "internal" scope queries to \`this.currentInternalUser\` instead of \`this.currentUser\`. Paths that begin with "admin" remove owner scoping of queries entirely (\`--owning-model\` may be provided to apply query scoping). Each segment maps to a directory level in the controllers folder.
|
|
156
157
|
${INDENT}
|
|
157
158
|
${INDENT}Examples:
|
|
158
159
|
${INDENT} v1/posts # /v1/posts, /v1/posts/:id
|
|
@@ -13,8 +13,10 @@ export default function generateControllerContent({ ancestorName, ancestorImport
|
|
|
13
13
|
fullyQualifiedControllerName = DreamApp.system.standardizeFullyQualifiedModelName(fullyQualifiedControllerName);
|
|
14
14
|
const additionalImports = [];
|
|
15
15
|
const controllerClassName = DreamApp.system.globalClassNameFromFullyQualifiedModelName(fullyQualifiedControllerName);
|
|
16
|
-
// Determine user model variables
|
|
17
|
-
|
|
16
|
+
// Determine user model variables. Internal-namespaced controllers scope to
|
|
17
|
+
// the current internal user the same way default controllers scope to the
|
|
18
|
+
// current user; only the Admin namespace bypasses owner scoping entirely.
|
|
19
|
+
const actualOwningModel = owningModel || (forInternal ? 'InternalUser' : 'User');
|
|
18
20
|
const owningModelClassName = DreamApp.system.globalClassNameFromFullyQualifiedModelName(actualOwningModel);
|
|
19
21
|
const owningModelProperty = `current${owningModelClassName}`;
|
|
20
22
|
let modelClassName;
|
|
@@ -34,7 +36,7 @@ export default function generateControllerContent({ ancestorName, ancestorImport
|
|
|
34
36
|
? `
|
|
35
37
|
serializerKey: 'internal',`
|
|
36
38
|
: '';
|
|
37
|
-
const useDirectModelAccess =
|
|
39
|
+
const useDirectModelAccess = forAdmin && !owningModel;
|
|
38
40
|
const loadQueryBase = useDirectModelAccess
|
|
39
41
|
? (modelClassName ?? 'no-class-name')
|
|
40
42
|
: `this.${owningModelProperty}.associationQuery('${pluralizedModelAttributeName}')`;
|
|
@@ -31,7 +31,7 @@ function createModelConfiguration(options) {
|
|
|
31
31
|
const owningModelVariableName = options.owningModel
|
|
32
32
|
? camelize(DreamApp.system.standardizeFullyQualifiedModelName(options.owningModel).split('/').pop())
|
|
33
33
|
: userVariableName;
|
|
34
|
-
const useDirectModelAccess =
|
|
34
|
+
const useDirectModelAccess = options.forAdmin && !options.owningModel;
|
|
35
35
|
const simpleCreationCommand = `const ${modelVariableName} = await create${modelClassName}(${useDirectModelAccess ? '' : `{ ${owningModelVariableName} }`})`;
|
|
36
36
|
return {
|
|
37
37
|
fullyQualifiedModelName,
|
|
@@ -277,7 +277,7 @@ Try setting it to something valid, like:
|
|
|
277
277
|
}
|
|
278
278
|
_jsonOptions;
|
|
279
279
|
/**
|
|
280
|
-
* Options passed through to
|
|
280
|
+
* Options passed through to `@koa/bodyparser`. When unset, the upstream
|
|
281
281
|
* defaults apply — notably `jsonLimit: '1mb'` and `formLimit: '56kb'`,
|
|
282
282
|
* which cap request-body size at the framework boundary and defend against
|
|
283
283
|
* unbounded-payload memory DoS even when no edge (WAF / API Gateway)
|
|
@@ -288,7 +288,7 @@ Try setting it to something valid, like:
|
|
|
288
288
|
*
|
|
289
289
|
* See https://github.com/koajs/bodyparser for the full option list
|
|
290
290
|
* (`jsonLimit`, `formLimit`, `textLimit`, `xmlLimit`, `enableTypes`,
|
|
291
|
-
* `
|
|
291
|
+
* `jsonStrict`, `detectJSON`, etc.).
|
|
292
292
|
*/
|
|
293
293
|
get jsonOptions() {
|
|
294
294
|
return this._jsonOptions;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { bodyParser } from '@koa/bodyparser';
|
|
1
2
|
import cors from '@koa/cors';
|
|
2
3
|
import etag from '@koa/etag';
|
|
3
4
|
import { closeAllDbConnections } from '@rvoh/dream/db';
|
|
4
5
|
import Koa from 'koa';
|
|
5
|
-
import koaBodyparser from 'koa-bodyparser';
|
|
6
6
|
import conditional from 'koa-conditional-get';
|
|
7
7
|
import logIfDevelopment from '../controller/helpers/logIfDevelopment.js';
|
|
8
8
|
import EnvInternal from '../helpers/EnvInternal.js';
|
|
@@ -200,7 +200,7 @@ export default class PsychicServer {
|
|
|
200
200
|
this.koaApp.use(cors(corsOptions));
|
|
201
201
|
}
|
|
202
202
|
initializeJSON() {
|
|
203
|
-
this.koaApp.use(
|
|
203
|
+
this.koaApp.use(bodyParser(PsychicApp.getOrFail().jsonOptions));
|
|
204
204
|
}
|
|
205
205
|
async buildRoutes() {
|
|
206
206
|
const r = new PsychicRouter(this.koaApp);
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { type PsychicAppInitOptions } from '../psychic-app/index.js';
|
|
1
|
+
export { type BodyParserOptions, type PsychicAppInitOptions } from '../psychic-app/index.js';
|
|
2
2
|
export { type UUID } from '../psychic-app/types.js';
|
|
3
3
|
export { type HttpMethod } from '../router/types.js';
|
|
@@ -3,9 +3,9 @@ import { DreamApp } from '@rvoh/dream';
|
|
|
3
3
|
import { OpenapiSchemaBody } from '@rvoh/dream/openapi';
|
|
4
4
|
import { DreamAppAllowedPackageManagersEnum } from '@rvoh/dream/system';
|
|
5
5
|
import { DreamAppInitOptions, DreamLogLevel, DreamLogger, EncryptOptions } from '@rvoh/dream/types';
|
|
6
|
+
import { bodyParser } from '@koa/bodyparser';
|
|
6
7
|
import { Command } from 'commander';
|
|
7
8
|
import Koa from 'koa';
|
|
8
|
-
import bodyParser from 'koa-bodyparser';
|
|
9
9
|
import * as http from 'node:http';
|
|
10
10
|
import * as https from 'node:https';
|
|
11
11
|
import { OpenapiValidateTarget } from '../openapi-renderer/defaults.js';
|
|
@@ -14,6 +14,11 @@ import PsychicRouter from '../router/index.js';
|
|
|
14
14
|
import { RouteConfig } from '../router/route-manager.js';
|
|
15
15
|
import PsychicServer from '../server/index.js';
|
|
16
16
|
import { PsychicAppInitializerCb, PsychicHookEventType, PsychicUseEventType } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Options passed through to `@koa/bodyparser`. The package does not export its
|
|
19
|
+
* options type by name, so we derive it from the middleware's call signature.
|
|
20
|
+
*/
|
|
21
|
+
export type BodyParserOptions = NonNullable<Parameters<typeof bodyParser>[0]>;
|
|
17
22
|
export default class PsychicApp {
|
|
18
23
|
/**
|
|
19
24
|
* Called by the initializePsychicApp function, which is built
|
|
@@ -165,7 +170,7 @@ export default class PsychicApp {
|
|
|
165
170
|
get redirectAllowedHosts(): readonly string[];
|
|
166
171
|
private _jsonOptions;
|
|
167
172
|
/**
|
|
168
|
-
* Options passed through to
|
|
173
|
+
* Options passed through to `@koa/bodyparser`. When unset, the upstream
|
|
169
174
|
* defaults apply — notably `jsonLimit: '1mb'` and `formLimit: '56kb'`,
|
|
170
175
|
* which cap request-body size at the framework boundary and defend against
|
|
171
176
|
* unbounded-payload memory DoS even when no edge (WAF / API Gateway)
|
|
@@ -176,9 +181,9 @@ export default class PsychicApp {
|
|
|
176
181
|
*
|
|
177
182
|
* See https://github.com/koajs/bodyparser for the full option list
|
|
178
183
|
* (`jsonLimit`, `formLimit`, `textLimit`, `xmlLimit`, `enableTypes`,
|
|
179
|
-
* `
|
|
184
|
+
* `jsonStrict`, `detectJSON`, etc.).
|
|
180
185
|
*/
|
|
181
|
-
get jsonOptions():
|
|
186
|
+
get jsonOptions(): BodyParserOptions;
|
|
182
187
|
private _cookieOptions;
|
|
183
188
|
get cookieOptions(): {
|
|
184
189
|
maxAge: number;
|
|
@@ -255,7 +260,7 @@ export default class PsychicApp {
|
|
|
255
260
|
plugin(cb: (app: PsychicApp) => void | Promise<void>): void;
|
|
256
261
|
on<T extends PsychicHookEventType>(hookEventType: T, cb: T extends 'server:error' ? (err: Error, ctx: Koa.Context) => void | Promise<void> : T extends 'server:init:before-middleware' ? (psychicServer: PsychicServer) => void | Promise<void> : T extends 'server:init:after-middleware' ? (psychicServer: PsychicServer) => void | Promise<void> : T extends 'server:start' ? (psychicServer: PsychicServer) => void | Promise<void> : T extends 'server:shutdown' ? (psychicServer: PsychicServer) => void | Promise<void> : T extends 'server:init:after-routes' ? (psychicServer: PsychicServer) => void | Promise<void> : T extends 'cli:start' ? (program: Command) => void | Promise<void> : T extends 'cli:sync' ? () => any : (conf: PsychicApp) => void | Promise<void>): void;
|
|
257
262
|
set(option: 'openapi', name: string, value: NamedPsychicOpenapiOptions): void;
|
|
258
|
-
set<Opt extends PsychicAppOption>(option: Opt, value: Opt extends 'appName' ? string : Opt extends 'apiOnly' ? boolean : Opt extends 'defaultResponseHeaders' ? Record<string, string | null> : Opt extends 'httpServerOptions' ? http.ServerOptions | https.ServerOptions : Opt extends 'encryption' ? PsychicAppEncryptionOptions : Opt extends 'cors' ? cors.Options : Opt extends 'cookie' ? CustomCookieOptions : Opt extends 'apiRoot' ? string : Opt extends 'importExtension' ? GeneratorImportStyle : Opt extends 'sessionCookieName' ? string : Opt extends 'json' ?
|
|
263
|
+
set<Opt extends PsychicAppOption>(option: Opt, value: Opt extends 'appName' ? string : Opt extends 'apiOnly' ? boolean : Opt extends 'defaultResponseHeaders' ? Record<string, string | null> : Opt extends 'httpServerOptions' ? http.ServerOptions | https.ServerOptions : Opt extends 'encryption' ? PsychicAppEncryptionOptions : Opt extends 'cors' ? cors.Options : Opt extends 'cookie' ? CustomCookieOptions : Opt extends 'apiRoot' ? string : Opt extends 'importExtension' ? GeneratorImportStyle : Opt extends 'sessionCookieName' ? string : Opt extends 'json' ? BodyParserOptions : Opt extends 'logger' ? PsychicLogger : Opt extends 'ssl' ? PsychicSslCredentials : Opt extends 'openapi' ? DefaultPsychicOpenapiOptions : Opt extends 'paths' ? PsychicPathOptions : Opt extends 'port' ? number : Opt extends 'saltRounds' ? number : Opt extends 'packageManager' ? DreamAppAllowedPackageManagersEnum : Opt extends 'inflections' ? () => void | Promise<void> : Opt extends 'routes' ? (r: PsychicRouter) => void | Promise<void> : Opt extends 'redirectAllowedHosts' ? readonly string[] : never): void;
|
|
259
264
|
override<Override extends keyof PsychicAppOverrides>(override: Override, value: PsychicAppOverrides[Override]): void;
|
|
260
265
|
}
|
|
261
266
|
export type PsychicAppOption = 'appName' | 'apiOnly' | 'apiRoot' | 'httpServerOptions' | 'importExtension' | 'encryption' | 'sessionCookieName' | 'cookie' | 'cors' | 'defaultResponseHeaders' | 'inflections' | 'json' | 'logger' | 'openapi' | 'packageManager' | 'paths' | 'port' | 'redirectAllowedHosts' | 'routes' | 'saltRounds' | 'ssl';
|
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.
|
|
5
|
+
"version": "3.7.0",
|
|
6
6
|
"author": "RVOHealth",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
@@ -72,23 +72,22 @@
|
|
|
72
72
|
"yoctocolors": "^2.1.1"
|
|
73
73
|
},
|
|
74
74
|
"peerDependencies": {
|
|
75
|
+
"@koa/bodyparser": "^6.1.0",
|
|
75
76
|
"@koa/cors": "^5.0.0",
|
|
76
77
|
"@koa/etag": "^5.0.2",
|
|
77
78
|
"@koa/router": "^15.3.0",
|
|
78
79
|
"@rvoh/dream": "^2.10.0",
|
|
79
80
|
"@types/koa": "^3.0.1",
|
|
80
|
-
"@types/koa-bodyparser": "^4.3.12",
|
|
81
81
|
"@types/koa-conditional-get": "^2.0.3",
|
|
82
|
-
"@types/koa-etag": "^3.0.3",
|
|
83
82
|
"@types/koa__cors": "^5.0.0",
|
|
84
83
|
"@types/koa__router": "^12.0.5",
|
|
85
84
|
"koa": "^3.1.2",
|
|
86
|
-
"koa-bodyparser": "^4.4.1",
|
|
87
85
|
"koa-conditional-get": "^3.0.0",
|
|
88
86
|
"openapi-typescript": "^7.8.0"
|
|
89
87
|
},
|
|
90
88
|
"devDependencies": {
|
|
91
89
|
"@eslint/js": "^9.39.1",
|
|
90
|
+
"@koa/bodyparser": "^6.1.0",
|
|
92
91
|
"@koa/cors": "^5.0.0",
|
|
93
92
|
"@koa/etag": "^5.0.2",
|
|
94
93
|
"@koa/router": "^15.3.1",
|
|
@@ -96,9 +95,7 @@
|
|
|
96
95
|
"@rvoh/dream-spec-helpers": "^2.1.1",
|
|
97
96
|
"@rvoh/psychic-spec-helpers": "3.0.0",
|
|
98
97
|
"@types/koa": "^3.0.1",
|
|
99
|
-
"@types/koa-bodyparser": "^4.3.12",
|
|
100
98
|
"@types/koa-conditional-get": "^2.0.3",
|
|
101
|
-
"@types/koa-etag": "^3.0.3",
|
|
102
99
|
"@types/koa-passport": "^6.0.3",
|
|
103
100
|
"@types/koa__cors": "^5.0.0",
|
|
104
101
|
"@types/koa__router": "^12.0.5",
|
|
@@ -114,7 +111,6 @@
|
|
|
114
111
|
"eslint": "^9.39.4",
|
|
115
112
|
"jsdom": "^26.1.0",
|
|
116
113
|
"koa": "^3.1.2",
|
|
117
|
-
"koa-bodyparser": "^4.4.1",
|
|
118
114
|
"koa-conditional-get": "^3.0.0",
|
|
119
115
|
"koa-passport": "^6.0.0",
|
|
120
116
|
"koa-session": "^7.0.2",
|