@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.
Files changed (78) hide show
  1. package/README.md +193 -0
  2. package/cjs/config/env-config.service.js +158 -0
  3. package/cjs/config/index.js +18 -0
  4. package/cjs/constants/database.constants.js +20 -0
  5. package/cjs/constants/index.js +18 -0
  6. package/cjs/docs/docs.config.js +192 -0
  7. package/cjs/docs/docs.setup.js +14 -0
  8. package/cjs/docs/index.js +19 -0
  9. package/cjs/index.js +24 -151
  10. package/cjs/interfaces/app-config.interfaces.js +4 -0
  11. package/cjs/interfaces/base-entity.interface.js +7 -0
  12. package/cjs/interfaces/database.interface.js +6 -0
  13. package/cjs/interfaces/index.js +21 -0
  14. package/cjs/interfaces/migration.interface.js +4 -0
  15. package/cjs/migration/cli.js +10 -0
  16. package/cjs/migration/datasource.factory.js +55 -0
  17. package/cjs/migration/index.js +54 -0
  18. package/cjs/migration/migration.cli.js +227 -0
  19. package/cjs/migration/migration.runner.js +235 -0
  20. package/cjs/seeders/base-seeder.js +95 -0
  21. package/cjs/seeders/cli.js +398 -0
  22. package/cjs/seeders/data-generator.js +247 -0
  23. package/cjs/seeders/entity-reader.js +168 -0
  24. package/cjs/seeders/index.js +77 -0
  25. package/cjs/seeders/seed-config.js +101 -0
  26. package/cjs/seeders/seed-runner.js +320 -0
  27. package/cjs/seeders/template-generator.js +297 -0
  28. package/cjs/utils/datasource-config.builder.js +98 -0
  29. package/cjs/utils/index.js +18 -0
  30. package/fesm/config/env-config.service.js +108 -0
  31. package/fesm/config/index.js +1 -0
  32. package/fesm/constants/database.constants.js +2 -0
  33. package/fesm/constants/index.js +1 -0
  34. package/fesm/docs/docs.config.js +184 -0
  35. package/fesm/docs/docs.setup.js +4 -0
  36. package/fesm/docs/index.js +2 -0
  37. package/fesm/index.js +12 -151
  38. package/fesm/interfaces/app-config.interfaces.js +3 -0
  39. package/fesm/interfaces/base-entity.interface.js +6 -0
  40. package/fesm/interfaces/database.interface.js +5 -0
  41. package/fesm/interfaces/index.js +4 -0
  42. package/fesm/interfaces/migration.interface.js +1 -0
  43. package/fesm/migration/cli.js +25 -0
  44. package/fesm/migration/datasource.factory.js +52 -0
  45. package/fesm/migration/index.js +17 -0
  46. package/fesm/migration/migration.cli.js +176 -0
  47. package/fesm/migration/migration.runner.js +225 -0
  48. package/fesm/seeders/base-seeder.js +110 -0
  49. package/fesm/seeders/cli.js +366 -0
  50. package/fesm/seeders/data-generator.js +249 -0
  51. package/fesm/seeders/entity-reader.js +170 -0
  52. package/fesm/seeders/index.js +11 -0
  53. package/fesm/seeders/seed-config.js +85 -0
  54. package/fesm/seeders/seed-runner.js +323 -0
  55. package/fesm/seeders/template-generator.js +257 -0
  56. package/fesm/utils/datasource-config.builder.js +79 -0
  57. package/fesm/utils/index.js +1 -0
  58. package/package.json +21 -18
  59. package/cjs/config-index.js +0 -1
  60. package/cjs/constants-index.js +0 -1
  61. package/cjs/docs-index.js +0 -1
  62. package/cjs/interfaces-index.js +0 -1
  63. package/cjs/migration-cli.js +0 -35
  64. package/cjs/migration-index.js +0 -34
  65. package/cjs/seeders-cli.js +0 -119
  66. package/cjs/seeders-index.js +0 -118
  67. package/cjs/utils-index.js +0 -1
  68. package/fesm/config-index.js +0 -1
  69. package/fesm/constants-index.js +0 -1
  70. package/fesm/docs-index.js +0 -1
  71. package/fesm/interfaces-index.js +0 -0
  72. package/fesm/migration-cli.js +0 -35
  73. package/fesm/migration-index.js +0 -34
  74. package/fesm/seeders-cli.js +0 -119
  75. package/fesm/seeders-index.js +0 -118
  76. package/fesm/utils-index.js +0 -1
  77. package/migration/cli.js +0 -3
  78. 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
+ }