@venizia/ignis-kernel 0.4.7-0 → 0.4.7-1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +1 -4
- package/dist/esm/base/applications/cors.d.ts +12 -10
- package/dist/esm/base/applications/cors.d.ts.map +1 -1
- package/dist/esm/base/applications/cors.js +37 -35
- package/dist/esm/base/applications/cors.js.map +1 -1
- package/dist/esm/base/applications/rest.js +11 -11
- package/dist/esm/base/applications/rest.js.map +1 -1
- package/dist/esm/base/auth/authenticate/common/codecs.js +2 -2
- package/dist/esm/base/auth/authenticate/common/codecs.js.map +1 -1
- package/dist/esm/base/auth/authenticate/strategies/strategy-registry.d.ts +1 -1
- package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js +1 -1
- package/dist/esm/base/auth/authenticate/strategies/strategy-registry.js.map +1 -1
- package/dist/esm/base/auth/authorize/providers/authorization.provider.js +7 -7
- package/dist/esm/base/auth/authorize/providers/authorization.provider.js.map +1 -1
- package/dist/esm/base/auth/authorize/providers/request-domain.d.ts +14 -11
- package/dist/esm/base/auth/authorize/providers/request-domain.d.ts.map +1 -1
- package/dist/esm/base/auth/authorize/providers/request-domain.js +42 -39
- package/dist/esm/base/auth/authorize/providers/request-domain.js.map +1 -1
- package/dist/esm/base/auth/base/abstract-auth-registry.js +2 -2
- package/dist/esm/base/auth/base/abstract-auth-registry.js.map +1 -1
- package/dist/esm/base/auth/models/requests/change-password.schema.js +3 -3
- package/dist/esm/base/auth/models/requests/change-password.schema.js.map +1 -1
- package/dist/esm/base/auth/models/requests/sign-in.schema.js +5 -5
- package/dist/esm/base/auth/models/requests/sign-in.schema.js.map +1 -1
- package/dist/esm/base/components/controller/rest/rest.component.js +2 -2
- package/dist/esm/base/components/controller/rest/rest.component.js.map +1 -1
- package/dist/esm/base/controllers/common/index.d.ts +0 -1
- package/dist/esm/base/controllers/common/index.d.ts.map +1 -1
- package/dist/esm/base/controllers/common/index.js +0 -1
- package/dist/esm/base/controllers/common/index.js.map +1 -1
- package/dist/esm/base/controllers/common/schema-builders.d.ts +0 -5
- package/dist/esm/base/controllers/common/schema-builders.d.ts.map +1 -1
- package/dist/esm/base/controllers/common/schema-builders.js +0 -14
- package/dist/esm/base/controllers/common/schema-builders.js.map +1 -1
- package/dist/esm/base/controllers/context.d.ts +7 -2
- package/dist/esm/base/controllers/context.d.ts.map +1 -1
- package/dist/esm/base/controllers/context.js +7 -4
- package/dist/esm/base/controllers/context.js.map +1 -1
- package/dist/esm/base/controllers/factory/controller.d.ts +33 -1
- package/dist/esm/base/controllers/factory/controller.d.ts.map +1 -1
- package/dist/esm/base/controllers/factory/controller.js +90 -6
- package/dist/esm/base/controllers/factory/controller.js.map +1 -1
- package/dist/esm/base/controllers/factory/definition.d.ts +1 -8
- package/dist/esm/base/controllers/factory/definition.d.ts.map +1 -1
- package/dist/esm/base/controllers/factory/definition.js +17 -24
- package/dist/esm/base/controllers/factory/definition.js.map +1 -1
- package/dist/esm/base/controllers/factory/index.d.ts +0 -1
- package/dist/esm/base/controllers/factory/index.d.ts.map +1 -1
- package/dist/esm/base/controllers/factory/index.js +0 -1
- package/dist/esm/base/controllers/factory/index.js.map +1 -1
- package/dist/esm/base/controllers/rest/abstract.d.ts.map +1 -1
- package/dist/esm/base/controllers/rest/abstract.js +6 -6
- package/dist/esm/base/controllers/rest/abstract.js.map +1 -1
- package/dist/esm/base/controllers/rest/base.d.ts +0 -5
- package/dist/esm/base/controllers/rest/base.d.ts.map +1 -1
- package/dist/esm/base/controllers/rest/base.js +14 -14
- package/dist/esm/base/controllers/rest/base.js.map +1 -1
- package/dist/esm/base/datasources/abstract.js +2 -2
- package/dist/esm/base/datasources/abstract.js.map +1 -1
- package/dist/esm/base/events/event-bus.js +4 -4
- package/dist/esm/base/events/event-bus.js.map +1 -1
- package/dist/esm/base/metadata/injectable.d.ts +7 -4
- package/dist/esm/base/metadata/injectable.d.ts.map +1 -1
- package/dist/esm/base/metadata/injectable.js +26 -23
- package/dist/esm/base/metadata/injectable.js.map +1 -1
- package/dist/esm/base/metadata/model-metadata.d.ts +27 -13
- package/dist/esm/base/metadata/model-metadata.d.ts.map +1 -1
- package/dist/esm/base/metadata/model-metadata.js +56 -26
- package/dist/esm/base/metadata/model-metadata.js.map +1 -1
- package/dist/esm/base/metadata/persistents.d.ts.map +1 -1
- package/dist/esm/base/metadata/persistents.js +21 -13
- package/dist/esm/base/metadata/persistents.js.map +1 -1
- package/dist/esm/base/metadata/routes/controller.d.ts.map +1 -1
- package/dist/esm/base/metadata/routes/controller.js +5 -2
- package/dist/esm/base/metadata/routes/controller.js.map +1 -1
- package/dist/esm/base/middlewares/app-error/app-error.middleware.js +7 -7
- package/dist/esm/base/middlewares/app-error/app-error.middleware.js.map +1 -1
- package/dist/esm/base/middlewares/app-error/database.handler.d.ts +14 -12
- package/dist/esm/base/middlewares/app-error/database.handler.d.ts.map +1 -1
- package/dist/esm/base/middlewares/app-error/database.handler.js +37 -35
- package/dist/esm/base/middlewares/app-error/database.handler.js.map +1 -1
- package/dist/esm/base/middlewares/app-error/zod.handler.d.ts +28 -23
- package/dist/esm/base/middlewares/app-error/zod.handler.d.ts.map +1 -1
- package/dist/esm/base/middlewares/app-error/zod.handler.js +56 -53
- package/dist/esm/base/middlewares/app-error/zod.handler.js.map +1 -1
- package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.d.ts +6 -4
- package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.d.ts.map +1 -1
- package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.js +14 -12
- package/dist/esm/base/middlewares/emoji-favicon/emoji-favicon.middleware.js.map +1 -1
- package/dist/esm/base/middlewares/form-body/form-body.middleware.d.ts +15 -11
- package/dist/esm/base/middlewares/form-body/form-body.middleware.d.ts.map +1 -1
- package/dist/esm/base/middlewares/form-body/form-body.middleware.js +25 -21
- package/dist/esm/base/middlewares/form-body/form-body.middleware.js.map +1 -1
- package/dist/esm/base/models/common/schemas.d.ts +184 -105
- package/dist/esm/base/models/common/schemas.d.ts.map +1 -1
- package/dist/esm/base/models/common/schemas.js +105 -54
- package/dist/esm/base/models/common/schemas.js.map +1 -1
- package/dist/esm/base/models/common/utilities.d.ts +10 -5
- package/dist/esm/base/models/common/utilities.d.ts.map +1 -1
- package/dist/esm/base/models/common/utilities.js +22 -16
- package/dist/esm/base/models/common/utilities.js.map +1 -1
- package/dist/esm/base/repositories/common/types/results.d.ts +15 -7
- package/dist/esm/base/repositories/common/types/results.d.ts.map +1 -1
- package/dist/esm/base/repositories/common/types/results.js +16 -7
- package/dist/esm/base/repositories/common/types/results.js.map +1 -1
- package/dist/esm/base/repositories/core/abstract.d.ts.map +1 -1
- package/dist/esm/base/repositories/core/abstract.js +5 -3
- package/dist/esm/base/repositories/core/abstract.js.map +1 -1
- package/dist/esm/base/repositories/query-schemas/index.d.ts +1 -1
- package/dist/esm/base/repositories/query-schemas/index.d.ts.map +1 -1
- package/dist/esm/base/repositories/query-schemas/index.js +3 -3
- package/dist/esm/base/repositories/query-schemas/index.js.map +1 -1
- package/dist/esm/helpers/inversion/common/relation-builder.js.map +1 -1
- package/dist/esm/helpers/inversion/index.d.ts +1 -1
- package/dist/esm/helpers/inversion/index.d.ts.map +1 -1
- package/dist/esm/helpers/inversion/index.js +1 -1
- package/dist/esm/helpers/inversion/index.js.map +1 -1
- package/dist/esm/helpers/inversion/mixins/repository.mixin.d.ts.map +1 -1
- package/dist/esm/helpers/inversion/mixins/repository.mixin.js +5 -5
- package/dist/esm/helpers/inversion/mixins/repository.mixin.js.map +1 -1
- package/dist/esm/metadata.d.ts +1 -1
- package/dist/esm/metadata.d.ts.map +1 -1
- package/dist/esm/metadata.js +1 -1
- package/dist/esm/metadata.js.map +1 -1
- package/dist/esm/repository.d.ts +2 -2
- package/dist/esm/repository.d.ts.map +1 -1
- package/dist/esm/repository.js +2 -2
- package/dist/esm/repository.js.map +1 -1
- package/dist/esm/utilities/index.d.ts +1 -1
- package/dist/esm/utilities/index.d.ts.map +1 -1
- package/dist/esm/utilities/index.js +1 -1
- package/dist/esm/utilities/index.js.map +1 -1
- package/dist/esm/utilities/not-supported.utility.d.ts +11 -0
- package/dist/esm/utilities/not-supported.utility.d.ts.map +1 -0
- package/dist/esm/utilities/not-supported.utility.js +19 -0
- package/dist/esm/utilities/not-supported.utility.js.map +1 -0
- package/package.json +6 -7
- package/dist/esm/base/controllers/common/html-response.d.ts +0 -70
- package/dist/esm/base/controllers/common/html-response.d.ts.map +0 -1
- package/dist/esm/base/controllers/common/html-response.js +0 -30
- package/dist/esm/base/controllers/common/html-response.js.map +0 -1
- package/dist/esm/base/controllers/factory/authorize-guard.d.ts +0 -19
- package/dist/esm/base/controllers/factory/authorize-guard.d.ts.map +0 -1
- package/dist/esm/base/controllers/factory/authorize-guard.js +0 -56
- package/dist/esm/base/controllers/factory/authorize-guard.js.map +0 -1
- package/dist/esm/base/controllers/factory/helper.d.ts +0 -2
- package/dist/esm/base/controllers/factory/helper.d.ts.map +0 -1
- package/dist/esm/base/controllers/factory/helper.js +0 -2
- package/dist/esm/base/controllers/factory/helper.js.map +0 -1
- package/dist/esm/base/controllers/factory/repository-injection.d.ts +0 -14
- package/dist/esm/base/controllers/factory/repository-injection.d.ts.map +0 -1
- package/dist/esm/base/controllers/factory/repository-injection.js +0 -27
- package/dist/esm/base/controllers/factory/repository-injection.js.map +0 -1
- package/dist/esm/base/metadata/model-settings.d.ts +0 -11
- package/dist/esm/base/metadata/model-settings.d.ts.map +0 -1
- package/dist/esm/base/metadata/model-settings.js +0 -30
- package/dist/esm/base/metadata/model-settings.js.map +0 -1
- package/dist/esm/utilities/error.utility.d.ts +0 -8
- package/dist/esm/utilities/error.utility.d.ts.map +0 -1
- package/dist/esm/utilities/error.utility.js +0 -14
- package/dist/esm/utilities/error.utility.js.map +0 -1
|
@@ -1,13 +1,28 @@
|
|
|
1
|
+
import type { IAuthorizationSpec } from '../../auth/authorize/common/types/index.js';
|
|
1
2
|
import type { AbstractEntity } from '../../models/index.js';
|
|
2
3
|
import type { AbstractRepository } from '../../repositories/index.js';
|
|
3
4
|
import type { TAnyObjectSchema } from '../common/schema-builders.js';
|
|
4
|
-
import type { AnyType, ValueOrPromise } from '@venizia/ignis-helpers/common';
|
|
5
|
+
import type { AnyType, TClass, ValueOrPromise } from '@venizia/ignis-helpers/common';
|
|
5
6
|
import { BaseHelper } from '@venizia/ignis-helpers/core';
|
|
6
7
|
import type { Env, Schema } from 'hono';
|
|
7
8
|
import type { ICrudControllerOptions, ICustomizableRoutes, TEntityDataObject, TEntityPersistObject } from '../common/index.js';
|
|
8
9
|
/** Factory for generating typed CRUD controllers from entity definitions. */
|
|
9
10
|
export declare class ControllerFactory extends BaseHelper {
|
|
11
|
+
/** The generated routes that change data: the ones that must never be answered by a `read` permission. */
|
|
12
|
+
private static readonly WRITE_VERBS;
|
|
10
13
|
constructor();
|
|
14
|
+
/**
|
|
15
|
+
* Injects `repositories.<repositoryName>` into constructor parameter 0 of a factory-generated
|
|
16
|
+
* controller, so a subclass needs no constructor. Recorded as metadata rather than a parameter
|
|
17
|
+
* decorator, which Bun drops in some configurations. A subclass that declares its own `@inject` at
|
|
18
|
+
* index 0 wins, and a sibling subclass keeps the factory's key.
|
|
19
|
+
*/
|
|
20
|
+
static registerRepositoryInjection(opts: {
|
|
21
|
+
target: TClass<unknown>;
|
|
22
|
+
factoryName: string;
|
|
23
|
+
controllerName: string;
|
|
24
|
+
repositoryName: string;
|
|
25
|
+
}): void;
|
|
11
26
|
static defineCrudController<TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>, Routes extends ICustomizableRoutes = ICustomizableRoutes, RouteEnv extends Env = Env, RouteSchema extends Schema = {}, BasePath extends string = '/', ConfigurableOptions extends object = {}, TDataObject extends object = TEntityDataObject<TEntity>, TPersistObject extends object = TEntityPersistObject<TEntity>>(defOpts: ICrudControllerOptions<TEntity, Routes>): {
|
|
12
27
|
new (repository: AbstractRepository<TDataObject, TPersistObject, AnyType>): {
|
|
13
28
|
/** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */
|
|
@@ -206,5 +221,22 @@ export declare class ControllerFactory extends BaseHelper {
|
|
|
206
221
|
getLogger(): import("@venizia/ignis-helpers/core").ILogger;
|
|
207
222
|
};
|
|
208
223
|
};
|
|
224
|
+
private static describeSpec;
|
|
225
|
+
/**
|
|
226
|
+
* Refuses a CRUD controller whose enabled write verb would inherit a controller-level `authorize`
|
|
227
|
+
* that is only a `read` permission: the verb would then answer to anyone who may read.
|
|
228
|
+
*
|
|
229
|
+
* A write verb is fine when it declares its own `authorize` (a spec, an array, or `{ skip: true }`),
|
|
230
|
+
* skips authentication, is not enabled, or the controller is `readonly`. Only the literal action
|
|
231
|
+
* `read` is detected; a custom action name is the application's own vocabulary. An array counts when
|
|
232
|
+
* every spec in it is `read`, since the specs of one route must all pass.
|
|
233
|
+
*/
|
|
234
|
+
static assertWriteVerbsDeclareAuthorize(opts: {
|
|
235
|
+
controllerName: string;
|
|
236
|
+
authorize: IAuthorizationSpec | IAuthorizationSpec[] | undefined;
|
|
237
|
+
routes: ICustomizableRoutes | undefined;
|
|
238
|
+
readonly: boolean | undefined;
|
|
239
|
+
enabledRoutes: Array<keyof ICustomizableRoutes> | undefined;
|
|
240
|
+
}): void;
|
|
209
241
|
}
|
|
210
242
|
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAEpD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAGlF,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AACrF,OAAO,EAAE,UAAU,EAAY,MAAM,6BAA6B,CAAC;AAEnE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACxC,OAAO,KAAK,EACV,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,oBAAoB,EACrB,MAAM,WAAW,CAAC;AAInB,6EAA6E;AAC7E,qBAAa,iBAAkB,SAAQ,UAAU;IAC/C,0GAA0G;IAC1G,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAMxB;;IAMX;;;;;OAKG;IACH,MAAM,CAAC,2BAA2B,CAAC,IAAI,EAAE;QACvC,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;KACxB,GAAG,IAAI;IAoBR,MAAM,CAAC,oBAAoB,CACzB,OAAO,SAAS,cAAc,CAAC,gBAAgB,CAAC,GAAG,cAAc,CAAC,gBAAgB,CAAC,EACnF,MAAM,SAAS,mBAAmB,GAAG,mBAAmB,EACxD,QAAQ,SAAS,GAAG,GAAG,GAAG,EAC1B,WAAW,SAAS,MAAM,GAAG,EAAE,EAC/B,QAAQ,SAAS,MAAM,GAAG,GAAG,EAC7B,mBAAmB,SAAS,MAAM,GAAG,EAAE,EACvC,WAAW,SAAS,MAAM,GAAG,iBAAiB,CAAC,OAAO,CAAC,EACvD,cAAc,SAAS,MAAM,GAAG,oBAAoB,CAAC,OAAO,CAAC,EAC7D,OAAO,EAAE,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC;yBAiDtB,kBAAkB,CAAC,WAAW,EAAE,cAAc,EAAE,OAAO,CAAC;YAUhF,iGAAiG;uBAC7E,cAAc,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAxDxC,CAAH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAiJD,OAAO,CAAC,MAAM,CAAC,YAAY;IAK3B;;;;;;;;OAQG;IACH,MAAM,CAAC,gCAAgC,CAAC,IAAI,EAAE;QAC5C,cAAc,EAAE,MAAM,CAAC;QACvB,SAAS,EAAE,kBAAkB,GAAG,kBAAkB,EAAE,GAAG,SAAS,CAAC;QACjE,MAAM,EAAE,mBAAmB,GAAG,SAAS,CAAC;QACxC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;QAC9B,aAAa,EAAE,KAAK,CAAC,MAAM,mBAAmB,CAAC,GAAG,SAAS,CAAC;KAC7D,GAAG,IAAI;CAgDT"}
|
|
@@ -1,15 +1,47 @@
|
|
|
1
|
+
import { AuthorizationActions } from '../../auth/authorize/common/constants/index.js';
|
|
1
2
|
import { SchemaTypes } from '../../models/common/constants.js';
|
|
3
|
+
import { BindingNamespaces } from '../../../common/bindings.js';
|
|
4
|
+
import { BindingKeys, MetadataRegistry } from '../../../helpers/inversion/index.js';
|
|
2
5
|
import { BaseHelper, getError } from '@venizia/ignis-helpers/core';
|
|
3
6
|
import { isClass } from '@venizia/ignis-inversion';
|
|
4
7
|
import { PersistableCrudController } from './crud/index.js';
|
|
5
|
-
import {
|
|
6
|
-
import { defineControllerRouteConfigs } from './definition.js';
|
|
7
|
-
import { registerFactoryRepositoryInjection } from './repository-injection.js';
|
|
8
|
+
import { RouteConfigResolver } from './definition.js';
|
|
8
9
|
/** Factory for generating typed CRUD controllers from entity definitions. */
|
|
9
10
|
export class ControllerFactory extends BaseHelper {
|
|
11
|
+
/** The generated routes that change data: the ones that must never be answered by a `read` permission. */
|
|
12
|
+
static { this.WRITE_VERBS = [
|
|
13
|
+
'create',
|
|
14
|
+
'updateById',
|
|
15
|
+
'updateBy',
|
|
16
|
+
'deleteById',
|
|
17
|
+
'deleteBy',
|
|
18
|
+
]; }
|
|
10
19
|
constructor() {
|
|
11
20
|
super({ scope: ControllerFactory.name });
|
|
12
21
|
}
|
|
22
|
+
/**
|
|
23
|
+
* Injects `repositories.<repositoryName>` into constructor parameter 0 of a factory-generated
|
|
24
|
+
* controller, so a subclass needs no constructor. Recorded as metadata rather than a parameter
|
|
25
|
+
* decorator, which Bun drops in some configurations. A subclass that declares its own `@inject` at
|
|
26
|
+
* index 0 wins, and a sibling subclass keeps the factory's key.
|
|
27
|
+
*/
|
|
28
|
+
static registerRepositoryInjection(opts) {
|
|
29
|
+
const { target, factoryName, controllerName, repositoryName } = opts;
|
|
30
|
+
if (!repositoryName) {
|
|
31
|
+
throw getError({
|
|
32
|
+
message: `[${factoryName}] Invalid repository name | controller: ${controllerName} | repository.name must name the repository binding`,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
MetadataRegistry.getInstance().setInjectMetadata({
|
|
36
|
+
target,
|
|
37
|
+
index: 0,
|
|
38
|
+
metadata: {
|
|
39
|
+
key: BindingKeys.build({ namespace: BindingNamespaces.REPOSITORY, key: repositoryName }),
|
|
40
|
+
index: 0,
|
|
41
|
+
isOptional: false,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
13
45
|
static defineCrudController(defOpts) {
|
|
14
46
|
const { controller, entity, authenticate, authorize, routes } = defOpts;
|
|
15
47
|
const { name, basePath = 'unknown_path', isStrict = { path: true, requestSchema: true }, } = controller;
|
|
@@ -18,7 +50,7 @@ export class ControllerFactory extends BaseHelper {
|
|
|
18
50
|
message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,
|
|
19
51
|
});
|
|
20
52
|
}
|
|
21
|
-
assertWriteVerbsDeclareAuthorize({
|
|
53
|
+
ControllerFactory.assertWriteVerbsDeclareAuthorize({
|
|
22
54
|
controllerName: name,
|
|
23
55
|
authorize,
|
|
24
56
|
routes,
|
|
@@ -27,7 +59,7 @@ export class ControllerFactory extends BaseHelper {
|
|
|
27
59
|
});
|
|
28
60
|
const entityClass = isClass(entity) ? entity : entity();
|
|
29
61
|
const entityInstance = new entityClass();
|
|
30
|
-
const routeDefinitions = defineControllerRouteConfigs({
|
|
62
|
+
const routeDefinitions = RouteConfigResolver.defineControllerRouteConfigs({
|
|
31
63
|
isStrict: isStrict.requestSchema ?? true,
|
|
32
64
|
idType: entityInstance.getIdType(),
|
|
33
65
|
authenticate,
|
|
@@ -121,7 +153,7 @@ export class ControllerFactory extends BaseHelper {
|
|
|
121
153
|
}
|
|
122
154
|
};
|
|
123
155
|
Object.defineProperty(controllerClass, 'name', { value: name, configurable: true });
|
|
124
|
-
|
|
156
|
+
ControllerFactory.registerRepositoryInjection({
|
|
125
157
|
target: controllerClass,
|
|
126
158
|
factoryName: 'defineCrudController',
|
|
127
159
|
controllerName: name,
|
|
@@ -129,5 +161,57 @@ export class ControllerFactory extends BaseHelper {
|
|
|
129
161
|
});
|
|
130
162
|
return controllerClass;
|
|
131
163
|
}
|
|
164
|
+
static describeSpec(opts) {
|
|
165
|
+
const { spec } = opts;
|
|
166
|
+
return `{ action: ${String(spec.action)}, resource: ${String(spec.resource)} }`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Refuses a CRUD controller whose enabled write verb would inherit a controller-level `authorize`
|
|
170
|
+
* that is only a `read` permission: the verb would then answer to anyone who may read.
|
|
171
|
+
*
|
|
172
|
+
* A write verb is fine when it declares its own `authorize` (a spec, an array, or `{ skip: true }`),
|
|
173
|
+
* skips authentication, is not enabled, or the controller is `readonly`. Only the literal action
|
|
174
|
+
* `read` is detected; a custom action name is the application's own vocabulary. An array counts when
|
|
175
|
+
* every spec in it is `read`, since the specs of one route must all pass.
|
|
176
|
+
*/
|
|
177
|
+
static assertWriteVerbsDeclareAuthorize(opts) {
|
|
178
|
+
const { controllerName, authorize, routes, readonly, enabledRoutes } = opts;
|
|
179
|
+
if (readonly || authorize == null) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const specs = Array.isArray(authorize) ? authorize : [authorize];
|
|
183
|
+
const isReadOnlyPermission = specs.length > 0 && specs.every((spec) => spec.action === AuthorizationActions.READ);
|
|
184
|
+
if (!isReadOnlyPermission) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const offending = ControllerFactory.WRITE_VERBS.filter((verb) => {
|
|
188
|
+
const isEnabled = enabledRoutes
|
|
189
|
+
? enabledRoutes.includes(verb)
|
|
190
|
+
: routes?.[verb]?.enabled !== false;
|
|
191
|
+
if (!isEnabled) {
|
|
192
|
+
return false;
|
|
193
|
+
}
|
|
194
|
+
const route = routes?.[verb];
|
|
195
|
+
return route?.authenticate?.skip !== true && route?.authorize == null;
|
|
196
|
+
});
|
|
197
|
+
if (offending.length === 0) {
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
const inherited = specs.map((spec) => ControllerFactory.describeSpec({ spec })).join(', ');
|
|
201
|
+
const verbs = offending.map((verb) => `${controllerName}.${verb}`).join(', ');
|
|
202
|
+
const hasBulkVerb = offending.some((verb) => verb === 'updateBy' || verb === 'deleteBy');
|
|
203
|
+
throw getError({
|
|
204
|
+
message: [
|
|
205
|
+
`[defineCrudController] Write routes would inherit a read-only authorize | controller: ${controllerName} | routes: ${verbs} | inherited: ${inherited}`,
|
|
206
|
+
'Anyone allowed to read could then create, update or delete.',
|
|
207
|
+
`Fix: declare routes.<verb>.authorize for each of them (a spec, an array or { skip: true }), or set controller.readonly, or leave them out of controller.enabledRoutes.`,
|
|
208
|
+
...(hasBulkVerb
|
|
209
|
+
? [
|
|
210
|
+
'updateBy and deleteBy are bulk routes on the collection and are generated unless controller.enabledRoutes lists the routes you want, so dropping them there closes this too.',
|
|
211
|
+
]
|
|
212
|
+
: []),
|
|
213
|
+
].join(' | '),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
132
216
|
}
|
|
133
217
|
//# sourceMappingURL=controller.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AbstractEntity } from '@/base/models';\nimport { SchemaTypes } from '@/base/models/common/constants';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport type { AnyType, ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { isClass } from '@venizia/ignis-inversion';\nimport type { Env, Schema } from 'hono';\nimport type {\n ICrudControllerOptions,\n ICustomizableRoutes,\n TEntityDataObject,\n TEntityPersistObject,\n} from '../common';\nimport { PersistableCrudController } from './crud';\nimport { assertWriteVerbsDeclareAuthorize } from './authorize-guard';\nimport { defineControllerRouteConfigs } from './definition';\nimport { registerFactoryRepositoryInjection } from './repository-injection';\n\n/** Factory for generating typed CRUD controllers from entity definitions. */\nexport class ControllerFactory extends BaseHelper {\n constructor() {\n super({ scope: ControllerFactory.name });\n }\n\n static defineCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n Routes extends ICustomizableRoutes = ICustomizableRoutes,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n >(defOpts: ICrudControllerOptions<TEntity, Routes>) {\n const { controller, entity, authenticate, authorize, routes } = defOpts;\n\n const {\n name,\n basePath = 'unknown_path',\n isStrict = { path: true, requestSchema: true },\n } = controller;\n if (!basePath || basePath === 'unknown_path') {\n throw getError({\n message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,\n });\n }\n\n assertWriteVerbsDeclareAuthorize({\n controllerName: name,\n authorize,\n routes,\n readonly: controller.readonly,\n enabledRoutes: controller.enabledRoutes,\n });\n\n const entityClass = isClass(entity) ? entity : entity();\n const entityInstance = new entityClass();\n\n const routeDefinitions = defineControllerRouteConfigs({\n isStrict: isStrict.requestSchema ?? true,\n idType: entityInstance.getIdType(),\n authenticate,\n authorize,\n routes,\n schema: {\n select: entityInstance.getSchema({ type: SchemaTypes.SELECT }),\n create: entityInstance.getSchema({ type: SchemaTypes.CREATE }),\n update: entityInstance.getSchema({ type: SchemaTypes.UPDATE }),\n },\n serverStampedKeys: entityInstance.getServerStampedKeys(),\n });\n\n const controllerClass = class extends PersistableCrudController<\n TEntity,\n RouteEnv,\n RouteSchema,\n BasePath,\n ConfigurableOptions,\n TDataObject,\n TPersistObject\n > {\n // Any extra options: a repository whose options narrow `IExtraOptions` (a typed transaction) must fit.\n constructor(repository: AbstractRepository<TDataObject, TPersistObject, AnyType>) {\n super({\n scope: name,\n path: basePath,\n isStrict: isStrict.path ?? true,\n repository,\n definitions: routeDefinitions,\n });\n }\n\n /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */\n override binding(): ValueOrPromise<void> {\n const isEnabled = (routeKey: keyof ICustomizableRoutes) => {\n if (controller.enabledRoutes) {\n return controller.enabledRoutes.includes(routeKey);\n }\n return routes?.[routeKey]?.enabled !== false;\n };\n\n // Read routes - always registered (unless explicitly disabled)\n if (isEnabled('count')) {\n this.defineRoute({\n configs: routeDefinitions.COUNT,\n handler: async (context) => this.count({ context }),\n });\n }\n\n if (isEnabled('find')) {\n this.defineRoute({\n configs: routeDefinitions.FIND,\n handler: async (context) => this.find({ context }),\n });\n }\n\n if (isEnabled('findOne')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_ONE,\n handler: async (context) => this.findOne({ context }),\n });\n }\n\n if (isEnabled('findById')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_BY_ID,\n handler: async (context) => this.findById({ context }),\n });\n }\n\n // Write routes - skipped when readonly\n if (controller.readonly) {\n return;\n }\n\n if (isEnabled('create')) {\n this.defineRoute({\n configs: routeDefinitions.CREATE,\n handler: async (context) => this.create({ context }),\n });\n }\n\n if (isEnabled('updateById')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY_ID,\n handler: async (context) => this.updateById({ context }),\n });\n }\n\n if (isEnabled('updateBy')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY,\n handler: async (context) => this.updateBy({ context }),\n });\n }\n\n if (isEnabled('deleteById')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY_ID,\n handler: async (context) => this.deleteById({ context }),\n });\n }\n\n if (isEnabled('deleteBy')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY,\n handler: async (context) => this.deleteBy({ context }),\n });\n }\n }\n };\n\n Object.defineProperty(controllerClass, 'name', { value: name, configurable: true });\n registerFactoryRepositoryInjection({\n target: controllerClass,\n factoryName: 'defineCrudController',\n controllerName: name,\n repositoryName: defOpts.repository.name,\n });\n return controllerClass;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { AuthorizationActions } from '@/base/auth/authorize/common/constants';\nimport type { IAuthorizationSpec } from '@/base/auth/authorize/common/types';\nimport type { AbstractEntity } from '@/base/models';\nimport { SchemaTypes } from '@/base/models/common/constants';\nimport type { AbstractRepository } from '@/base/repositories';\nimport type { TAnyObjectSchema } from '@/base/controllers/common/schema-builders';\nimport { BindingNamespaces } from '@/common/bindings';\nimport { BindingKeys, MetadataRegistry } from '@/helpers/inversion';\nimport type { AnyType, TClass, ValueOrPromise } from '@venizia/ignis-helpers/common';\nimport { BaseHelper, getError } from '@venizia/ignis-helpers/core';\nimport { isClass } from '@venizia/ignis-inversion';\nimport type { Env, Schema } from 'hono';\nimport type {\n ICrudControllerOptions,\n ICustomizableRoutes,\n TEntityDataObject,\n TEntityPersistObject,\n} from '../common';\nimport { PersistableCrudController } from './crud';\nimport { RouteConfigResolver } from './definition';\n\n/** Factory for generating typed CRUD controllers from entity definitions. */\nexport class ControllerFactory extends BaseHelper {\n /** The generated routes that change data: the ones that must never be answered by a `read` permission. */\n private static readonly WRITE_VERBS = [\n 'create',\n 'updateById',\n 'updateBy',\n 'deleteById',\n 'deleteBy',\n ] as const;\n\n constructor() {\n super({ scope: ControllerFactory.name });\n }\n\n /**\n * Injects `repositories.<repositoryName>` into constructor parameter 0 of a factory-generated\n * controller, so a subclass needs no constructor. Recorded as metadata rather than a parameter\n * decorator, which Bun drops in some configurations. A subclass that declares its own `@inject` at\n * index 0 wins, and a sibling subclass keeps the factory's key.\n */\n static registerRepositoryInjection(opts: {\n target: TClass<unknown>;\n factoryName: string;\n controllerName: string;\n repositoryName: string;\n }): void {\n const { target, factoryName, controllerName, repositoryName } = opts;\n\n if (!repositoryName) {\n throw getError({\n message: `[${factoryName}] Invalid repository name | controller: ${controllerName} | repository.name must name the repository binding`,\n });\n }\n\n MetadataRegistry.getInstance().setInjectMetadata({\n target,\n index: 0,\n metadata: {\n key: BindingKeys.build({ namespace: BindingNamespaces.REPOSITORY, key: repositoryName }),\n index: 0,\n isOptional: false,\n },\n });\n }\n\n static defineCrudController<\n TEntity extends AbstractEntity<TAnyObjectSchema> = AbstractEntity<TAnyObjectSchema>,\n Routes extends ICustomizableRoutes = ICustomizableRoutes,\n RouteEnv extends Env = Env,\n RouteSchema extends Schema = {},\n BasePath extends string = '/',\n ConfigurableOptions extends object = {},\n TDataObject extends object = TEntityDataObject<TEntity>,\n TPersistObject extends object = TEntityPersistObject<TEntity>,\n >(defOpts: ICrudControllerOptions<TEntity, Routes>) {\n const { controller, entity, authenticate, authorize, routes } = defOpts;\n\n const {\n name,\n basePath = 'unknown_path',\n isStrict = { path: true, requestSchema: true },\n } = controller;\n if (!basePath || basePath === 'unknown_path') {\n throw getError({\n message: `[defineCrudController] Invalid controller basePath | name: ${name} | basePath: ${basePath}`,\n });\n }\n\n ControllerFactory.assertWriteVerbsDeclareAuthorize({\n controllerName: name,\n authorize,\n routes,\n readonly: controller.readonly,\n enabledRoutes: controller.enabledRoutes,\n });\n\n const entityClass = isClass(entity) ? entity : entity();\n const entityInstance = new entityClass();\n\n const routeDefinitions = RouteConfigResolver.defineControllerRouteConfigs({\n isStrict: isStrict.requestSchema ?? true,\n idType: entityInstance.getIdType(),\n authenticate,\n authorize,\n routes,\n schema: {\n select: entityInstance.getSchema({ type: SchemaTypes.SELECT }),\n create: entityInstance.getSchema({ type: SchemaTypes.CREATE }),\n update: entityInstance.getSchema({ type: SchemaTypes.UPDATE }),\n },\n serverStampedKeys: entityInstance.getServerStampedKeys(),\n });\n\n const controllerClass = class extends PersistableCrudController<\n TEntity,\n RouteEnv,\n RouteSchema,\n BasePath,\n ConfigurableOptions,\n TDataObject,\n TPersistObject\n > {\n // Any extra options: a repository whose options narrow `IExtraOptions` (a typed transaction) must fit.\n constructor(repository: AbstractRepository<TDataObject, TPersistObject, AnyType>) {\n super({\n scope: name,\n path: basePath,\n isStrict: isStrict.path ?? true,\n repository,\n definitions: routeDefinitions,\n });\n }\n\n /** Registers each CRUD route whose handler tier supplies it, honoring enabledRoutes/readonly. */\n override binding(): ValueOrPromise<void> {\n const isEnabled = (routeKey: keyof ICustomizableRoutes) => {\n if (controller.enabledRoutes) {\n return controller.enabledRoutes.includes(routeKey);\n }\n return routes?.[routeKey]?.enabled !== false;\n };\n\n // Read routes - always registered (unless explicitly disabled)\n if (isEnabled('count')) {\n this.defineRoute({\n configs: routeDefinitions.COUNT,\n handler: async (context) => this.count({ context }),\n });\n }\n\n if (isEnabled('find')) {\n this.defineRoute({\n configs: routeDefinitions.FIND,\n handler: async (context) => this.find({ context }),\n });\n }\n\n if (isEnabled('findOne')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_ONE,\n handler: async (context) => this.findOne({ context }),\n });\n }\n\n if (isEnabled('findById')) {\n this.defineRoute({\n configs: routeDefinitions.FIND_BY_ID,\n handler: async (context) => this.findById({ context }),\n });\n }\n\n // Write routes - skipped when readonly\n if (controller.readonly) {\n return;\n }\n\n if (isEnabled('create')) {\n this.defineRoute({\n configs: routeDefinitions.CREATE,\n handler: async (context) => this.create({ context }),\n });\n }\n\n if (isEnabled('updateById')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY_ID,\n handler: async (context) => this.updateById({ context }),\n });\n }\n\n if (isEnabled('updateBy')) {\n this.defineRoute({\n configs: routeDefinitions.UPDATE_BY,\n handler: async (context) => this.updateBy({ context }),\n });\n }\n\n if (isEnabled('deleteById')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY_ID,\n handler: async (context) => this.deleteById({ context }),\n });\n }\n\n if (isEnabled('deleteBy')) {\n this.defineRoute({\n configs: routeDefinitions.DELETE_BY,\n handler: async (context) => this.deleteBy({ context }),\n });\n }\n }\n };\n\n Object.defineProperty(controllerClass, 'name', { value: name, configurable: true });\n ControllerFactory.registerRepositoryInjection({\n target: controllerClass,\n factoryName: 'defineCrudController',\n controllerName: name,\n repositoryName: defOpts.repository.name,\n });\n return controllerClass;\n }\n\n private static describeSpec(opts: { spec: IAuthorizationSpec }): string {\n const { spec } = opts;\n return `{ action: ${String(spec.action)}, resource: ${String(spec.resource)} }`;\n }\n\n /**\n * Refuses a CRUD controller whose enabled write verb would inherit a controller-level `authorize`\n * that is only a `read` permission: the verb would then answer to anyone who may read.\n *\n * A write verb is fine when it declares its own `authorize` (a spec, an array, or `{ skip: true }`),\n * skips authentication, is not enabled, or the controller is `readonly`. Only the literal action\n * `read` is detected; a custom action name is the application's own vocabulary. An array counts when\n * every spec in it is `read`, since the specs of one route must all pass.\n */\n static assertWriteVerbsDeclareAuthorize(opts: {\n controllerName: string;\n authorize: IAuthorizationSpec | IAuthorizationSpec[] | undefined;\n routes: ICustomizableRoutes | undefined;\n readonly: boolean | undefined;\n enabledRoutes: Array<keyof ICustomizableRoutes> | undefined;\n }): void {\n const { controllerName, authorize, routes, readonly, enabledRoutes } = opts;\n\n if (readonly || authorize == null) {\n return;\n }\n\n const specs = Array.isArray(authorize) ? authorize : [authorize];\n const isReadOnlyPermission =\n specs.length > 0 && specs.every((spec) => spec.action === AuthorizationActions.READ);\n\n if (!isReadOnlyPermission) {\n return;\n }\n\n const offending = ControllerFactory.WRITE_VERBS.filter((verb) => {\n const isEnabled = enabledRoutes\n ? enabledRoutes.includes(verb)\n : routes?.[verb]?.enabled !== false;\n if (!isEnabled) {\n return false;\n }\n\n const route = routes?.[verb];\n return route?.authenticate?.skip !== true && route?.authorize == null;\n });\n\n if (offending.length === 0) {\n return;\n }\n\n const inherited = specs.map((spec) => ControllerFactory.describeSpec({ spec })).join(', ');\n const verbs = offending.map((verb) => `${controllerName}.${verb}`).join(', ');\n const hasBulkVerb = offending.some((verb) => verb === 'updateBy' || verb === 'deleteBy');\n\n throw getError({\n message: [\n `[defineCrudController] Write routes would inherit a read-only authorize | controller: ${controllerName} | routes: ${verbs} | inherited: ${inherited}`,\n 'Anyone allowed to read could then create, update or delete.',\n `Fix: declare routes.<verb>.authorize for each of them (a spec, an array or { skip: true }), or set controller.readonly, or leave them out of controller.enabledRoutes.`,\n ...(hasBulkVerb\n ? [\n 'updateBy and deleteBy are bulk routes on the collection and are generated unless controller.enabledRoutes lists the routes you want, so dropping them there closes this too.',\n ]\n : []),\n ].join(' | '),\n });\n }\n}\n"]}
|
|
@@ -16,7 +16,7 @@ type TResolvedResponseSchema<C, D extends z.ZodType> = C extends {
|
|
|
16
16
|
* `this.other(...)`, or `this` is `undefined` at the call site.
|
|
17
17
|
*/
|
|
18
18
|
export declare class RouteConfigResolver {
|
|
19
|
-
/** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `
|
|
19
|
+
/** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `OpenApiSchemas.idParams` alone rejects `/accounts/7`. */
|
|
20
20
|
private static idPathParamsSchema;
|
|
21
21
|
/**
|
|
22
22
|
* The default body of a write route: the entity schema without the keys the entity stamps, and on
|
|
@@ -1138,12 +1138,5 @@ export declare class RouteConfigResolver {
|
|
|
1138
1138
|
};
|
|
1139
1139
|
};
|
|
1140
1140
|
}
|
|
1141
|
-
export declare const conditionalCountResponse: typeof RouteConfigResolver.conditionalCountResponse;
|
|
1142
|
-
export declare const resolveCountConfig: typeof RouteConfigResolver.resolveCountConfig;
|
|
1143
|
-
export declare const resolveFindConfig: typeof RouteConfigResolver.resolveFindConfig;
|
|
1144
|
-
export declare const resolveFindByIdConfig: typeof RouteConfigResolver.resolveFindByIdConfig;
|
|
1145
|
-
export declare const resolveFindOneConfig: typeof RouteConfigResolver.resolveFindOneConfig;
|
|
1146
|
-
export declare const resolveCreateConfig: typeof RouteConfigResolver.resolveCreateConfig;
|
|
1147
|
-
export declare const defineControllerRouteConfigs: typeof RouteConfigResolver.defineControllerRouteConfigs;
|
|
1148
1141
|
export {};
|
|
1149
1142
|
//# sourceMappingURL=definition.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/definition.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAC1F,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI1D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,CAAC,EAAE,MAAM,mBAAmB,CAAC;AAGtC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AASrD,8FAA8F;AAC9F,KAAK,uBAAuB,CAAC,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,OAAO,IAAI,CAAC,SAAS;IAC/D,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC;KACnC,CAAC;CACH,GACG,CAAC,GACD,CAAC,CAAC;AAEN;;;;GAIG;AACH,qBAAa,mBAAmB;IAC9B,
|
|
1
|
+
{"version":3,"file":"definition.d.ts","sourceRoot":"","sources":["../../../../../src/base/controllers/factory/definition.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { OpenApiResponses, OpenApiSchemas } from '../../models/common/index.js';
|
|
2
2
|
import { CountSchema } from '../../repositories/common/index.js';
|
|
3
3
|
import { FilterQuerySchema, WhereSchema } from '../../repositories/query-schemas/index.js';
|
|
4
4
|
import { z } from '@hono/zod-openapi';
|
|
@@ -11,11 +11,11 @@ import { commonResponseHeaders, defaultRequestHeaders, findResponseHeaders, Rest
|
|
|
11
11
|
* `this.other(...)`, or `this` is `undefined` at the call site.
|
|
12
12
|
*/
|
|
13
13
|
export class RouteConfigResolver {
|
|
14
|
-
/** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `
|
|
14
|
+
/** Path params always reach the validator as strings, so a number-typed id must be coerced before `z.number()` sees it - `OpenApiSchemas.idParams` alone rejects `/accounts/7`. */
|
|
15
15
|
static idPathParamsSchema(opts) {
|
|
16
16
|
const { idType } = opts;
|
|
17
17
|
if (idType !== 'number') {
|
|
18
|
-
return
|
|
18
|
+
return OpenApiSchemas.idParams({ idType });
|
|
19
19
|
}
|
|
20
20
|
return z.object({
|
|
21
21
|
id: z.coerce.number().openapi({
|
|
@@ -42,7 +42,7 @@ export class RouteConfigResolver {
|
|
|
42
42
|
}
|
|
43
43
|
if (!isObjectSchema || schema.def.checks?.length) {
|
|
44
44
|
throw getError({
|
|
45
|
-
message: `[defineControllerRouteConfigs] Cannot build the default ${route} body | keys to leave out: ${omittedKeys.join(', ')} | The schema is refined or transformed, so zod cannot remove them | Pass routes.${route}.request.body`,
|
|
45
|
+
message: `[RouteConfigResolver.defineControllerRouteConfigs] Cannot build the default ${route} body | keys to leave out: ${omittedKeys.join(', ')} | The schema is refined or transformed, so zod cannot remove them | Pass routes.${route}.request.body`,
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
const mask = {};
|
|
@@ -346,7 +346,7 @@ export class RouteConfigResolver {
|
|
|
346
346
|
authenticate: resolveRouteAuth('count'),
|
|
347
347
|
authorize: resolveRouteAuthorize('count'),
|
|
348
348
|
request: count.request,
|
|
349
|
-
responses: jsonResponse(count.response),
|
|
349
|
+
responses: OpenApiResponses.jsonResponse(count.response),
|
|
350
350
|
},
|
|
351
351
|
FIND: {
|
|
352
352
|
method: HTTP.Methods.GET,
|
|
@@ -355,7 +355,7 @@ export class RouteConfigResolver {
|
|
|
355
355
|
authenticate: resolveRouteAuth('find'),
|
|
356
356
|
authorize: resolveRouteAuthorize('find'),
|
|
357
357
|
request: find.request,
|
|
358
|
-
responses: jsonResponse(find.response),
|
|
358
|
+
responses: OpenApiResponses.jsonResponse(find.response),
|
|
359
359
|
},
|
|
360
360
|
FIND_BY_ID: {
|
|
361
361
|
method: HTTP.Methods.GET,
|
|
@@ -364,7 +364,7 @@ export class RouteConfigResolver {
|
|
|
364
364
|
authenticate: resolveRouteAuth('findById'),
|
|
365
365
|
authorize: resolveRouteAuthorize('findById'),
|
|
366
366
|
request: findById.request,
|
|
367
|
-
responses: jsonResponse(findById.response),
|
|
367
|
+
responses: OpenApiResponses.jsonResponse(findById.response),
|
|
368
368
|
},
|
|
369
369
|
FIND_ONE: {
|
|
370
370
|
method: HTTP.Methods.GET,
|
|
@@ -373,7 +373,7 @@ export class RouteConfigResolver {
|
|
|
373
373
|
authenticate: resolveRouteAuth('findOne'),
|
|
374
374
|
authorize: resolveRouteAuthorize('findOne'),
|
|
375
375
|
request: findOne.request,
|
|
376
|
-
responses: jsonResponse(findOne.response),
|
|
376
|
+
responses: OpenApiResponses.jsonResponse(findOne.response),
|
|
377
377
|
},
|
|
378
378
|
CREATE: {
|
|
379
379
|
method: HTTP.Methods.POST,
|
|
@@ -382,13 +382,13 @@ export class RouteConfigResolver {
|
|
|
382
382
|
authenticate: resolveRouteAuth('create'),
|
|
383
383
|
authorize: resolveRouteAuthorize('create'),
|
|
384
384
|
request: {
|
|
385
|
-
body: jsonContent({
|
|
385
|
+
body: OpenApiResponses.jsonContent({
|
|
386
386
|
description: 'Record data (required fields must be provided)',
|
|
387
387
|
schema: create.request.body,
|
|
388
388
|
}),
|
|
389
389
|
headers: create.request.headers,
|
|
390
390
|
},
|
|
391
|
-
responses: jsonResponse(create.response),
|
|
391
|
+
responses: OpenApiResponses.jsonResponse(create.response),
|
|
392
392
|
},
|
|
393
393
|
UPDATE_BY_ID: {
|
|
394
394
|
method: HTTP.Methods.PATCH,
|
|
@@ -398,13 +398,13 @@ export class RouteConfigResolver {
|
|
|
398
398
|
authorize: resolveRouteAuthorize('updateById'),
|
|
399
399
|
request: {
|
|
400
400
|
params: updateById.request.params,
|
|
401
|
-
body: jsonContent({
|
|
401
|
+
body: OpenApiResponses.jsonContent({
|
|
402
402
|
description: 'Partial data (only changed fields)',
|
|
403
403
|
schema: updateById.request.body,
|
|
404
404
|
}),
|
|
405
405
|
headers: updateById.request.headers,
|
|
406
406
|
},
|
|
407
|
-
responses: jsonResponse(updateById.response),
|
|
407
|
+
responses: OpenApiResponses.jsonResponse(updateById.response),
|
|
408
408
|
},
|
|
409
409
|
UPDATE_BY: {
|
|
410
410
|
method: HTTP.Methods.PATCH,
|
|
@@ -414,13 +414,13 @@ export class RouteConfigResolver {
|
|
|
414
414
|
authorize: resolveRouteAuthorize('updateBy'),
|
|
415
415
|
request: {
|
|
416
416
|
query: updateBy.request.query,
|
|
417
|
-
body: jsonContent({
|
|
417
|
+
body: OpenApiResponses.jsonContent({
|
|
418
418
|
description: 'Partial data to apply to all matches',
|
|
419
419
|
schema: updateBy.request.body,
|
|
420
420
|
}),
|
|
421
421
|
headers: updateBy.request.headers,
|
|
422
422
|
},
|
|
423
|
-
responses: jsonResponse(updateBy.response),
|
|
423
|
+
responses: OpenApiResponses.jsonResponse(updateBy.response),
|
|
424
424
|
},
|
|
425
425
|
DELETE_BY_ID: {
|
|
426
426
|
method: HTTP.Methods.DELETE,
|
|
@@ -429,7 +429,7 @@ export class RouteConfigResolver {
|
|
|
429
429
|
authenticate: resolveRouteAuth('deleteById'),
|
|
430
430
|
authorize: resolveRouteAuthorize('deleteById'),
|
|
431
431
|
request: deleteById.request,
|
|
432
|
-
responses: jsonResponse(deleteById.response),
|
|
432
|
+
responses: OpenApiResponses.jsonResponse(deleteById.response),
|
|
433
433
|
},
|
|
434
434
|
DELETE_BY: {
|
|
435
435
|
method: HTTP.Methods.DELETE,
|
|
@@ -441,7 +441,7 @@ export class RouteConfigResolver {
|
|
|
441
441
|
query: deleteBy.request.query,
|
|
442
442
|
...(deleteBy.request.body
|
|
443
443
|
? {
|
|
444
|
-
body: jsonContent({
|
|
444
|
+
body: OpenApiResponses.jsonContent({
|
|
445
445
|
description: 'Where condition, when it does not fit in the query',
|
|
446
446
|
schema: deleteBy.request.body,
|
|
447
447
|
required: false,
|
|
@@ -450,17 +450,10 @@ export class RouteConfigResolver {
|
|
|
450
450
|
: {}),
|
|
451
451
|
headers: deleteBy.request.headers,
|
|
452
452
|
},
|
|
453
|
-
responses: jsonResponse(deleteBy.response),
|
|
453
|
+
responses: OpenApiResponses.jsonResponse(deleteBy.response),
|
|
454
454
|
},
|
|
455
455
|
};
|
|
456
456
|
return rs;
|
|
457
457
|
}
|
|
458
458
|
}
|
|
459
|
-
export const conditionalCountResponse = RouteConfigResolver.conditionalCountResponse;
|
|
460
|
-
export const resolveCountConfig = RouteConfigResolver.resolveCountConfig;
|
|
461
|
-
export const resolveFindConfig = RouteConfigResolver.resolveFindConfig;
|
|
462
|
-
export const resolveFindByIdConfig = RouteConfigResolver.resolveFindByIdConfig;
|
|
463
|
-
export const resolveFindOneConfig = RouteConfigResolver.resolveFindOneConfig;
|
|
464
|
-
export const resolveCreateConfig = RouteConfigResolver.resolveCreateConfig;
|
|
465
|
-
export const defineControllerRouteConfigs = RouteConfigResolver.defineControllerRouteConfigs;
|
|
466
459
|
//# sourceMappingURL=definition.js.map
|