@appweaver/data 0.0.0-stage → 2.0.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 +21 -0
- package/README.md +61 -2
- package/config.d.ts +6 -0
- package/config.js +22 -0
- package/database/create-client.d.ts +11 -0
- package/database/create-client.js +145 -0
- package/database/database-config.d.ts +14 -0
- package/database/database-config.js +40 -0
- package/database/database-error.d.ts +49 -0
- package/database/database-error.js +216 -0
- package/database/index.d.ts +3 -0
- package/database/index.js +19 -0
- package/database/prisma-database.d.ts +33 -0
- package/database/prisma-database.js +178 -0
- package/database/run-transaction.d.ts +21 -0
- package/database/run-transaction.js +15 -0
- package/export/export-config.d.ts +7 -0
- package/export/export-config.js +17 -0
- package/export/export-service.d.ts +22 -0
- package/export/export-service.js +188 -0
- package/export/index.d.ts +1 -0
- package/export/index.js +17 -0
- package/factory/create-model.d.ts +11 -0
- package/factory/create-model.js +479 -0
- package/factory/create-policy.d.ts +12 -0
- package/factory/create-policy.js +20 -0
- package/factory/create-service.d.ts +14 -0
- package/factory/create-service.js +116 -0
- package/index.d.ts +22 -0
- package/index.js +38 -0
- package/internal.d.ts +2 -0
- package/internal.js +6 -0
- package/module.d.ts +3 -0
- package/module.js +81 -0
- package/package.json +67 -3
- package/prisma/client/browser.d.ts +39 -0
- package/prisma/client/browser.js +56 -0
- package/prisma/client/client.d.ts +58 -0
- package/prisma/client/client.js +70 -0
- package/prisma/client/commonInputTypes.d.ts +345 -0
- package/prisma/client/commonInputTypes.js +11 -0
- package/prisma/client/enums.d.ts +1 -0
- package/prisma/client/enums.js +11 -0
- package/prisma/client/internal/class.d.ts +198 -0
- package/prisma/client/internal/class.js +85 -0
- package/prisma/client/internal/prismaNamespace.d.ts +1125 -0
- package/prisma/client/internal/prismaNamespace.js +204 -0
- package/prisma/client/internal/prismaNamespaceBrowser.d.ts +137 -0
- package/prisma/client/internal/prismaNamespaceBrowser.js +175 -0
- package/prisma/client/models/ApiKey.d.ts +1167 -0
- package/prisma/client/models/ApiKey.js +2 -0
- package/prisma/client/models/ConnectedAccount.d.ts +1094 -0
- package/prisma/client/models/ConnectedAccount.js +2 -0
- package/prisma/client/models/File.d.ts +1291 -0
- package/prisma/client/models/File.js +2 -0
- package/prisma/client/models/OneTimeToken.d.ts +1055 -0
- package/prisma/client/models/OneTimeToken.js +2 -0
- package/prisma/client/models/Permission.d.ts +1209 -0
- package/prisma/client/models/Permission.js +2 -0
- package/prisma/client/models/Role.d.ts +1209 -0
- package/prisma/client/models/Role.js +2 -0
- package/prisma/client/models/Seeder.d.ts +1023 -0
- package/prisma/client/models/Seeder.js +2 -0
- package/prisma/client/models.d.ts +8 -0
- package/prisma/client/models.js +2 -0
- package/resource/load-data-resources.d.ts +13 -0
- package/resource/load-data-resources.js +37 -0
- package/resource/model-schema.d.ts +34 -0
- package/resource/model-schema.js +54 -0
- package/resource/resource-config.d.ts +16 -0
- package/resource/resource-config.js +62 -0
- package/resource/resource-loader.d.ts +25 -0
- package/resource/resource-loader.js +138 -0
- package/resource/resource-service.d.ts +462 -0
- package/resource/resource-service.js +1042 -0
- package/resource/schemas/index.d.ts +3 -0
- package/resource/schemas/index.js +19 -0
- package/resource/schemas/resource-aggregate-schema.d.ts +53 -0
- package/resource/schemas/resource-aggregate-schema.js +130 -0
- package/resource/schemas/resource-filter-schema.d.ts +39 -0
- package/resource/schemas/resource-filter-schema.js +153 -0
- package/resource/schemas/resource-sort-schema.d.ts +38 -0
- package/resource/schemas/resource-sort-schema.js +113 -0
- package/resource/utils/aggregate-util.d.ts +113 -0
- package/resource/utils/aggregate-util.js +322 -0
- package/resource/utils/cursor-util.d.ts +60 -0
- package/resource/utils/cursor-util.js +116 -0
- package/resource/utils/date-util.d.ts +22 -0
- package/resource/utils/date-util.js +112 -0
- package/resource/utils/delete-util.d.ts +131 -0
- package/resource/utils/delete-util.js +385 -0
- package/resource/utils/filter-util.d.ts +24 -0
- package/resource/utils/filter-util.js +289 -0
- package/resource/utils/prune-util.d.ts +11 -0
- package/resource/utils/prune-util.js +56 -0
- package/resource/utils/relation-util.d.ts +75 -0
- package/resource/utils/relation-util.js +400 -0
- package/resource/utils/sort-util.d.ts +31 -0
- package/resource/utils/sort-util.js +235 -0
- package/resource/utils/text-search-util.d.ts +14 -0
- package/resource/utils/text-search-util.js +39 -0
- package/resources.d.ts +10 -0
- package/resources.js +26 -0
- package/security/auth-config.d.ts +23 -0
- package/security/auth-config.js +43 -0
- package/security/create-auth-resources.d.ts +28 -0
- package/security/create-auth-resources.js +163 -0
- package/security/helper.d.ts +109 -0
- package/security/helper.js +298 -0
- package/security/resources/api-key/model.d.ts +2 -0
- package/security/resources/api-key/model.js +67 -0
- package/security/resources/api-key/policy.d.ts +2 -0
- package/security/resources/api-key/policy.js +27 -0
- package/security/resources/api-key/service.d.ts +3 -0
- package/security/resources/api-key/service.js +34 -0
- package/security/resources/connected-account/model.d.ts +2 -0
- package/security/resources/connected-account/model.js +57 -0
- package/security/resources/connected-account/service.d.ts +2 -0
- package/security/resources/connected-account/service.js +7 -0
- package/security/resources/one-time-token/model.d.ts +2 -0
- package/security/resources/one-time-token/model.js +36 -0
- package/security/resources/permission/model.d.ts +2 -0
- package/security/resources/permission/model.js +16 -0
- package/security/resources/role/model.d.ts +2 -0
- package/security/resources/role/model.js +22 -0
- package/security/store/database-security-store.d.ts +5 -0
- package/security/store/database-security-store.js +54 -0
- package/seeder/create-seeder.d.ts +29 -0
- package/seeder/create-seeder.js +28 -0
- package/seeder/index.d.ts +2 -0
- package/seeder/index.js +18 -0
- package/seeder/resources/seeder/model.d.ts +2 -0
- package/seeder/resources/seeder/model.js +38 -0
- package/seeder/seeder.d.ts +29 -0
- package/seeder/seeder.js +197 -0
- package/storage/file-service.d.ts +133 -0
- package/storage/file-service.js +586 -0
- package/storage/image-config.d.ts +3 -0
- package/storage/image-config.js +11 -0
- package/storage/resources/file/model.d.ts +2 -0
- package/storage/resources/file/model.js +80 -0
- package/types/auth.d.ts +23 -0
- package/types/auth.js +2 -0
- package/types/generated.d.ts +366 -0
- package/types/generated.js +3 -0
- package/types/storage.d.ts +35 -0
- package/types/storage.js +2 -0
- package/utils/export-util.d.ts +8 -0
- package/utils/export-util.js +26 -0
- package/utils/file-util.d.ts +106 -0
- package/utils/file-util.js +254 -0
- package/utils/model-util.d.ts +36 -0
- package/utils/model-util.js +154 -0
- package/utils/policy-util.d.ts +18 -0
- package/utils/policy-util.js +28 -0
- package/utils/virtual-util.d.ts +11 -0
- package/utils/virtual-util.js +53 -0
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export type * from './models/ApiKey';
|
|
2
|
+
export type * from './models/ConnectedAccount';
|
|
3
|
+
export type * from './models/OneTimeToken';
|
|
4
|
+
export type * from './models/Permission';
|
|
5
|
+
export type * from './models/Role';
|
|
6
|
+
export type * from './models/Seeder';
|
|
7
|
+
export type * from './models/File';
|
|
8
|
+
export type * from './commonInputTypes';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModuleSetupContext } from '@appweaver/common';
|
|
2
|
+
/**
|
|
3
|
+
* The setup of `@appweaver/data`: loads the models, services and policies of the application, then the resources of
|
|
4
|
+
* the modules, unless the `autoLoadResources` parameter of `createApp` is `false`.
|
|
5
|
+
*
|
|
6
|
+
* @param {ModuleSetupContext} setupContext - The setup context.
|
|
7
|
+
*/
|
|
8
|
+
export declare function loadDataResources(setupContext: ModuleSetupContext): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Warns about the file fields transforming their images (`image`) when no image processor is provided, since their
|
|
11
|
+
* images are then stored as they are uploaded.
|
|
12
|
+
*/
|
|
13
|
+
export declare function warnUnprocessedImages(): void;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadDataResources = loadDataResources;
|
|
4
|
+
exports.warnUnprocessedImages = warnUnprocessedImages;
|
|
5
|
+
const common_1 = require("@appweaver/common");
|
|
6
|
+
const core_1 = require("@appweaver/core");
|
|
7
|
+
const internal_1 = require("@appweaver/core/internal");
|
|
8
|
+
const resource_loader_1 = require("./resource-loader");
|
|
9
|
+
/**
|
|
10
|
+
* The setup of `@appweaver/data`: loads the models, services and policies of the application, then the resources of
|
|
11
|
+
* the modules, unless the `autoLoadResources` parameter of `createApp` is `false`.
|
|
12
|
+
*
|
|
13
|
+
* @param {ModuleSetupContext} setupContext - The setup context.
|
|
14
|
+
*/
|
|
15
|
+
async function loadDataResources(setupContext) {
|
|
16
|
+
if (setupContext.params.autoLoadResources === false) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
await (0, resource_loader_1.loadResources)(setupContext.scanPath, setupContext.params.resourcePaths, setupContext.modules.flatMap((module) => module.resources ? [module.resources] : []));
|
|
20
|
+
warnUnprocessedImages();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Warns about the file fields transforming their images (`image`) when no image processor is provided, since their
|
|
24
|
+
* images are then stored as they are uploaded.
|
|
25
|
+
*/
|
|
26
|
+
function warnUnprocessedImages() {
|
|
27
|
+
if ((0, core_1.isDefined)(common_1.ImageProcessor)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const fields = [...internal_1.context.resource.models.values()].flatMap((model) => Object.entries(model.config.files ?? {})
|
|
31
|
+
.filter(([, field]) => field?.image)
|
|
32
|
+
.map(([name]) => `${model.name}.${name}`));
|
|
33
|
+
if (fields.length > 0) {
|
|
34
|
+
common_1.logger.warn({ fields }, 'The images of these file fields are stored unprocessed, since no image processor is provided: install ' +
|
|
35
|
+
'@appweaver/sharp, or select one in IMAGE_PROVIDER');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { TObject, TSchema } from '@sinclair/typebox';
|
|
2
|
+
import { IdField } from '@appweaver/common';
|
|
3
|
+
export declare const ID_STRING_MAX_LENGTH = 36;
|
|
4
|
+
export declare const Id: TObject<{
|
|
5
|
+
id: import("@sinclair/typebox").TInteger;
|
|
6
|
+
}>;
|
|
7
|
+
export declare const IdString: TObject<{
|
|
8
|
+
id: import("@sinclair/typebox").TString;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* Builds the schema of a single primary key value, used wherever an id is
|
|
12
|
+
* accepted on its own (i.e. a relation input connecting an existing record).
|
|
13
|
+
*
|
|
14
|
+
* @param {IdField} [idField] - The id configuration, integer by default.
|
|
15
|
+
* @return {TSchema} The schema of the id value.
|
|
16
|
+
*/
|
|
17
|
+
export declare function idValueSchema(idField?: IdField): TSchema;
|
|
18
|
+
/**
|
|
19
|
+
* Builds the primary key schema of a model, used as the route path parameter
|
|
20
|
+
* and as the connection shape of the relation inputs pointing at the model. A
|
|
21
|
+
* fresh object per call, since each model annotates its own schemas.
|
|
22
|
+
*
|
|
23
|
+
* @param {IdField} [idField] - The id configuration, integer by default.
|
|
24
|
+
* @return {TObject} The primary key schema of the model.
|
|
25
|
+
*/
|
|
26
|
+
export declare function idSchema(idField?: IdField): TObject;
|
|
27
|
+
/**
|
|
28
|
+
* Builds the audit field schema of a model. The `createdById` field references
|
|
29
|
+
* the authentication model, so it follows that model's id type.
|
|
30
|
+
*
|
|
31
|
+
* @param {IdField} [authIdField] - The auth model id configuration, integer by default.
|
|
32
|
+
* @return {TObject} The schema holding all supported audit fields.
|
|
33
|
+
*/
|
|
34
|
+
export declare function auditSchema(authIdField?: IdField): TObject;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.IdString = exports.Id = exports.ID_STRING_MAX_LENGTH = void 0;
|
|
4
|
+
exports.idValueSchema = idValueSchema;
|
|
5
|
+
exports.idSchema = idSchema;
|
|
6
|
+
exports.auditSchema = auditSchema;
|
|
7
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
8
|
+
const common_1 = require("@appweaver/common");
|
|
9
|
+
// Maximum length of a string primary key, sized for the longest value the
|
|
10
|
+
// supported generators produce (a 36-character UUID)
|
|
11
|
+
exports.ID_STRING_MAX_LENGTH = 36;
|
|
12
|
+
exports.Id = typebox_1.Type.Object({
|
|
13
|
+
id: typebox_1.Type.Integer({ minimum: 1, example: 1 })
|
|
14
|
+
});
|
|
15
|
+
exports.IdString = typebox_1.Type.Object({
|
|
16
|
+
id: typebox_1.Type.String({ maxLength: exports.ID_STRING_MAX_LENGTH, example: 'a1b2c3d4' })
|
|
17
|
+
});
|
|
18
|
+
/**
|
|
19
|
+
* Builds the schema of a single primary key value, used wherever an id is
|
|
20
|
+
* accepted on its own (i.e. a relation input connecting an existing record).
|
|
21
|
+
*
|
|
22
|
+
* @param {IdField} [idField] - The id configuration, integer by default.
|
|
23
|
+
* @return {TSchema} The schema of the id value.
|
|
24
|
+
*/
|
|
25
|
+
function idValueSchema(idField) {
|
|
26
|
+
return (0, common_1.idFieldType)(idField) === 'string'
|
|
27
|
+
? exports.IdString.properties.id
|
|
28
|
+
: exports.Id.properties.id;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Builds the primary key schema of a model, used as the route path parameter
|
|
32
|
+
* and as the connection shape of the relation inputs pointing at the model. A
|
|
33
|
+
* fresh object per call, since each model annotates its own schemas.
|
|
34
|
+
*
|
|
35
|
+
* @param {IdField} [idField] - The id configuration, integer by default.
|
|
36
|
+
* @return {TObject} The primary key schema of the model.
|
|
37
|
+
*/
|
|
38
|
+
function idSchema(idField) {
|
|
39
|
+
return typebox_1.Type.Object({ id: idValueSchema(idField) });
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Builds the audit field schema of a model. The `createdById` field references
|
|
43
|
+
* the authentication model, so it follows that model's id type.
|
|
44
|
+
*
|
|
45
|
+
* @param {IdField} [authIdField] - The auth model id configuration, integer by default.
|
|
46
|
+
* @return {TObject} The schema holding all supported audit fields.
|
|
47
|
+
*/
|
|
48
|
+
function auditSchema(authIdField) {
|
|
49
|
+
return typebox_1.Type.Object({
|
|
50
|
+
updatedAt: (0, common_1.StringDate)(),
|
|
51
|
+
createdAt: (0, common_1.StringDate)(),
|
|
52
|
+
createdById: (0, common_1.Nullable)(idValueSchema(authIdField))
|
|
53
|
+
});
|
|
54
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { QueryMethod } from '@appweaver/common';
|
|
2
|
+
export declare const resourceConfig: Readonly<{
|
|
3
|
+
MODEL_PATTERN: string;
|
|
4
|
+
SERVICE_PATTERN: string;
|
|
5
|
+
POLICY_PATTERN: string;
|
|
6
|
+
ROUTES_PATTERN: string;
|
|
7
|
+
GENERATED_TYPES_PATH: string;
|
|
8
|
+
QUERY_METHOD: QueryMethod;
|
|
9
|
+
AGGREGATE_METHOD: QueryMethod;
|
|
10
|
+
BULK_CREATE_ENABLED: boolean;
|
|
11
|
+
BULK_UPDATE_ENABLED: boolean;
|
|
12
|
+
BULK_DELETE_ENABLED: boolean;
|
|
13
|
+
BULK_MAX_ITEMS: number;
|
|
14
|
+
BULK_TRANSACTION_TIMEOUT: number;
|
|
15
|
+
BULK_RETURN_RECORDS: boolean;
|
|
16
|
+
}>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.resourceConfig = void 0;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
5
|
+
const common_1 = require("@appweaver/common");
|
|
6
|
+
exports.resourceConfig = (0, common_1.defineConfig)('resource', {
|
|
7
|
+
/** Glob pattern for resource model files. Default: `'<srcPath>/resources/"*"/*model.ts'`. */
|
|
8
|
+
MODEL_PATTERN: typebox_1.Type.String({
|
|
9
|
+
default: '<srcPath>/resources/*/*model.ts'
|
|
10
|
+
}),
|
|
11
|
+
/** Glob pattern for resource service files. Default: `'<srcPath>/resources/"*"/*service.ts'`. */
|
|
12
|
+
SERVICE_PATTERN: typebox_1.Type.String({
|
|
13
|
+
default: '<srcPath>/resources/*/*service.ts'
|
|
14
|
+
}),
|
|
15
|
+
/** Glob pattern for resource policy files. Default: `'<srcPath>/resources/"*"/*policy.ts'`. */
|
|
16
|
+
POLICY_PATTERN: typebox_1.Type.String({
|
|
17
|
+
default: '<srcPath>/resources/*/*policy.ts'
|
|
18
|
+
}),
|
|
19
|
+
/** Glob pattern for resource routes files. Default: `'<srcPath>/resources/"*"/*routes.ts'`. */
|
|
20
|
+
ROUTES_PATTERN: typebox_1.Type.String({
|
|
21
|
+
default: '<srcPath>/resources/*/*routes.ts'
|
|
22
|
+
}),
|
|
23
|
+
/** Output path for generated TypeScript types. Default: `'<srcPath>/types/generated.ts'`. */
|
|
24
|
+
GENERATED_TYPES_PATH: typebox_1.Type.String({
|
|
25
|
+
default: '<srcPath>/types/generated.ts'
|
|
26
|
+
}),
|
|
27
|
+
/** HTTP methods of the resource query routes. Values: `post`, `get`, `get-post`. Default: `'post'`. */
|
|
28
|
+
QUERY_METHOD: typebox_1.Type.Enum(common_1.QueryMethod, {
|
|
29
|
+
default: common_1.QueryMethod.Post
|
|
30
|
+
}),
|
|
31
|
+
/** HTTP methods of the resource aggregate routes. Values: `post`, `get`, `get-post`. Default: `'post'`. */
|
|
32
|
+
AGGREGATE_METHOD: typebox_1.Type.Enum(common_1.QueryMethod, {
|
|
33
|
+
default: common_1.QueryMethod.Post
|
|
34
|
+
}),
|
|
35
|
+
/** Register the bulk create route of every resource, unless its route sets `exclude`. Default: `false`. */
|
|
36
|
+
BULK_CREATE_ENABLED: typebox_1.Type.Boolean({ default: false }),
|
|
37
|
+
/** Register the bulk update routes of every resource, unless its route sets `exclude`. Default: `false`. */
|
|
38
|
+
BULK_UPDATE_ENABLED: typebox_1.Type.Boolean({ default: false }),
|
|
39
|
+
/** Register the bulk delete route of every resource, unless its route sets `exclude`. Default: `false`. */
|
|
40
|
+
BULK_DELETE_ENABLED: typebox_1.Type.Boolean({ default: false }),
|
|
41
|
+
/** Maximum number of items a bulk create, update, or delete request accepts, unless its route sets `maxItems`.
|
|
42
|
+
* Default: `2000`. */
|
|
43
|
+
BULK_MAX_ITEMS: typebox_1.Type.Integer({ default: 2000, minimum: 1 }),
|
|
44
|
+
/** Timeout in milliseconds of the transaction a bulk request runs in. Default: `5000`. */
|
|
45
|
+
BULK_TRANSACTION_TIMEOUT: typebox_1.Type.Integer({ default: 5000 }),
|
|
46
|
+
/** Respond to a bulk request with the records it applied, the same as their single routes, or only with
|
|
47
|
+
* `{ success, count }` when `false`, unless its route sets `returnRecords`. Default: `true`. */
|
|
48
|
+
BULK_RETURN_RECORDS: typebox_1.Type.Boolean({ default: true })
|
|
49
|
+
}, {
|
|
50
|
+
// The path patterns are relative to the source directory of the application
|
|
51
|
+
transform: (values) => {
|
|
52
|
+
const withSource = (path) => path.replace('<srcPath>', common_1.appConfig.SOURCE_PATH);
|
|
53
|
+
return {
|
|
54
|
+
...values,
|
|
55
|
+
MODEL_PATTERN: withSource(values.MODEL_PATTERN),
|
|
56
|
+
SERVICE_PATTERN: withSource(values.SERVICE_PATTERN),
|
|
57
|
+
POLICY_PATTERN: withSource(values.POLICY_PATTERN),
|
|
58
|
+
ROUTES_PATTERN: withSource(values.ROUTES_PATTERN),
|
|
59
|
+
GENERATED_TYPES_PATH: withSource(values.GENERATED_TYPES_PATH)
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
});
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ResourceContext } from '@appweaver/core';
|
|
2
|
+
export type LoadResourcePaths = {
|
|
3
|
+
/** Path pattern used for finding files that export resource models (default: `./src/resources/"*"/*model.ts`) */
|
|
4
|
+
modelPattern?: string;
|
|
5
|
+
/** Path pattern used for finding files that export resource models (default: `./src/resources/"*"/*service.ts`) */
|
|
6
|
+
servicePattern?: string;
|
|
7
|
+
/** Path pattern used for finding files that export resource models (default: `./src/resources/"*"/*policy.ts`) */
|
|
8
|
+
policyPattern?: string;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Loads the application resources: models, services and policies.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} [baseDir] - Optional base directory path from which to load the resources.
|
|
14
|
+
* If not provided, defaults to the application's root directory.
|
|
15
|
+
* @param {LoadResourcePaths} [paths={}] Path patterns for loading the models, services and policies.
|
|
16
|
+
* @param {Array<() => unknown>} [moduleResources=[]] The loaders of the resources of the enabled modules, imported after
|
|
17
|
+
* the files of the application, so a module model can relate to a model of the application, i.e. its auth model.
|
|
18
|
+
* @return {Promise<ResourceContext>} A promise that resolves to an object containing
|
|
19
|
+
* the loaded resources:
|
|
20
|
+
*
|
|
21
|
+
* - `models`: The application models.
|
|
22
|
+
* - `services`: The application services.
|
|
23
|
+
* - `policies`: The access policies.
|
|
24
|
+
*/
|
|
25
|
+
export declare function loadResources(baseDir?: string, paths?: LoadResourcePaths, moduleResources?: Array<() => unknown>): Promise<Omit<ResourceContext, 'routes'>>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadResources = loadResources;
|
|
4
|
+
const typebox_1 = require("@sinclair/typebox");
|
|
5
|
+
const common_1 = require("@appweaver/common");
|
|
6
|
+
const resource_config_1 = require("./resource-config");
|
|
7
|
+
const file_util_1 = require("../utils/file-util");
|
|
8
|
+
const model_util_1 = require("../utils/model-util");
|
|
9
|
+
const internal_1 = require("@appweaver/core/internal");
|
|
10
|
+
const prune_util_1 = require("./utils/prune-util");
|
|
11
|
+
/**
|
|
12
|
+
* Loads the application resources: models, services and policies.
|
|
13
|
+
*
|
|
14
|
+
* @param {string} [baseDir] - Optional base directory path from which to load the resources.
|
|
15
|
+
* If not provided, defaults to the application's root directory.
|
|
16
|
+
* @param {LoadResourcePaths} [paths={}] Path patterns for loading the models, services and policies.
|
|
17
|
+
* @param {Array<() => unknown>} [moduleResources=[]] The loaders of the resources of the enabled modules, imported after
|
|
18
|
+
* the files of the application, so a module model can relate to a model of the application, i.e. its auth model.
|
|
19
|
+
* @return {Promise<ResourceContext>} A promise that resolves to an object containing
|
|
20
|
+
* the loaded resources:
|
|
21
|
+
*
|
|
22
|
+
* - `models`: The application models.
|
|
23
|
+
* - `services`: The application services.
|
|
24
|
+
* - `policies`: The access policies.
|
|
25
|
+
*/
|
|
26
|
+
async function loadResources(baseDir, paths = {}, moduleResources = []) {
|
|
27
|
+
const exports = (pattern) => findExports(pattern, baseDir ?? process.cwd(), moduleResources);
|
|
28
|
+
const models = await loadModels(await exports(paths.modelPattern || resource_config_1.resourceConfig.MODEL_PATTERN));
|
|
29
|
+
const services = loadServices(await exports(paths.servicePattern || resource_config_1.resourceConfig.SERVICE_PATTERN));
|
|
30
|
+
const policies = loadPolicies(await exports(paths.policyPattern || resource_config_1.resourceConfig.POLICY_PATTERN));
|
|
31
|
+
return {
|
|
32
|
+
models: new Map(Object.entries(models)),
|
|
33
|
+
services: new Map(Object.entries(services)),
|
|
34
|
+
policies: new Map(Object.entries(policies))
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function loadModels(exports) {
|
|
38
|
+
const models = {};
|
|
39
|
+
for (const modelSchema of exports) {
|
|
40
|
+
if ((0, common_1.isResourceModel)(modelSchema)) {
|
|
41
|
+
models[modelSchema.name] = modelSchema;
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
for (const maybeSchema of Object.values(modelSchema)) {
|
|
45
|
+
if ((0, common_1.isResourceModel)(maybeSchema)) {
|
|
46
|
+
models[maybeSchema.name] = maybeSchema;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// Leave out the models of the framework the application does not use
|
|
52
|
+
for (const name of (0, prune_util_1.pruneUnusedModels)(models)) {
|
|
53
|
+
internal_1.context.resource.models.delete(name);
|
|
54
|
+
internal_1.context.resource.services.delete(name);
|
|
55
|
+
internal_1.context.resource.policies.delete(name);
|
|
56
|
+
internal_1.context.resource.routes.delete(name);
|
|
57
|
+
}
|
|
58
|
+
// Resolve the schemas referencing the primary key of another model, now that
|
|
59
|
+
// every model is registered
|
|
60
|
+
(0, common_1.relinkResourceModels)(models);
|
|
61
|
+
// Reject a default value that its own field constraints would reject, since
|
|
62
|
+
// the records it produces cannot be serialized by the routes of their model
|
|
63
|
+
(0, model_util_1.validateScalarDefaults)(models);
|
|
64
|
+
// Reject file name patterns writing into a reserved storage path before any
|
|
65
|
+
// upload can reach the storage layer.
|
|
66
|
+
(0, file_util_1.validateFileNamePatterns)(models);
|
|
67
|
+
// Reject a cascade from a soft deleted model into one that removes its
|
|
68
|
+
// records, since the database cascade never runs on a soft delete
|
|
69
|
+
(0, model_util_1.validateSoftDeleteCascades)(models);
|
|
70
|
+
// Map model variants to schemas using their corresponding suffixes
|
|
71
|
+
const resourceModels = {};
|
|
72
|
+
for (const model of Object.values(models)) {
|
|
73
|
+
for (const [suffix, property] of Object.entries(common_1.resourceModelProps)) {
|
|
74
|
+
resourceModels[`${model.name}${suffix}`] = model[property];
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// Resolve all model references through the TypeBox module system
|
|
78
|
+
const module = typebox_1.Type.Module(resourceModels);
|
|
79
|
+
// Apply resolved models back to the resource schema definitions
|
|
80
|
+
for (const model of Object.values(models)) {
|
|
81
|
+
for (const [suffix, property] of Object.entries(common_1.resourceModelProps)) {
|
|
82
|
+
const schemaKey = `${model.name}${suffix}`;
|
|
83
|
+
const importedModel = module.Import(schemaKey);
|
|
84
|
+
model[property] = importedModel;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return models;
|
|
88
|
+
}
|
|
89
|
+
function loadServices(exports) {
|
|
90
|
+
const services = {};
|
|
91
|
+
for (const resourceService of exports) {
|
|
92
|
+
if ((0, common_1.isResourceService)(resourceService)) {
|
|
93
|
+
services[resourceService.modelName] = resourceService;
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
for (const maybeService of Object.values(resourceService)) {
|
|
97
|
+
if ((0, common_1.isResourceService)(maybeService)) {
|
|
98
|
+
services[maybeService.modelName] = maybeService;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return services;
|
|
104
|
+
}
|
|
105
|
+
function loadPolicies(exports) {
|
|
106
|
+
const policies = {};
|
|
107
|
+
for (const resourcePolicy of exports) {
|
|
108
|
+
if ((0, common_1.isResourcePolicy)(resourcePolicy)) {
|
|
109
|
+
policies[resourcePolicy.modelName] = resourcePolicy;
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
for (const maybePolicy of Object.values(resourcePolicy)) {
|
|
113
|
+
if ((0, common_1.isResourcePolicy)(maybePolicy)) {
|
|
114
|
+
policies[maybePolicy.modelName] = maybePolicy;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return policies;
|
|
120
|
+
}
|
|
121
|
+
/** The exports of the application files matching a pattern, then of the resources of the modules. */
|
|
122
|
+
async function findExports(pattern, cwd, moduleResources) {
|
|
123
|
+
const exports = [];
|
|
124
|
+
for (const filePath of await (0, common_1.findFilesByPattern)(pattern, cwd)) {
|
|
125
|
+
const { value, error } = await (0, common_1.importModule)(filePath);
|
|
126
|
+
if (error) {
|
|
127
|
+
common_1.logger.error(error, 'Resource path import error');
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (value) {
|
|
131
|
+
exports.push(value);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const load of moduleResources) {
|
|
135
|
+
exports.push(await load());
|
|
136
|
+
}
|
|
137
|
+
return exports;
|
|
138
|
+
}
|