@nestledjs/api 0.0.10 → 0.0.11
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/package.json +4 -4
- package/src/app/files/src/app.module.ts__tmpl__ +2 -2
- package/src/app/files/src/main.ts__tmpl__ +19 -7
- package/src/app/generator.js +5 -6
- package/src/app/generator.js.map +1 -1
- package/src/config/files/src/index.ts__tmpl__ +1 -1
- package/src/config/files/src/lib/config.service.ts__tmpl__ +16 -2
- package/src/config/files/src/lib/configuration.ts__tmpl__ +1 -0
- package/src/config/generator.js +1 -1
- package/src/config/generator.js.map +1 -1
- package/src/core/files/helpers/src/index.ts__tmpl__ +1 -0
- package/src/core/files/helpers/src/lib/graphql-select.ts__tmpl__ +52 -0
- package/src/core/generator.js +5 -1
- package/src/core/generator.js.map +1 -1
- package/src/generate-crud/files/data-access/src/lib/api-crud-data-access.service.ts__tmpl__ +5 -9
- package/src/generate-crud/files/data-access/src/lib/dto/index.ts__tmpl__ +78 -147
- package/src/setup/generator.js +5 -6
- package/src/setup/generator.js.map +1 -1
- package/src/app/files/src/app.config.ts__tmpl__ +0 -66
- /package/src/config/files/src/lib/{config.modules.ts__tmpl__ → config.module.ts__tmpl__} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nestledjs/api",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.11",
|
|
4
4
|
"generators": "./generators.json",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"tslib": "^2.3.0",
|
|
20
|
-
"@nx/devkit": "21.2.
|
|
21
|
-
"@nx/js": "21.2.
|
|
20
|
+
"@nx/devkit": "21.2.1",
|
|
21
|
+
"@nx/js": "21.2.1",
|
|
22
22
|
"@prisma/internals": "^6.9.0",
|
|
23
23
|
"pluralize": "^8.0.0",
|
|
24
24
|
"dotenv": "16.4.5",
|
|
25
25
|
"pg": "^8.13.0"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
|
-
"@nestledjs/utils": "0.0.
|
|
28
|
+
"@nestledjs/utils": "0.0.11"
|
|
29
29
|
}
|
|
30
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { MiddlewareConsumer, Module, NestModule, RequestMethod } from '@nestjs/common'
|
|
2
2
|
import { LoggerMiddleware } from './applogger.middleware'
|
|
3
3
|
import { ConfigModule } from '@nestjs/config'
|
|
4
|
-
import {
|
|
4
|
+
import { configuration, validationSchema } from '@<%= npmScope %>/api/config'
|
|
5
5
|
|
|
6
6
|
// Auto-generated modules with special functions
|
|
7
7
|
export const coreModules = [
|
|
@@ -25,7 +25,7 @@ export const appModules = [
|
|
|
25
25
|
@Module({
|
|
26
26
|
imports: [
|
|
27
27
|
ConfigModule.forRoot({
|
|
28
|
-
load: [
|
|
28
|
+
load: [configuration],
|
|
29
29
|
validationSchema: validationSchema,
|
|
30
30
|
validationOptions: {
|
|
31
31
|
allowUnknown: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Logger } from '@nestjs/common'
|
|
2
2
|
import { NestFactory } from '@nestjs/core'
|
|
3
|
-
import { ConfigService } from '
|
|
3
|
+
import { ConfigService } from '@<%= npmScope %>/api/config'
|
|
4
4
|
import cookieParser from 'cookie-parser'
|
|
5
5
|
|
|
6
6
|
import { AppModule } from './app.module'
|
|
@@ -10,16 +10,28 @@ async function bootstrap() {
|
|
|
10
10
|
const configService = app.get(ConfigService)
|
|
11
11
|
|
|
12
12
|
// Get individual properties with fallbacks
|
|
13
|
-
const prefix = configService.
|
|
14
|
-
const port = configService.
|
|
15
|
-
const host = configService.
|
|
13
|
+
const prefix = configService.prefix || 'api';
|
|
14
|
+
const port = configService.port || 3000;
|
|
15
|
+
const host = configService.host || 'localhost';
|
|
16
16
|
|
|
17
17
|
app.setGlobalPrefix(prefix)
|
|
18
|
+
|
|
19
|
+
// Use the apiCorsOrigins getter and handle as array
|
|
20
|
+
const origins = configService.apiCorsOrigins.length
|
|
21
|
+
? configService.apiCorsOrigins
|
|
22
|
+
: ['http://localhost:4200']; // fallback for dev
|
|
23
|
+
|
|
18
24
|
app.enableCors({
|
|
19
25
|
credentials: true,
|
|
20
|
-
origin:
|
|
21
|
-
|
|
22
|
-
|
|
26
|
+
origin: (origin, callback) => {
|
|
27
|
+
if (!origin) return callback(null, true);
|
|
28
|
+
if (origins.includes(origin)) {
|
|
29
|
+
return callback(null, true);
|
|
30
|
+
}
|
|
31
|
+
return callback(new Error('Not allowed by CORS'));
|
|
32
|
+
},
|
|
33
|
+
});
|
|
34
|
+
app.use(cookieParser(configService.cookie.secret || 'secret'));
|
|
23
35
|
|
|
24
36
|
await app.listen(port, host, () => {
|
|
25
37
|
Logger.log(`Listening at http://${host}:${port}/${prefix}`)
|
package/src/app/generator.js
CHANGED
|
@@ -33,11 +33,11 @@ function default_1(tree, schema) {
|
|
|
33
33
|
try {
|
|
34
34
|
// Get the workspace root directory
|
|
35
35
|
const workspaceRoot = tree.root;
|
|
36
|
-
// Create apps directory if it doesn't exist
|
|
36
|
+
// Create the apps directory if it doesn't exist
|
|
37
37
|
if (!tree.exists('apps')) {
|
|
38
38
|
tree.write('apps/.gitkeep', '');
|
|
39
39
|
}
|
|
40
|
-
// Run the Nx generator command directly from the workspace root with proper workspace layout
|
|
40
|
+
// Run the Nx generator command directly from the workspace root with the proper workspace layout
|
|
41
41
|
(0, child_process_1.execSync)('nx g @nx/nest:application --name api --directory apps/api --no-interactive', {
|
|
42
42
|
stdio: 'inherit',
|
|
43
43
|
cwd: workspaceRoot,
|
|
@@ -50,13 +50,12 @@ function default_1(tree, schema) {
|
|
|
50
50
|
(0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, './files'), path.join('apps', 'api'), Object.assign(Object.assign({}, schema), { tmpl: '', npmScope: (0, get_npm_scope_1.getNpmScope)(tree) }));
|
|
51
51
|
// Add dev:api script to package.json
|
|
52
52
|
(0, devkit_1.updateJson)(tree, 'package.json', (json) => {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
53
|
+
var _a;
|
|
54
|
+
(_a = json.scripts) !== null && _a !== void 0 ? _a : (json.scripts = {});
|
|
56
55
|
json.scripts['dev:api'] = 'nx serve api --skip-nx-cache';
|
|
57
56
|
return json;
|
|
58
57
|
});
|
|
59
|
-
// Update the build target in apps/api/project.json to use custom webpack command
|
|
58
|
+
// Update the build target in apps/api/project.json to use the custom webpack command
|
|
60
59
|
const projectJsonPath = path.join('apps', 'api', 'project.json');
|
|
61
60
|
if (tree.exists(projectJsonPath)) {
|
|
62
61
|
(0, devkit_1.updateJson)(tree, projectJsonPath, (json) => {
|
package/src/app/generator.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/app/generator.ts"],"names":[],"mappings":";;AA+BA,
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/app/generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -14,8 +14,22 @@ export class ConfigService {
|
|
|
14
14
|
return this.config.get<string[]>('api.cors.origin') ?? []
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
get cookie(): { name: string; options: CookieOptions } {
|
|
18
|
-
return this.config.getOrThrow<{ name: string; options: CookieOptions }>(
|
|
17
|
+
get cookie(): { name: string; secret: string; options: CookieOptions } {
|
|
18
|
+
return this.config.getOrThrow<{ name: string; secret: string; options: CookieOptions }>(
|
|
19
|
+
'api.cookie',
|
|
20
|
+
)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
get prefix(): string {
|
|
24
|
+
return this.config.getOrThrow<string>('prefix')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
get port(): number {
|
|
28
|
+
return this.config.getOrThrow<number>('port')
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
get host(): string {
|
|
32
|
+
return this.config.getOrThrow<string>('host')
|
|
19
33
|
}
|
|
20
34
|
|
|
21
35
|
get appEmail(): string {
|
package/src/config/generator.js
CHANGED
|
@@ -8,7 +8,7 @@ function generateLibraries(tree_1) {
|
|
|
8
8
|
return tslib_1.__awaiter(this, arguments, void 0, function* (tree, options = {}) {
|
|
9
9
|
const templateRootPath = (0, devkit_1.joinPathFragments)(__dirname, './files');
|
|
10
10
|
const overwrite = options.overwrite === true;
|
|
11
|
-
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'config', overwrite }, templateRootPath);
|
|
11
|
+
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'config', overwrite, customName: true }, templateRootPath);
|
|
12
12
|
yield (0, devkit_1.formatFiles)(tree);
|
|
13
13
|
return () => {
|
|
14
14
|
(0, devkit_1.installPackagesTask)(tree);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/config/generator.ts"],"names":[],"mappings":";;AAIA,oCAWC;;AAfD,uCAAsF;AACtF,4CAAsD;AAGtD,SAA8B,iBAAiB;iEAAC,IAAU,EAAE,UAAoC,EAAE;QAChG,MAAM,gBAAgB,GAAG,IAAA,0BAAiB,EAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAChE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,IAAI,CAAA;QAE5C,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,gBAAgB,CAAC,CAAA;
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/config/generator.ts"],"names":[],"mappings":";;AAIA,oCAWC;;AAfD,uCAAsF;AACtF,4CAAsD;AAGtD,SAA8B,iBAAiB;iEAAC,IAAU,EAAE,UAAoC,EAAE;QAChG,MAAM,gBAAgB,GAAG,IAAA,0BAAiB,EAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAChE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,IAAI,CAAA;QAE5C,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,gBAAgB,CAAC,CAAA;QAElG,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAA;QAEvB,OAAO,GAAG,EAAE;YACV,IAAA,4BAAmB,EAAC,IAAI,CAAC,CAAA;QAC3B,CAAC,CAAA;IACH,CAAC;CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './lib/graphql-select'
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import graphqlFields from 'graphql-fields'
|
|
2
|
+
import { Prisma } from '@<%= npmScope %>/api/prisma'
|
|
3
|
+
import type { DMMF } from '@prisma/client/runtime/library'
|
|
4
|
+
import { GraphQLResolveInfo } from 'graphql/type'
|
|
5
|
+
|
|
6
|
+
const dmmf = Prisma.dmmf
|
|
7
|
+
|
|
8
|
+
function getNamedType(type: any): string {
|
|
9
|
+
if (type.ofType) return getNamedType(type.ofType)
|
|
10
|
+
return type.name
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function getModelFromTypeName(typeName: string) {
|
|
14
|
+
return dmmf.datamodel.models.find(m => m.name === typeName)
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function buildSelectTree(fieldTree: any, model: any): any {
|
|
18
|
+
const result: Record<string, any> = {}
|
|
19
|
+
|
|
20
|
+
for (const key in fieldTree) {
|
|
21
|
+
const field = model.fields.find((f: DMMF.Field) => f.name === key)
|
|
22
|
+
if (!field) continue
|
|
23
|
+
|
|
24
|
+
if (field.relationName && typeof fieldTree[key] === 'object') {
|
|
25
|
+
const relatedModel = dmmf.datamodel.models.find(m => m.name === field.type)
|
|
26
|
+
if (relatedModel) {
|
|
27
|
+
result[key] = {
|
|
28
|
+
select: buildSelectTree(fieldTree[key], relatedModel),
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
result[key] = true
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Automatically converts a GraphQL `info` object into a Prisma `select` object.
|
|
41
|
+
*/
|
|
42
|
+
export function createSelect(info: GraphQLResolveInfo) {
|
|
43
|
+
const returnTypeName = getNamedType(info.returnType)
|
|
44
|
+
const model = getModelFromTypeName(returnTypeName)
|
|
45
|
+
|
|
46
|
+
if (!model) {
|
|
47
|
+
throw new Error(`Model "${returnTypeName}" not found in Prisma schema.`)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const rawFields = graphqlFields(info)
|
|
51
|
+
return buildSelectTree(rawFields, model)
|
|
52
|
+
}
|
package/src/core/generator.js
CHANGED
|
@@ -16,12 +16,16 @@ function generateLibraries(tree_1) {
|
|
|
16
16
|
'@nestjs/axios': '^3.0.0',
|
|
17
17
|
'@prisma/client': '^6.9.0',
|
|
18
18
|
'@apollo/server': '^4.9.0',
|
|
19
|
+
'graphql-fields': '^2.0.3',
|
|
20
|
+
};
|
|
21
|
+
const devDependencies = {
|
|
22
|
+
'@types/graphql-fields': '^1.3.9',
|
|
19
23
|
};
|
|
20
|
-
const devDependencies = {};
|
|
21
24
|
yield (0, utils_1.installPlugins)(tree, dependencies, devDependencies);
|
|
22
25
|
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'core', overwrite }, templateRootPath, 'data-access');
|
|
23
26
|
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'core', overwrite }, templateRootPath, 'feature', true);
|
|
24
27
|
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'core', overwrite }, templateRootPath, 'models');
|
|
28
|
+
yield (0, utils_1.apiLibraryGenerator)(tree, { name: 'core', overwrite }, templateRootPath, 'helpers');
|
|
25
29
|
yield (0, devkit_1.formatFiles)(tree);
|
|
26
30
|
return () => {
|
|
27
31
|
(0, devkit_1.installPackagesTask)(tree);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/core/generator.ts"],"names":[],"mappings":";;AAIA,
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/core/generator.ts"],"names":[],"mappings":";;AAIA,oCAkCC;;AAtCD,uCAAyG;AACzG,4CAAsE;AAGtE,SAA8B,iBAAiB;iEAC7C,IAAU,EACV,UAAkC,EAAE;QAEpC,MAAM,gBAAgB,GAAG,IAAA,0BAAiB,EAAC,SAAS,EAAE,SAAS,CAAC,CAAA;QAChE,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,KAAK,IAAI,CAAA;QAE5C,MAAM,YAAY,GAAG;YACnB,mBAAmB,EAAE,QAAQ;YAC7B,iBAAiB,EAAE,SAAS;YAC5B,gBAAgB,EAAE,SAAS;YAC3B,kBAAkB,EAAE,SAAS;YAC7B,eAAe,EAAE,QAAQ;YACzB,gBAAgB,EAAE,QAAQ;YAC1B,gBAAgB,EAAE,QAAQ;YAC1B,gBAAgB,EAAE,QAAQ;SAC3B,CAAA;QAED,MAAM,eAAe,GAAG;YACtB,uBAAuB,EAAE,QAAQ;SAClC,CAAA;QAED,MAAM,IAAA,sBAAc,EAAC,IAAI,EAAE,YAAY,EAAE,eAAe,CAAC,CAAA;QAEzD,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,gBAAgB,EAAE,aAAa,CAAC,CAAA;QAC7F,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,gBAAgB,EAAE,SAAS,EAAE,IAAI,CAAC,CAAA;QAC/F,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,gBAAgB,EAAE,QAAQ,CAAC,CAAA;QACxF,MAAM,IAAA,2BAAmB,EAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,gBAAgB,EAAE,SAAS,CAAC,CAAA;QAEzF,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAA;QAEvB,OAAO,GAAG,EAAE;YACV,IAAA,4BAAmB,EAAC,IAAI,CAAC,CAAA;QAC3B,CAAC,CAAA;IACH,CAAC;CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Injectable } from '@nestjs/common'
|
|
2
2
|
import { ApiCoreDataAccessService } from '@<%= npmScope %>/api/core/data-access'
|
|
3
|
-
import {
|
|
3
|
+
import { createSelect } from '@<%= npmScope %>/api/core/helpers'
|
|
4
4
|
import type { GraphQLResolveInfo } from 'graphql'
|
|
5
5
|
import * as dto from './dto'
|
|
6
6
|
|
|
@@ -14,18 +14,16 @@ export class ApiCrudDataAccessService {
|
|
|
14
14
|
|
|
15
15
|
<% for (const model of models) { %>
|
|
16
16
|
async create<%= model.modelName.charAt(0).toUpperCase() + model.modelName.slice(1) %>(info: GraphQLResolveInfo, input: dto.Create<%= model.modelName %>Input) {
|
|
17
|
-
const select = new PrismaSelect(info).value
|
|
18
17
|
return this.data['<%= model.modelPropertyName %>'].create({
|
|
19
18
|
data: input,
|
|
20
|
-
|
|
19
|
+
select: createSelect(info),
|
|
21
20
|
});
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
async <%= (model.pluralModelName === model.modelName ? model.pluralModelName + 'List' : model.pluralModelName).charAt(0).toLowerCase() + (model.pluralModelName === model.modelName ? model.pluralModelName + 'List' : model.pluralModelName).slice(1) %>(info: GraphQLResolveInfo, input?: dto.List<%= model.modelName %>Input) {
|
|
25
|
-
const select = new PrismaSelect(info).value
|
|
26
24
|
return this.data['<%= model.modelPropertyName %>'].findMany({
|
|
27
25
|
...this.data.filter(input),
|
|
28
|
-
|
|
26
|
+
select: createSelect(info),
|
|
29
27
|
});
|
|
30
28
|
}
|
|
31
29
|
|
|
@@ -47,19 +45,17 @@ export class ApiCrudDataAccessService {
|
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
async <%= model.modelName.charAt(0).toLowerCase() + model.modelName.slice(1) %>(info: GraphQLResolveInfo, id: string) {
|
|
50
|
-
const select = new PrismaSelect(info).value
|
|
51
48
|
return this.data['<%= model.modelPropertyName %>'].findUnique({
|
|
52
49
|
where: { id },
|
|
53
|
-
|
|
50
|
+
select: createSelect(info),
|
|
54
51
|
});
|
|
55
52
|
}
|
|
56
53
|
|
|
57
54
|
async update<%= model.modelName.charAt(0).toUpperCase() + model.modelName.slice(1) %>(info: GraphQLResolveInfo, id: string, input: dto.Update<%= model.modelName %>Input) {
|
|
58
|
-
const select = new PrismaSelect(info).value
|
|
59
55
|
return this.data['<%= model.modelPropertyName %>'].update({
|
|
60
56
|
where: { id },
|
|
61
57
|
data: input,
|
|
62
|
-
|
|
58
|
+
select: createSelect(info),
|
|
63
59
|
});
|
|
64
60
|
}
|
|
65
61
|
|
|
@@ -6,26 +6,19 @@ let usesInt = false;
|
|
|
6
6
|
let usesFloat = false;
|
|
7
7
|
let usesID = false;
|
|
8
8
|
let enumNames = new Set();
|
|
9
|
+
let usesPartialType = false;
|
|
10
|
+
const alwaysOptionalFields = ['id', 'createdAt', 'updatedAt'];
|
|
9
11
|
|
|
10
12
|
// First pass to determine necessary imports and enums
|
|
11
13
|
for (const model of models) {
|
|
12
14
|
for (const field of model.fields) {
|
|
15
|
+
if (field.kind === 'object') continue; // Skip relation fields entirely
|
|
13
16
|
if (field.type === 'Int') usesInt = true;
|
|
14
17
|
if (field.type === 'Float' || field.type === 'Decimal') usesFloat = true;
|
|
15
18
|
if (field.type === 'Json') usesGraphQLJSON = true;
|
|
16
|
-
|
|
17
|
-
if (field.
|
|
18
|
-
|
|
19
|
-
} else if (field.kind === 'object') {
|
|
20
|
-
// Check if a corresponding scalar ID field (e.g., 'userId') exists for this object field (e.g., 'user')
|
|
21
|
-
const correspondingIdFieldName = `${field.name}Id`;
|
|
22
|
-
const hasCorrespondingIdField = model.fields.some(f => f.name === correspondingIdFieldName && f.kind !== 'object');
|
|
23
|
-
if (!hasCorrespondingIdField) {
|
|
24
|
-
// If no pre-existing '...Id' scalar, we'll generate one, so 'ID' import is needed.
|
|
25
|
-
usesID = true;
|
|
26
|
-
}
|
|
27
|
-
} else if (field.kind === 'enum') {
|
|
28
|
-
enumNames.add(field.type);
|
|
19
|
+
if (field.type === 'ID') usesID = true;
|
|
20
|
+
if (field.kind === 'enum') {
|
|
21
|
+
enumNames.add(field.type);
|
|
29
22
|
}
|
|
30
23
|
}
|
|
31
24
|
}
|
|
@@ -33,9 +26,9 @@ for (const model of models) {
|
|
|
33
26
|
if (usesInt) gqlImports.add('Int');
|
|
34
27
|
if (usesFloat) gqlImports.add('Float');
|
|
35
28
|
if (usesID) gqlImports.add('ID');
|
|
29
|
+
usesPartialType = models.length > 0; // If we generate any Update input, we need PartialType
|
|
36
30
|
%>
|
|
37
31
|
import { <%= Array.from(gqlImports).join(', ') %> } from '@nestjs/graphql'
|
|
38
|
-
|
|
39
32
|
<% if (enumNames.size > 0) { %>import { <%= Array.from(enumNames).join(', ') %> } from '@<%= npmScope %>/api/core/models'
|
|
40
33
|
<% } %><% if (usesGraphQLJSON) { %>import { GraphQLJSON } from 'graphql-type-json'<% } %>
|
|
41
34
|
import { CorePagingInput } from '@<%= npmScope %>/api/core/data-access'
|
|
@@ -44,180 +37,118 @@ import { CorePagingInput } from '@<%= npmScope %>/api/core/data-access'
|
|
|
44
37
|
@InputType()
|
|
45
38
|
export class Create<%= model.modelName %>Input {
|
|
46
39
|
<% for (const field of model.fields) { %>
|
|
40
|
+
<% if (field.kind === 'object') { continue; } %>
|
|
47
41
|
<%
|
|
48
|
-
let shouldSkipField = false;
|
|
49
42
|
let baseGqlType;
|
|
50
43
|
let tsType;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (field.
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
effectiveFieldName = correspondingIdFieldName;
|
|
63
|
-
}
|
|
44
|
+
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
45
|
+
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
46
|
+
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
47
|
+
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
48
|
+
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
49
|
+
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
50
|
+
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
51
|
+
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
52
|
+
else if (field.kind === 'enum') {
|
|
53
|
+
baseGqlType = field.type;
|
|
54
|
+
tsType = field.type;
|
|
64
55
|
} else {
|
|
65
|
-
|
|
66
|
-
effectiveFieldName = field.name;
|
|
67
|
-
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
68
|
-
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
69
|
-
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
70
|
-
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
71
|
-
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
72
|
-
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
73
|
-
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
74
|
-
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
75
|
-
else if (field.kind === 'enum') {
|
|
76
|
-
baseGqlType = field.type;
|
|
77
|
-
tsType = field.type;
|
|
78
|
-
} else { // Fallback, should ideally not be reached if all model types are known
|
|
79
|
-
baseGqlType = 'String'; tsType = 'string';
|
|
80
|
-
}
|
|
56
|
+
baseGqlType = 'String'; tsType = 'string';
|
|
81
57
|
}
|
|
82
|
-
|
|
83
58
|
let fieldDecoratorTypeArg = '';
|
|
84
59
|
let finalTsType = tsType;
|
|
85
|
-
|
|
86
|
-
if (
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
60
|
+
let isOptional = false;
|
|
61
|
+
if (field.isList) {
|
|
62
|
+
fieldDecoratorTypeArg = `() => [${baseGqlType}]`;
|
|
63
|
+
finalTsType = tsType + '[]';
|
|
64
|
+
} else {
|
|
65
|
+
if (baseGqlType !== 'String' && baseGqlType !== 'Boolean') {
|
|
66
|
+
fieldDecoratorTypeArg = `() => ${baseGqlType}`;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// Always optional for id, createdAt, updatedAt
|
|
70
|
+
if (alwaysOptionalFields.includes(field.name)) {
|
|
71
|
+
isOptional = true;
|
|
72
|
+
} else {
|
|
73
|
+
isOptional = !field.isRequired;
|
|
97
74
|
}
|
|
98
75
|
%>
|
|
99
|
-
<% if (
|
|
100
|
-
|
|
101
|
-
<%= effectiveFieldName %>?: <%= finalTsType %>
|
|
102
|
-
<% } %>
|
|
76
|
+
@Field(<% if (fieldDecoratorTypeArg) { %><%- fieldDecoratorTypeArg %>, <% } %>{ nullable: <%= isOptional ? 'true' : 'false' %> })
|
|
77
|
+
<%= field.name %><%= isOptional ? '?' : '!' %>: <%= finalTsType %>
|
|
103
78
|
<% } %>
|
|
104
79
|
}
|
|
105
80
|
|
|
106
81
|
@InputType()
|
|
107
82
|
export class Update<%= model.modelName %>Input {
|
|
108
83
|
<% for (const field of model.fields) { %>
|
|
84
|
+
<% if (field.kind === 'object') { continue; } %>
|
|
109
85
|
<%
|
|
110
|
-
let shouldSkipField = false;
|
|
111
86
|
let baseGqlType;
|
|
112
87
|
let tsType;
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if (field.
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
88
|
+
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
89
|
+
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
90
|
+
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
91
|
+
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
92
|
+
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
93
|
+
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
94
|
+
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
95
|
+
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
96
|
+
else if (field.kind === 'enum') {
|
|
97
|
+
baseGqlType = field.type;
|
|
98
|
+
tsType = field.type;
|
|
125
99
|
} else {
|
|
126
|
-
|
|
127
|
-
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
128
|
-
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
129
|
-
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
130
|
-
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
131
|
-
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
132
|
-
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
133
|
-
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
134
|
-
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
135
|
-
else if (field.kind === 'enum') {
|
|
136
|
-
baseGqlType = field.type;
|
|
137
|
-
tsType = field.type;
|
|
138
|
-
} else {
|
|
139
|
-
baseGqlType = 'String'; tsType = 'string';
|
|
140
|
-
}
|
|
100
|
+
baseGqlType = 'String'; tsType = 'string';
|
|
141
101
|
}
|
|
142
|
-
|
|
143
102
|
let fieldDecoratorTypeArg = '';
|
|
144
103
|
let finalTsType = tsType;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
fieldDecoratorTypeArg = `() => ${baseGqlType}`;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
104
|
+
if (field.isList) {
|
|
105
|
+
fieldDecoratorTypeArg = `() => [${baseGqlType}]`;
|
|
106
|
+
finalTsType = tsType + '[]';
|
|
107
|
+
} else {
|
|
108
|
+
if (baseGqlType !== 'String' && baseGqlType !== 'Boolean') {
|
|
109
|
+
fieldDecoratorTypeArg = `() => ${baseGqlType}`;
|
|
110
|
+
}
|
|
155
111
|
}
|
|
156
112
|
%>
|
|
157
|
-
<% if (!shouldSkipField) { %>
|
|
158
113
|
@Field(<% if (fieldDecoratorTypeArg) { %><%- fieldDecoratorTypeArg %>, <% } %>{ nullable: true })
|
|
159
|
-
<%=
|
|
160
|
-
<% } %>
|
|
114
|
+
<%= field.name %>?: <%= finalTsType %>
|
|
161
115
|
<% } %>
|
|
162
116
|
}
|
|
163
117
|
|
|
164
118
|
@InputType()
|
|
165
119
|
export class List<%= model.modelName %>Input extends CorePagingInput {
|
|
166
120
|
<% for (const field of model.fields) { %>
|
|
121
|
+
<% if (field.kind === 'object') { continue; } %>
|
|
167
122
|
<%
|
|
168
|
-
let shouldSkipField = false;
|
|
169
123
|
let baseGqlType;
|
|
170
124
|
let tsType;
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (field.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
effectiveFieldName = correspondingIdFieldName;
|
|
183
|
-
}
|
|
125
|
+
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
126
|
+
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
127
|
+
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
128
|
+
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
129
|
+
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
130
|
+
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
131
|
+
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
132
|
+
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
133
|
+
else if (field.kind === 'enum') {
|
|
134
|
+
baseGqlType = field.type;
|
|
135
|
+
tsType = field.type;
|
|
184
136
|
} else {
|
|
185
|
-
|
|
186
|
-
effectiveFieldName = field.name;
|
|
187
|
-
if (field.type === 'String') { baseGqlType = 'String'; tsType = 'string'; }
|
|
188
|
-
else if (field.type === 'Int') { baseGqlType = 'Int'; tsType = 'number'; }
|
|
189
|
-
else if (field.type === 'Float') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
190
|
-
else if (field.type === 'Decimal') { baseGqlType = 'Float'; tsType = 'number'; }
|
|
191
|
-
else if (field.type === 'Boolean') { baseGqlType = 'Boolean'; tsType = 'boolean'; }
|
|
192
|
-
else if (field.type === 'DateTime') { baseGqlType = 'Date'; tsType = 'Date'; }
|
|
193
|
-
else if (field.type === 'Json') { baseGqlType = 'GraphQLJSON'; tsType = 'typeof GraphQLJSON'; }
|
|
194
|
-
else if (field.type === 'ID') { baseGqlType = 'ID'; tsType = 'string'; }
|
|
195
|
-
else if (field.kind === 'enum') {
|
|
196
|
-
baseGqlType = field.type;
|
|
197
|
-
tsType = field.type;
|
|
198
|
-
} else {
|
|
199
|
-
baseGqlType = 'String'; tsType = 'string';
|
|
200
|
-
}
|
|
137
|
+
baseGqlType = 'String'; tsType = 'string';
|
|
201
138
|
}
|
|
202
|
-
|
|
203
139
|
let fieldDecoratorTypeArg = '';
|
|
204
140
|
let finalTsType = tsType;
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
fieldDecoratorTypeArg = `() => ${baseGqlType}`;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
141
|
+
if (field.isList) {
|
|
142
|
+
fieldDecoratorTypeArg = `() => [${baseGqlType}]`;
|
|
143
|
+
finalTsType = tsType + '[]';
|
|
144
|
+
} else {
|
|
145
|
+
if (baseGqlType !== 'String' && baseGqlType !== 'Boolean') {
|
|
146
|
+
fieldDecoratorTypeArg = `() => ${baseGqlType}`;
|
|
147
|
+
}
|
|
215
148
|
}
|
|
216
149
|
%>
|
|
217
|
-
<% if (!shouldSkipField) { %>
|
|
218
150
|
@Field(<% if (fieldDecoratorTypeArg) { %><%- fieldDecoratorTypeArg %>, <% } %>{ nullable: true })
|
|
219
|
-
<%=
|
|
220
|
-
<% } %>
|
|
151
|
+
<%= field.name %>?: <%= finalTsType %>
|
|
221
152
|
<% } %>
|
|
222
153
|
}
|
|
223
154
|
|
package/src/setup/generator.js
CHANGED
|
@@ -22,7 +22,6 @@ function apiSetupGenerator(tree) {
|
|
|
22
22
|
'@nestjs/jwt': '^11.0.0',
|
|
23
23
|
'@nestjs/passport': '^11.0.5',
|
|
24
24
|
'@nestjs/platform-express': '^11.1.3',
|
|
25
|
-
'@paljs/plugins': '^8.2.0',
|
|
26
25
|
axios: '^1.9.0',
|
|
27
26
|
bcryptjs: '^3.0.2',
|
|
28
27
|
express: '^5.1.0',
|
|
@@ -44,11 +43,11 @@ function apiSetupGenerator(tree) {
|
|
|
44
43
|
'cookie-parser': '^1.4.7',
|
|
45
44
|
'passport-jwt': '^4.0.1',
|
|
46
45
|
}, {
|
|
47
|
-
nx: '21.2.
|
|
48
|
-
'@nx/js': '21.2.
|
|
49
|
-
'@nx/nest': '21.2.
|
|
50
|
-
'@nx/node': '21.2.
|
|
51
|
-
'@nx/webpack': '21.2.
|
|
46
|
+
nx: '21.2.1',
|
|
47
|
+
'@nx/js': '21.2.1',
|
|
48
|
+
'@nx/nest': '21.2.1',
|
|
49
|
+
'@nx/node': '21.2.1',
|
|
50
|
+
'@nx/webpack': '21.2.1',
|
|
52
51
|
'@nestjs/schematics': '^11.0.5',
|
|
53
52
|
'@nestjs/testing': '^11.1.3',
|
|
54
53
|
'@prisma/extension-optimize': '2.0.0',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/setup/generator.ts"],"names":[],"mappings":";;AASA,
|
|
1
|
+
{"version":3,"file":"generator.js","sourceRoot":"","sources":["../../../../../generators/api/src/setup/generator.ts"],"names":[],"mappings":";;AASA,8CA8FC;;AAvGD,uCAAkF;AAClF,4CAAiF;AAEjF,SAAS,WAAW,CAAC,IAAU;IAC7B,MAAM,SAAS,GAAG,QAAQ,CAAA;IAC1B,MAAM,OAAO,GAAG,oCAAoC,CAAA;IACpD,IAAI,CAAC,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;AAChC,CAAC;AAED,SAAsB,iBAAiB,CAAC,IAAU;;QAChD,mBAAmB;QACnB,IAAA,qCAA4B,EAC1B,IAAI,EACJ;YACE,gBAAgB,EAAE,SAAS;YAC3B,eAAe,EAAE,QAAQ;YACzB,gBAAgB,EAAE,SAAS;YAC3B,gBAAgB,EAAE,QAAQ;YAC1B,cAAc,EAAE,SAAS;YACzB,iBAAiB,EAAE,SAAS;YAC5B,aAAa,EAAE,SAAS;YACxB,kBAAkB,EAAE,SAAS;YAC7B,0BAA0B,EAAE,SAAS;YACrC,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,QAAQ;YACjB,OAAO,EAAE,UAAU;YACnB,0BAA0B,EAAE,OAAO;YACnC,iBAAiB,EAAE,SAAS;YAC5B,uBAAuB,EAAE,QAAQ;YACjC,YAAY,EAAE,QAAQ;YACtB,GAAG,EAAE,UAAU;YACf,UAAU,EAAE,QAAQ;YACpB,kBAAkB,EAAE,QAAQ;YAC5B,IAAI,EAAE,QAAQ;YACd,cAAc,EAAE,aAAa;YAC7B,gBAAgB,EAAE,QAAQ;YAC1B,iBAAiB,EAAE,SAAS;YAC5B,mBAAmB,EAAE,QAAQ;YAC7B,6BAA6B,EAAE,QAAQ;YACvC,OAAO,EAAE,QAAQ;YACjB,eAAe,EAAE,QAAQ;YACzB,cAAc,EAAE,QAAQ;SACzB,EACD;YACE,EAAE,EAAE,QAAQ;YACZ,QAAQ,EAAE,QAAQ;YAClB,UAAU,EAAE,QAAQ;YACpB,UAAU,EAAE,QAAQ;YACpB,aAAa,EAAE,QAAQ;YACvB,oBAAoB,EAAE,SAAS;YAC/B,iBAAiB,EAAE,SAAS;YAC5B,4BAA4B,EAAE,OAAO;YACrC,oBAAoB,EAAE,UAAU;YAChC,UAAU,EAAE,QAAQ;YACpB,WAAW,EAAE,SAAS;YACtB,sBAAsB,EAAE,QAAQ;YAChC,gBAAgB,EAAE,QAAQ;YAC1B,mBAAmB,EAAE,QAAQ;YAC7B,qBAAqB,EAAE,QAAQ;YAC/B,aAAa,EAAE,SAAS;YACxB,mBAAmB,EAAE,QAAQ;YAC7B,YAAY,EAAE,SAAS;YACvB,IAAI,EAAE,SAAS;YACf,uBAAuB,EAAE,SAAS;YAClC,EAAE,EAAE,QAAQ;YACZ,MAAM,EAAE,QAAQ;YAChB,SAAS,EAAE,QAAQ;YACnB,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,QAAQ;YACrB,aAAa,EAAE,QAAQ;YACvB,wBAAwB,EAAE,QAAQ;YAClC,+BAA+B,EAAE,QAAQ;YACzC,6BAA6B,EAAE,QAAQ;YACvC,mBAAmB,EAAE,QAAQ;SAC9B,CACF,CAAA;QAED,qDAAqD;QACrD,MAAM,eAAe,GAAG;YACtB,oBAAoB;YACpB,iBAAiB;YACjB,gBAAgB;YAChB,4BAA4B;YAC5B,iBAAiB;YACjB,SAAS;YACT,IAAI;YACJ,QAAQ;YACR,SAAS;YACT,6BAA6B;YAC7B,cAAc;YACd,cAAc;YACd,SAAS;YACT,eAAe;YACf,WAAW;SACZ,CAAA;QACD,IAAA,iCAAyB,EAAC,IAAI,EAAE,EAAE,qBAAqB,EAAE,eAAe,EAAE,CAAC,CAAA;QAE3E,iDAAiD;QACjD,WAAW,CAAC,IAAI,CAAC,CAAA;QAEjB,gEAAgE;QAChE,OAAO,IAAA,2BAAmB,GAAE,CAAA;IAC9B,CAAC;CAAA;AAED,kBAAe,iBAAiB,CAAA"}
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
import { registerAs } from '@nestjs/config'
|
|
2
|
-
import Joi from 'joi'
|
|
3
|
-
|
|
4
|
-
export const appConfig = registerAs('app', () => ({
|
|
5
|
-
prefix: 'api',
|
|
6
|
-
environment: process.env.NODE_ENV,
|
|
7
|
-
host: process.env.HOST,
|
|
8
|
-
port: process.env.PORT ? parseInt(process.env.PORT, 10) : 3000,
|
|
9
|
-
apiUrl: process.env.API_URL,
|
|
10
|
-
webPort: process.env.WEB_PORT ? parseInt(process.env.WEB_PORT, 10) : 4200,
|
|
11
|
-
api: {
|
|
12
|
-
cookie: {
|
|
13
|
-
name: process.env.API_COOKIE_NAME,
|
|
14
|
-
secret: process.env.API_COOKIE_SECRET,
|
|
15
|
-
options: {
|
|
16
|
-
domain: process.env.API_COOKIE_DOMAIN,
|
|
17
|
-
httpOnly: true,
|
|
18
|
-
secure: true,
|
|
19
|
-
sameSite: 'none',
|
|
20
|
-
path: '/',
|
|
21
|
-
},
|
|
22
|
-
},
|
|
23
|
-
cors: {
|
|
24
|
-
origin: [process.env.SITE_URL],
|
|
25
|
-
},
|
|
26
|
-
},
|
|
27
|
-
siteUrl: process.env.SITE_URL || (process.env.API_URL ? process.env.API_URL.replace('/api', '') : ''),
|
|
28
|
-
app: {
|
|
29
|
-
email: process.env.APP_EMAIL,
|
|
30
|
-
supportEmail: process.env.APP_SUPPORT_EMAIL,
|
|
31
|
-
adminEmails: process.env.APP_ADMIN_EMAILS,
|
|
32
|
-
name: process.env.APP_NAME,
|
|
33
|
-
},
|
|
34
|
-
smtp: {
|
|
35
|
-
host: process.env.SMTP_HOST,
|
|
36
|
-
port: process.env.SMTP_PORT ? parseInt(process.env.SMTP_PORT, 10) : 587,
|
|
37
|
-
user: process.env.SMTP_USER,
|
|
38
|
-
pass: process.env.SMTP_PASS,
|
|
39
|
-
ignoreTLS: true,
|
|
40
|
-
},
|
|
41
|
-
twilio: {
|
|
42
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID,
|
|
43
|
-
authToken: process.env.TWILIO_AUTH_TOKEN,
|
|
44
|
-
fromNumber: process.env.TWILIO_FROM_NUMBER,
|
|
45
|
-
},
|
|
46
|
-
}))
|
|
47
|
-
|
|
48
|
-
export const validationSchema = Joi.object({
|
|
49
|
-
NODE_ENV: Joi.string().valid('development', 'production', 'test'),
|
|
50
|
-
HOST: Joi.string().alphanum().default('localhost'),
|
|
51
|
-
PORT: Joi.number().default(3000),
|
|
52
|
-
WEB_PORT: Joi.number().default(4200),
|
|
53
|
-
WEB_URL: Joi.string().default(`http://${process.env.HOST || 'localhost'}:${process.env.WEB_PORT}`),
|
|
54
|
-
API_COOKIE_DOMAIN: Joi.string().default('localhost'),
|
|
55
|
-
API_COOKIE_NAME: Joi.string().default('__session'),
|
|
56
|
-
API_URL: Joi.string().default(`http://${process.env.HOST || 'localhost'}:${process.env.PORT}/api`),
|
|
57
|
-
APP_NAME: Joi.string().required(),
|
|
58
|
-
APP_EMAIL: Joi.string().email().required(),
|
|
59
|
-
APP_SUPPORT_EMAIL: Joi.string().email().required(),
|
|
60
|
-
APP_ADMIN_EMAILS: Joi.string().required(),
|
|
61
|
-
SITE_URL: Joi.string().uri().required(),
|
|
62
|
-
SMTP_HOST: Joi.string().required(),
|
|
63
|
-
SMTP_PORT: Joi.string().required(),
|
|
64
|
-
SMTP_USER: Joi.string().required(),
|
|
65
|
-
SMTP_PASS: Joi.string().required(),
|
|
66
|
-
})
|
|
File without changes
|