@flusys/nestjs-core 0.1.0-beta.1 → 0.1.0-beta.2
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/README.md +193 -0
- package/cjs/config/env-config.service.js +158 -0
- package/cjs/config/index.js +18 -0
- package/cjs/constants/database.constants.js +20 -0
- package/cjs/constants/index.js +18 -0
- package/cjs/docs/docs.config.js +192 -0
- package/cjs/docs/docs.setup.js +14 -0
- package/cjs/docs/index.js +19 -0
- package/cjs/index.js +24 -151
- package/cjs/interfaces/app-config.interfaces.js +4 -0
- package/cjs/interfaces/base-entity.interface.js +7 -0
- package/cjs/interfaces/database.interface.js +6 -0
- package/cjs/interfaces/index.js +21 -0
- package/cjs/interfaces/migration.interface.js +4 -0
- package/cjs/migration/cli.js +10 -0
- package/cjs/migration/datasource.factory.js +55 -0
- package/cjs/migration/index.js +54 -0
- package/cjs/migration/migration.cli.js +227 -0
- package/cjs/migration/migration.runner.js +235 -0
- package/cjs/seeders/base-seeder.js +95 -0
- package/cjs/seeders/cli.js +398 -0
- package/cjs/seeders/data-generator.js +247 -0
- package/cjs/seeders/entity-reader.js +168 -0
- package/cjs/seeders/index.js +77 -0
- package/cjs/seeders/seed-config.js +101 -0
- package/cjs/seeders/seed-runner.js +320 -0
- package/cjs/seeders/template-generator.js +297 -0
- package/cjs/utils/datasource-config.builder.js +98 -0
- package/cjs/utils/index.js +18 -0
- package/fesm/config/env-config.service.js +108 -0
- package/fesm/config/index.js +1 -0
- package/fesm/constants/database.constants.js +2 -0
- package/fesm/constants/index.js +1 -0
- package/fesm/docs/docs.config.js +184 -0
- package/fesm/docs/docs.setup.js +4 -0
- package/fesm/docs/index.js +2 -0
- package/fesm/index.js +12 -151
- package/fesm/interfaces/app-config.interfaces.js +3 -0
- package/fesm/interfaces/base-entity.interface.js +6 -0
- package/fesm/interfaces/database.interface.js +5 -0
- package/fesm/interfaces/index.js +4 -0
- package/fesm/interfaces/migration.interface.js +1 -0
- package/fesm/migration/cli.js +25 -0
- package/fesm/migration/datasource.factory.js +52 -0
- package/fesm/migration/index.js +17 -0
- package/fesm/migration/migration.cli.js +176 -0
- package/fesm/migration/migration.runner.js +225 -0
- package/fesm/seeders/base-seeder.js +110 -0
- package/fesm/seeders/cli.js +366 -0
- package/fesm/seeders/data-generator.js +249 -0
- package/fesm/seeders/entity-reader.js +170 -0
- package/fesm/seeders/index.js +11 -0
- package/fesm/seeders/seed-config.js +85 -0
- package/fesm/seeders/seed-runner.js +323 -0
- package/fesm/seeders/template-generator.js +257 -0
- package/fesm/utils/datasource-config.builder.js +79 -0
- package/fesm/utils/index.js +1 -0
- package/package.json +21 -18
- package/cjs/config-index.js +0 -1
- package/cjs/constants-index.js +0 -1
- package/cjs/docs-index.js +0 -1
- package/cjs/interfaces-index.js +0 -1
- package/cjs/migration-cli.js +0 -35
- package/cjs/migration-index.js +0 -34
- package/cjs/seeders-cli.js +0 -119
- package/cjs/seeders-index.js +0 -118
- package/cjs/utils-index.js +0 -1
- package/fesm/config-index.js +0 -1
- package/fesm/constants-index.js +0 -1
- package/fesm/docs-index.js +0 -1
- package/fesm/interfaces-index.js +0 -0
- package/fesm/migration-cli.js +0 -35
- package/fesm/migration-index.js +0 -34
- package/fesm/seeders-cli.js +0 -119
- package/fesm/seeders-index.js +0 -118
- package/fesm/utils-index.js +0 -1
- package/migration/cli.js +0 -3
- package/seeders/cli.js +0 -3
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Core Package Guide
|
|
2
|
+
|
|
3
|
+
> **Package:** `@flusys/nestjs-core`
|
|
4
|
+
> **Type:** Pure TypeScript utilities (Zero NestJS dependencies)
|
|
5
|
+
|
|
6
|
+
Foundation layer providing type-safe configuration, database utilities, migration CLI, seeders, and Swagger setup.
|
|
7
|
+
|
|
8
|
+
## Package Architecture
|
|
9
|
+
|
|
10
|
+
```
|
|
11
|
+
nestjs-core/src/
|
|
12
|
+
├── config/
|
|
13
|
+
│ └── env-config.service.ts # Environment configuration singleton
|
|
14
|
+
├── constants/
|
|
15
|
+
│ └── database.constants.ts # MODULE_OPTIONS, DEFAULT_TENANT_HEADER
|
|
16
|
+
├── interfaces/
|
|
17
|
+
│ ├── app-config.interfaces.ts # IBootstrapAppConfig, IDynamicModuleConfig
|
|
18
|
+
│ ├── base-entity.interface.ts # IBaseEntity, ISoftDeletable, ITimestampable
|
|
19
|
+
│ ├── database.interface.ts # IDatabaseConfig, ITenantDatabaseConfig
|
|
20
|
+
│ └── migration.interface.ts # IMigrationConfig, IMigrationResult
|
|
21
|
+
├── utils/
|
|
22
|
+
│ └── datasource-config.builder.ts
|
|
23
|
+
├── migration/
|
|
24
|
+
│ ├── cli.ts, migration.cli.ts, datasource.factory.ts, migration.runner.ts
|
|
25
|
+
├── seeders/
|
|
26
|
+
│ ├── cli.ts, base-seeder.ts, seed-runner.ts, seed-config.ts
|
|
27
|
+
│ ├── entity-reader.ts, data-generator.ts, template-generator.ts
|
|
28
|
+
├── docs/
|
|
29
|
+
│ ├── docs.config.ts, docs.setup.ts
|
|
30
|
+
└── index.ts
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Environment Configuration
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
import { envConfig } from '@flusys/nestjs-core/config';
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
| Method | Description |
|
|
40
|
+
|--------|-------------|
|
|
41
|
+
| `tryGetValue(key)` | Get env value (throws for restricted keys) |
|
|
42
|
+
| `getNumber(key)` | Get env value as number |
|
|
43
|
+
| `getBoolean(key)` | Get env value as boolean |
|
|
44
|
+
| `getPort()` | Get PORT (default: 3000) |
|
|
45
|
+
| `isProduction()` | Check if MODE !== 'DEV' |
|
|
46
|
+
| `getFrontendUrl()` | Get FRONTEND_URL |
|
|
47
|
+
| `getOrigins()` | Get ALLOW_ORIGINS as array |
|
|
48
|
+
| `getTypeOrmConfig()` | Get database config |
|
|
49
|
+
| `getJwtConfig()` | Get JWT config |
|
|
50
|
+
| `getRedisUrl()` | Get Redis connection URL |
|
|
51
|
+
| `getMailConfig()` | Get mail configuration |
|
|
52
|
+
| `getTenantId()` | Get TENANT_ID |
|
|
53
|
+
| `useTenantMode()` | Check USE_TENANT_MODE |
|
|
54
|
+
| `getLogConfig()` | Get logging configuration |
|
|
55
|
+
| `getEnv()` | Get all env vars as Record |
|
|
56
|
+
|
|
57
|
+
## Database Interfaces
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
interface IDatabaseConfig {
|
|
61
|
+
type: 'mysql' | 'postgres' | 'mariadb' | 'sqlite' | 'mssql';
|
|
62
|
+
host?: string; port?: number; username?: string; password?: string; database?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
interface ITenantDatabaseConfig {
|
|
66
|
+
id: string; database: string; name?: string;
|
|
67
|
+
host?: string; port?: number; username?: string; password?: string;
|
|
68
|
+
enableCompanyFeature?: boolean;
|
|
69
|
+
permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
interface IBootstrapAppConfig {
|
|
73
|
+
databaseMode: 'single' | 'multi-tenant';
|
|
74
|
+
enableCompanyFeature: boolean;
|
|
75
|
+
permissionMode?: 'FULL' | 'RBAC' | 'DIRECT';
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Migration CLI
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm run migration:generate --name=CreateUsers
|
|
83
|
+
npm run migration:run
|
|
84
|
+
npm run migration:revert
|
|
85
|
+
npm run migration:status
|
|
86
|
+
TENANT_ID=tenant1 npm run migration:run # specific tenant
|
|
87
|
+
npm run migration:run:all # all tenants
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
import { runMigrationCli, createMigrationDataSource } from '@flusys/nestjs-core/migration';
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Seed System
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
npm run seed:generate
|
|
98
|
+
npm run seed:run -- --entity=User --count=100
|
|
99
|
+
npm run seed:clear
|
|
100
|
+
npm run seed:status
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { BaseSeeder, SeedRunner } from '@flusys/nestjs-core/seeders';
|
|
105
|
+
|
|
106
|
+
class UserSeeder extends BaseSeeder<User> {
|
|
107
|
+
constructor(ds: DataSource) { super(ds, User); }
|
|
108
|
+
async generate(count: number): Promise<User[]> {
|
|
109
|
+
const users = [];
|
|
110
|
+
for (let i = 0; i < count; i++) {
|
|
111
|
+
users.push(this.repository.create({ email: faker.internet.email() }));
|
|
112
|
+
}
|
|
113
|
+
return this.repository.save(users);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const runner = new SeedRunner(dataSource);
|
|
118
|
+
runner.registerCustomSeeder('User', new UserSeeder(dataSource));
|
|
119
|
+
await runner.runAll({ count: 50, clear: true });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Swagger Documentation
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { setupSwaggerDocs, setupModuleSwaggerDocs } from '@flusys/nestjs-core/docs';
|
|
126
|
+
|
|
127
|
+
setupModuleSwaggerDocs(app, [
|
|
128
|
+
{ title: 'Auth API', path: 'auth/docs', bearerAuth: true },
|
|
129
|
+
{ title: 'Admin API', path: 'admin/docs', excludeTags: ['public'] },
|
|
130
|
+
]);
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### Conditional Schema Exclusion
|
|
134
|
+
|
|
135
|
+
```typescript
|
|
136
|
+
setupModuleSwaggerDocs(app, [{
|
|
137
|
+
title: 'Auth API',
|
|
138
|
+
path: 'auth/docs',
|
|
139
|
+
excludeSchemaProperties: enableCompanyFeature ? undefined : [
|
|
140
|
+
{ schemaName: 'LoginResponseDto', properties: ['company', 'branch'] },
|
|
141
|
+
],
|
|
142
|
+
}]);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## API Reference
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// Interfaces
|
|
149
|
+
import {
|
|
150
|
+
IDatabaseConfig, ITenantDatabaseConfig, IBootstrapAppConfig,
|
|
151
|
+
IDynamicModuleConfig, IDataSourceServiceOptions,
|
|
152
|
+
IMigrationConfig, IMigrationResult,
|
|
153
|
+
IBaseEntity, ISoftDeletable, ITimestampable, IOrderable,
|
|
154
|
+
} from '@flusys/nestjs-core';
|
|
155
|
+
|
|
156
|
+
// Constants
|
|
157
|
+
import { MODULE_OPTIONS, DEFAULT_TENANT_HEADER } from '@flusys/nestjs-core';
|
|
158
|
+
|
|
159
|
+
// Config
|
|
160
|
+
import { envConfig } from '@flusys/nestjs-core/config';
|
|
161
|
+
|
|
162
|
+
// Utils
|
|
163
|
+
import {
|
|
164
|
+
buildDataSourceOptions, getDatabaseForTenant,
|
|
165
|
+
resolveEntities, getActiveTenants,
|
|
166
|
+
} from '@flusys/nestjs-core/utils';
|
|
167
|
+
|
|
168
|
+
// Migration
|
|
169
|
+
import {
|
|
170
|
+
createMigrationDataSource, initializeDataSource, runMigrationCli,
|
|
171
|
+
generateMigration, runMigrations, revertMigration, migrationStatus,
|
|
172
|
+
} from '@flusys/nestjs-core/migration';
|
|
173
|
+
|
|
174
|
+
// Seeders
|
|
175
|
+
import {
|
|
176
|
+
BaseSeeder, SeedRunner, EntityReader, DataGenerator,
|
|
177
|
+
seedConfig, runSeedCli,
|
|
178
|
+
} from '@flusys/nestjs-core/seeders';
|
|
179
|
+
|
|
180
|
+
// Swagger
|
|
181
|
+
import {
|
|
182
|
+
setupSwaggerDocs, setupModuleSwaggerDocs,
|
|
183
|
+
IModuleSwaggerOptions, ISchemaPropertyExclusion,
|
|
184
|
+
} from '@flusys/nestjs-core/docs';
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Dependencies
|
|
188
|
+
|
|
189
|
+
- `dotenv` - Environment variable loading
|
|
190
|
+
- `typeorm` - Migration/seeder utilities
|
|
191
|
+
- `@faker-js/faker` - Seed data generation
|
|
192
|
+
|
|
193
|
+
**No NestJS dependencies** - Can be used in any TypeScript project.
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "envConfig", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return envConfig;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _dotenv = /*#__PURE__*/ _interop_require_wildcard(require("dotenv"));
|
|
12
|
+
function _define_property(obj, key, value) {
|
|
13
|
+
if (key in obj) {
|
|
14
|
+
Object.defineProperty(obj, key, {
|
|
15
|
+
value: value,
|
|
16
|
+
enumerable: true,
|
|
17
|
+
configurable: true,
|
|
18
|
+
writable: true
|
|
19
|
+
});
|
|
20
|
+
} else {
|
|
21
|
+
obj[key] = value;
|
|
22
|
+
}
|
|
23
|
+
return obj;
|
|
24
|
+
}
|
|
25
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
26
|
+
if (typeof WeakMap !== "function") return null;
|
|
27
|
+
var cacheBabelInterop = new WeakMap();
|
|
28
|
+
var cacheNodeInterop = new WeakMap();
|
|
29
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
30
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
31
|
+
})(nodeInterop);
|
|
32
|
+
}
|
|
33
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
34
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
35
|
+
return obj;
|
|
36
|
+
}
|
|
37
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
38
|
+
return {
|
|
39
|
+
default: obj
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
43
|
+
if (cache && cache.has(obj)) {
|
|
44
|
+
return cache.get(obj);
|
|
45
|
+
}
|
|
46
|
+
var newObj = {
|
|
47
|
+
__proto__: null
|
|
48
|
+
};
|
|
49
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
50
|
+
for(var key in obj){
|
|
51
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
52
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
53
|
+
if (desc && (desc.get || desc.set)) {
|
|
54
|
+
Object.defineProperty(newObj, key, desc);
|
|
55
|
+
} else {
|
|
56
|
+
newObj[key] = obj[key];
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
newObj.default = obj;
|
|
61
|
+
if (cache) {
|
|
62
|
+
cache.set(obj, newObj);
|
|
63
|
+
}
|
|
64
|
+
return newObj;
|
|
65
|
+
}
|
|
66
|
+
_dotenv.config();
|
|
67
|
+
let EnvConfigService = class EnvConfigService {
|
|
68
|
+
getValue(key, throwOnMissing = true) {
|
|
69
|
+
const value = this.env[key];
|
|
70
|
+
if (!value && throwOnMissing) {
|
|
71
|
+
throw new Error(`Config error - missing env.${key}`);
|
|
72
|
+
}
|
|
73
|
+
return value ?? '';
|
|
74
|
+
}
|
|
75
|
+
tryGetValue(key, throwOnMissing = false) {
|
|
76
|
+
if (this.restrictedKeys[key]) {
|
|
77
|
+
throw new Error(`Access denied for env key "${key}". Use the method \`${this.restrictedKeys[key]}()\` instead.`);
|
|
78
|
+
}
|
|
79
|
+
return this.getValue(key, throwOnMissing);
|
|
80
|
+
}
|
|
81
|
+
getNumber(key, throwOnMissing = true) {
|
|
82
|
+
return Number(this.getValue(key, throwOnMissing));
|
|
83
|
+
}
|
|
84
|
+
getBoolean(key, throwOnMissing = true) {
|
|
85
|
+
return this.getValue(key, throwOnMissing).toLowerCase() === 'true';
|
|
86
|
+
}
|
|
87
|
+
getPort() {
|
|
88
|
+
return this.getNumber('PORT', false);
|
|
89
|
+
}
|
|
90
|
+
isProduction() {
|
|
91
|
+
return this.getValue('MODE', false).toUpperCase() !== 'DEV';
|
|
92
|
+
}
|
|
93
|
+
getFrontendUrl() {
|
|
94
|
+
return this.getValue('FRONTEND_URL');
|
|
95
|
+
}
|
|
96
|
+
getOrigins() {
|
|
97
|
+
const origins = this.getValue('ALLOW_ORIGINS');
|
|
98
|
+
return origins ? origins.split(',').map((o)=>o.trim()) : [];
|
|
99
|
+
}
|
|
100
|
+
getTypeOrmConfig() {
|
|
101
|
+
return {
|
|
102
|
+
host: this.getValue('DB_HOST'),
|
|
103
|
+
port: this.getNumber('DB_PORT'),
|
|
104
|
+
username: this.getValue('DB_USER'),
|
|
105
|
+
password: this.getValue('DB_PASSWORD')
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
getJwtConfig() {
|
|
109
|
+
return {
|
|
110
|
+
secret: this.getValue('JWT_SECRET'),
|
|
111
|
+
expiration: this.getValue('JWT_EXPIRATION', false) || '1h',
|
|
112
|
+
refreshSecret: this.getValue('REFRESH_TOKEN_SECRET'),
|
|
113
|
+
refreshExpiration: this.getValue('REFRESH_TOKEN_EXPIRATION', false) || '7d'
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
getRedisUrl() {
|
|
117
|
+
return this.getValue('REDIS_URL', false) || 'redis://localhost:6379';
|
|
118
|
+
}
|
|
119
|
+
getMailConfig() {
|
|
120
|
+
return {
|
|
121
|
+
MAIL_FROM: this.getValue('MAIL_FROM', false) || '',
|
|
122
|
+
MAIL_APP_PASSWORD: this.getValue('MAIL_APP_PASSWORD', false) || ''
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
getTenantId() {
|
|
126
|
+
return this.getValue('TENANT_ID', false) || null;
|
|
127
|
+
}
|
|
128
|
+
useTenantMode() {
|
|
129
|
+
return this.getValue('USE_TENANT_MODE', false).toLowerCase() === 'true';
|
|
130
|
+
}
|
|
131
|
+
getLogConfig() {
|
|
132
|
+
return {
|
|
133
|
+
dir: this.getValue('LOG_DIR', false) || 'logs',
|
|
134
|
+
level: this.getValue('LOG_LEVEL', false) || (this.isProduction() ? 'info' : 'debug'),
|
|
135
|
+
maxSize: this.getValue('LOG_MAX_SIZE', false) || '20m',
|
|
136
|
+
maxFiles: this.getValue('LOG_MAX_FILES', false) || '14d'
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
getEnv() {
|
|
140
|
+
return process.env;
|
|
141
|
+
}
|
|
142
|
+
constructor(env){
|
|
143
|
+
_define_property(this, "env", void 0);
|
|
144
|
+
_define_property(this, "restrictedKeys", void 0);
|
|
145
|
+
this.env = env;
|
|
146
|
+
this.restrictedKeys = {
|
|
147
|
+
FRONTEND_URL: 'getFrontendUrl',
|
|
148
|
+
ALLOW_ORIGINS: 'getOrigins',
|
|
149
|
+
PORT: 'getPort',
|
|
150
|
+
MODE: 'isProduction',
|
|
151
|
+
DB_HOST: 'getTypeOrmConfig',
|
|
152
|
+
DB_PORT: 'getTypeOrmConfig',
|
|
153
|
+
DB_USER: 'getTypeOrmConfig',
|
|
154
|
+
DB_PASSWORD: 'getTypeOrmConfig'
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
const envConfig = new EnvConfigService(process.env);
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./env-config.service"), exports);
|
|
6
|
+
function _export_star(from, to) {
|
|
7
|
+
Object.keys(from).forEach(function(k) {
|
|
8
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
9
|
+
Object.defineProperty(to, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return from[k];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return from;
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get DEFAULT_TENANT_HEADER () {
|
|
13
|
+
return DEFAULT_TENANT_HEADER;
|
|
14
|
+
},
|
|
15
|
+
get MODULE_OPTIONS () {
|
|
16
|
+
return MODULE_OPTIONS;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
19
|
+
const MODULE_OPTIONS = Symbol('MODULE_OPTIONS');
|
|
20
|
+
const DEFAULT_TENANT_HEADER = 'x-tenant-id';
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./database.constants"), exports);
|
|
6
|
+
function _export_star(from, to) {
|
|
7
|
+
Object.keys(from).forEach(function(k) {
|
|
8
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
9
|
+
Object.defineProperty(to, k, {
|
|
10
|
+
enumerable: true,
|
|
11
|
+
get: function() {
|
|
12
|
+
return from[k];
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
return from;
|
|
18
|
+
}
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "setupModuleSwaggerDocs", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return setupModuleSwaggerDocs;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _swagger = require("@nestjs/swagger");
|
|
12
|
+
/**
|
|
13
|
+
* Filter OpenAPI document to exclude schema properties
|
|
14
|
+
*/ function filterSchemaProperties(document, exclusions) {
|
|
15
|
+
if (!exclusions?.length || !document.components?.schemas) {
|
|
16
|
+
return document;
|
|
17
|
+
}
|
|
18
|
+
const schemas = {
|
|
19
|
+
...document.components.schemas
|
|
20
|
+
};
|
|
21
|
+
for (const exclusion of exclusions){
|
|
22
|
+
const schema = schemas[exclusion.schemaName];
|
|
23
|
+
if (schema && typeof schema === 'object' && 'properties' in schema) {
|
|
24
|
+
const filteredProperties = {
|
|
25
|
+
...schema.properties
|
|
26
|
+
};
|
|
27
|
+
for (const prop of exclusion.properties){
|
|
28
|
+
delete filteredProperties[prop];
|
|
29
|
+
}
|
|
30
|
+
// Also remove from required array if present
|
|
31
|
+
const filteredRequired = schema.required?.filter((r)=>!exclusion.properties.includes(r));
|
|
32
|
+
schemas[exclusion.schemaName] = {
|
|
33
|
+
...schema,
|
|
34
|
+
properties: filteredProperties,
|
|
35
|
+
...filteredRequired?.length ? {
|
|
36
|
+
required: filteredRequired
|
|
37
|
+
} : {}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return {
|
|
42
|
+
...document,
|
|
43
|
+
components: {
|
|
44
|
+
...document.components,
|
|
45
|
+
schemas
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Filter OpenAPI document to exclude query parameters from specific endpoints
|
|
51
|
+
*/ function filterQueryParameters(document, exclusions) {
|
|
52
|
+
if (!exclusions?.length || !document.paths) {
|
|
53
|
+
return document;
|
|
54
|
+
}
|
|
55
|
+
const filteredPaths = {};
|
|
56
|
+
for (const [path, pathItem] of Object.entries(document.paths)){
|
|
57
|
+
const filteredPathItem = {};
|
|
58
|
+
for (const [method, operation] of Object.entries(pathItem)){
|
|
59
|
+
// Skip non-operation properties
|
|
60
|
+
if (!operation || typeof operation !== 'object') {
|
|
61
|
+
filteredPathItem[method] = operation;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
// Check if this endpoint matches any exclusion pattern
|
|
65
|
+
const matchingExclusions = exclusions.filter((exclusion)=>{
|
|
66
|
+
const pathMatches = pathMatchesPattern(path, exclusion.pathPattern);
|
|
67
|
+
const methodMatches = !exclusion.method || exclusion.method === method;
|
|
68
|
+
return pathMatches && methodMatches;
|
|
69
|
+
});
|
|
70
|
+
if (matchingExclusions.length > 0) {
|
|
71
|
+
// Collect all parameters to exclude
|
|
72
|
+
const paramsToExclude = new Set();
|
|
73
|
+
matchingExclusions.forEach((exclusion)=>{
|
|
74
|
+
exclusion.parameters.forEach((param)=>paramsToExclude.add(param));
|
|
75
|
+
});
|
|
76
|
+
// Filter out excluded query parameters
|
|
77
|
+
const filteredOperation = {
|
|
78
|
+
...operation
|
|
79
|
+
};
|
|
80
|
+
if (Array.isArray(filteredOperation.parameters)) {
|
|
81
|
+
filteredOperation.parameters = filteredOperation.parameters.filter((param)=>{
|
|
82
|
+
return !(param.in === 'query' && paramsToExclude.has(param.name));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
filteredPathItem[method] = filteredOperation;
|
|
86
|
+
} else {
|
|
87
|
+
filteredPathItem[method] = operation;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
filteredPaths[path] = filteredPathItem;
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
...document,
|
|
94
|
+
paths: filteredPaths
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if a path matches a pattern (supports wildcards)
|
|
99
|
+
*/ function pathMatchesPattern(path, pattern) {
|
|
100
|
+
// Convert wildcard pattern to regex
|
|
101
|
+
const regexPattern = pattern.replace(/\*/g, '[^/]+') // * matches any characters except /
|
|
102
|
+
.replace(/\*\*/g, '.*'); // ** matches any characters including /
|
|
103
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
104
|
+
return regex.test(path);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Filter OpenAPI document to exclude paths and tags based on excludeTags
|
|
108
|
+
*/ function filterDocumentByTags(document, excludeTags) {
|
|
109
|
+
if (!excludeTags?.length) {
|
|
110
|
+
return document;
|
|
111
|
+
}
|
|
112
|
+
const excludeTagsSet = new Set(excludeTags.map((tag)=>tag.toLowerCase()));
|
|
113
|
+
// Filter out paths that have any of the excluded tags
|
|
114
|
+
const filteredPaths = {};
|
|
115
|
+
for (const [path, pathItem] of Object.entries(document.paths)){
|
|
116
|
+
const filteredPathItem = {};
|
|
117
|
+
for (const [method, operation] of Object.entries(pathItem)){
|
|
118
|
+
// Skip non-operation properties like 'parameters'
|
|
119
|
+
if (!operation || typeof operation !== 'object' || !('tags' in operation)) {
|
|
120
|
+
filteredPathItem[method] = operation;
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const operationTags = operation.tags || [];
|
|
124
|
+
const hasExcludedTag = operationTags.some((tag)=>excludeTagsSet.has(tag.toLowerCase()));
|
|
125
|
+
if (!hasExcludedTag) {
|
|
126
|
+
filteredPathItem[method] = operation;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
// Only include path if it has at least one operation
|
|
130
|
+
const hasOperations = Object.keys(filteredPathItem).some((key)=>[
|
|
131
|
+
'get',
|
|
132
|
+
'post',
|
|
133
|
+
'put',
|
|
134
|
+
'patch',
|
|
135
|
+
'delete',
|
|
136
|
+
'options',
|
|
137
|
+
'head'
|
|
138
|
+
].includes(key));
|
|
139
|
+
if (hasOperations) {
|
|
140
|
+
filteredPaths[path] = filteredPathItem;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
// Filter out excluded tags from the tags array
|
|
144
|
+
const filteredTags = document.tags?.filter((tag)=>!excludeTagsSet.has(tag.name.toLowerCase()));
|
|
145
|
+
return {
|
|
146
|
+
...document,
|
|
147
|
+
paths: filteredPaths,
|
|
148
|
+
tags: filteredTags
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
function setupModuleSwaggerDocs(app, configs) {
|
|
152
|
+
configs.forEach((config)=>{
|
|
153
|
+
const builder = new _swagger.DocumentBuilder().setTitle(config.title).setDescription(config.description).setVersion(config.version || '1.0');
|
|
154
|
+
// Add bearer auth
|
|
155
|
+
if (config.bearerAuth) {
|
|
156
|
+
builder.addBearerAuth();
|
|
157
|
+
}
|
|
158
|
+
// Add custom global headers
|
|
159
|
+
if (config.globalHeaders?.length) {
|
|
160
|
+
config.globalHeaders.forEach((header)=>{
|
|
161
|
+
builder.addGlobalParameters({
|
|
162
|
+
name: header.name,
|
|
163
|
+
in: 'header',
|
|
164
|
+
description: header.description,
|
|
165
|
+
required: header.required ?? false,
|
|
166
|
+
schema: {
|
|
167
|
+
type: 'string',
|
|
168
|
+
example: header.example || ''
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
// Only filter by modules if specified
|
|
174
|
+
const createDocOptions = config.modules?.length ? {
|
|
175
|
+
include: config.modules
|
|
176
|
+
} : {};
|
|
177
|
+
let document = _swagger.SwaggerModule.createDocument(app, builder.build(), createDocOptions);
|
|
178
|
+
// Filter out excluded tags
|
|
179
|
+
if (config.excludeTags?.length) {
|
|
180
|
+
document = filterDocumentByTags(document, config.excludeTags);
|
|
181
|
+
}
|
|
182
|
+
// Filter out excluded schema properties
|
|
183
|
+
if (config.excludeSchemaProperties?.length) {
|
|
184
|
+
document = filterSchemaProperties(document, config.excludeSchemaProperties);
|
|
185
|
+
}
|
|
186
|
+
// Filter out excluded query parameters
|
|
187
|
+
if (config.excludeQueryParameters?.length) {
|
|
188
|
+
document = filterQueryParameters(document, config.excludeQueryParameters);
|
|
189
|
+
}
|
|
190
|
+
_swagger.SwaggerModule.setup(config.path, app, document);
|
|
191
|
+
});
|
|
192
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "setupSwaggerDocs", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return setupSwaggerDocs;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _docsconfig = require("./docs.config");
|
|
12
|
+
function setupSwaggerDocs(app, ...modules) {
|
|
13
|
+
(0, _docsconfig.setupModuleSwaggerDocs)(app, modules);
|
|
14
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
_export_star(require("./docs.config"), exports);
|
|
6
|
+
_export_star(require("./docs.setup"), exports);
|
|
7
|
+
function _export_star(from, to) {
|
|
8
|
+
Object.keys(from).forEach(function(k) {
|
|
9
|
+
if (k !== "default" && !Object.prototype.hasOwnProperty.call(to, k)) {
|
|
10
|
+
Object.defineProperty(to, k, {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
get: function() {
|
|
13
|
+
return from[k];
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
return from;
|
|
19
|
+
}
|