@plyaz/core 1.1.0 → 1.2.0
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/dist/backend/featureFlags/config/feature-flag.config.d.ts +111 -0
- package/dist/backend/featureFlags/config/feature-flag.config.d.ts.map +1 -0
- package/dist/backend/featureFlags/config/validation.d.ts +181 -0
- package/dist/backend/featureFlags/config/validation.d.ts.map +1 -0
- package/dist/backend/featureFlags/database/connection.d.ts +321 -0
- package/dist/backend/featureFlags/database/connection.d.ts.map +1 -0
- package/dist/backend/featureFlags/database/repository.d.ts +518 -0
- package/dist/backend/featureFlags/database/repository.d.ts.map +1 -0
- package/dist/backend/featureFlags/decorators/feature-disabled.decorator.d.ts +6 -0
- package/dist/backend/featureFlags/decorators/feature-disabled.decorator.d.ts.map +1 -0
- package/dist/backend/featureFlags/decorators/feature-enabled.decorator.d.ts +8 -0
- package/dist/backend/featureFlags/decorators/feature-enabled.decorator.d.ts.map +1 -0
- package/dist/backend/featureFlags/decorators/feature-flag.decorator.d.ts +11 -0
- package/dist/backend/featureFlags/decorators/feature-flag.decorator.d.ts.map +1 -0
- package/dist/backend/featureFlags/feature-flag.controller.d.ts +1 -2
- package/dist/backend/featureFlags/feature-flag.controller.d.ts.map +1 -1
- package/dist/backend/featureFlags/feature-flag.module.d.ts +2 -3
- package/dist/backend/featureFlags/feature-flag.module.d.ts.map +1 -1
- package/dist/backend/featureFlags/feature-flag.service.d.ts +149 -8
- package/dist/backend/featureFlags/feature-flag.service.d.ts.map +1 -1
- package/dist/backend/featureFlags/guards/feature-flag.guard.d.ts +19 -0
- package/dist/backend/featureFlags/guards/feature-flag.guard.d.ts.map +1 -0
- package/dist/backend/featureFlags/index.d.ts +10 -36
- package/dist/backend/featureFlags/index.d.ts.map +1 -1
- package/dist/backend/featureFlags/interceptors/error-handling-interceptor.d.ts +16 -0
- package/dist/backend/featureFlags/interceptors/error-handling-interceptor.d.ts.map +1 -0
- package/dist/backend/featureFlags/interceptors/feature-flag-logging-interceptor.d.ts +18 -0
- package/dist/backend/featureFlags/interceptors/feature-flag-logging-interceptor.d.ts.map +1 -0
- package/dist/backend/featureFlags/middleware/feature-flag-middleware.d.ts +167 -0
- package/dist/backend/featureFlags/middleware/feature-flag-middleware.d.ts.map +1 -0
- package/dist/base/cache/feature/caching.d.ts +16 -0
- package/dist/base/cache/feature/caching.d.ts.map +1 -0
- package/dist/base/cache/index.d.ts +1 -0
- package/dist/base/cache/index.d.ts.map +1 -1
- package/dist/domain/featureFlags/providers/database.d.ts +17 -12
- package/dist/domain/featureFlags/providers/database.d.ts.map +1 -1
- package/dist/frontend/index.d.ts +1 -0
- package/dist/frontend/index.d.ts.map +1 -1
- package/dist/frontend/providers/ApiProvider.d.ts +41 -0
- package/dist/frontend/providers/ApiProvider.d.ts.map +1 -0
- package/dist/frontend/providers/index.d.ts +7 -0
- package/dist/frontend/providers/index.d.ts.map +1 -0
- package/dist/index.cjs +2325 -273
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.mjs +2315 -275
- package/dist/index.mjs.map +1 -1
- package/dist/services/ApiClientService.d.ts +90 -0
- package/dist/services/ApiClientService.d.ts.map +1 -0
- package/dist/services/index.d.ts +8 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/utils/common/index.d.ts +1 -1
- package/dist/utils/common/index.d.ts.map +1 -1
- package/dist/utils/common/validation.d.ts +20 -0
- package/dist/utils/common/validation.d.ts.map +1 -0
- package/dist/utils/db/databaseService.d.ts +6 -0
- package/dist/utils/db/databaseService.d.ts.map +1 -0
- package/dist/utils/db/index.d.ts +2 -0
- package/dist/utils/db/index.d.ts.map +1 -0
- package/dist/web_app/auth/add_user.d.ts +3 -0
- package/dist/web_app/auth/add_user.d.ts.map +1 -0
- package/dist/web_app/auth/update_user.d.ts +2 -0
- package/dist/web_app/auth/update_user.d.ts.map +1 -0
- package/package.json +20 -7
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Flag Configuration
|
|
3
|
+
*
|
|
4
|
+
* Configuration integration for feature flags with environment variable support.
|
|
5
|
+
* Imports configuration from .env.local and provides validation.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import { type FeatureFlagEnvironmentConfig } from '@plyaz/types';
|
|
9
|
+
/**
|
|
10
|
+
* Feature flag configuration factory
|
|
11
|
+
*
|
|
12
|
+
* This factory is the FIRST component called during application startup.
|
|
13
|
+
* It reads environment variables from .env.local and creates a validated configuration object.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* // Step 1: Called automatically by FeatureFlagService.onModuleInit()
|
|
18
|
+
* const config = FeatureFlagConfigFactory.fromEnvironment();
|
|
19
|
+
*
|
|
20
|
+
* // Step 2: Configuration is validated
|
|
21
|
+
* // Step 3: Provider is created with this config
|
|
22
|
+
* const provider = FeatureFlagProviderFactory.create(config, FEATURES);
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example Environment Variables (.env.local)
|
|
26
|
+
* ```bash
|
|
27
|
+
* SUPABASE_URL=https://your-project.supabase.co
|
|
28
|
+
* SUPABASE_ANON_PUBLIC_KEY=your-anon-key
|
|
29
|
+
* FEATURE_FLAG_PROVIDER=database
|
|
30
|
+
* FEATURE_FLAG_CACHE_ENABLED=true
|
|
31
|
+
* FEATURE_FLAG_CACHE_TTL=300
|
|
32
|
+
* FEATURE_FLAG_TABLE_NAME=feature_flags
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare class FeatureFlagConfigFactory {
|
|
36
|
+
/**
|
|
37
|
+
* Creates configuration from environment variables
|
|
38
|
+
*
|
|
39
|
+
* **EXECUTION ORDER: This is called FIRST in the initialization chain**
|
|
40
|
+
*
|
|
41
|
+
* Flow:
|
|
42
|
+
* 1. NestJS starts → FeatureFlagModule loads
|
|
43
|
+
* 2. FeatureFlagService.onModuleInit() called
|
|
44
|
+
* 3. → initializeProvider() called
|
|
45
|
+
* 4. → **THIS METHOD CALLED** ← YOU ARE HERE
|
|
46
|
+
* 5. → Configuration validated
|
|
47
|
+
* 6. → Provider created and initialized
|
|
48
|
+
* 7. → Database connection established
|
|
49
|
+
*
|
|
50
|
+
* @returns Validated configuration object ready for provider creation
|
|
51
|
+
* @throws {FeatureFlagConfigError} If environment variables are missing or invalid
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* // This method reads from process.env and creates:
|
|
56
|
+
* {
|
|
57
|
+
* provider: 'database',
|
|
58
|
+
* isCacheEnabled: true,
|
|
59
|
+
* cacheTtl: 300,
|
|
60
|
+
* databaseConfig: {
|
|
61
|
+
* connectionString: 'https://your-project.supabase.co',
|
|
62
|
+
* tableName: 'feature_flags',
|
|
63
|
+
* poolSize: 10,
|
|
64
|
+
* timeout: 30000
|
|
65
|
+
* }
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
static fromEnvironment(): FeatureFlagEnvironmentConfig;
|
|
70
|
+
/**
|
|
71
|
+
* Determines which provider to use - now uses constants instead of environment variables
|
|
72
|
+
*
|
|
73
|
+
* @private
|
|
74
|
+
* @returns Provider type from constants
|
|
75
|
+
*/
|
|
76
|
+
private static getProvider;
|
|
77
|
+
private static getCacheEnabled;
|
|
78
|
+
private static getCacheTtl;
|
|
79
|
+
private static getRefreshInterval;
|
|
80
|
+
private static getLoggingEnabled;
|
|
81
|
+
/**
|
|
82
|
+
* Creates database configuration from environment variables
|
|
83
|
+
*
|
|
84
|
+
* **CRITICAL**: This method requires SUPABASE_URL to be set in .env.local
|
|
85
|
+
*
|
|
86
|
+
* @private
|
|
87
|
+
* @returns Database configuration object
|
|
88
|
+
* @throws {FeatureFlagConfigError} If SUPABASE_URL is missing
|
|
89
|
+
*
|
|
90
|
+
* @example Environment Variables Required:
|
|
91
|
+
* ```bash
|
|
92
|
+
* SUPABASE_URL=https://your-project.supabase.co # REQUIRED
|
|
93
|
+
* SUPABASE_ANON_PUBLIC_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # Used in connection
|
|
94
|
+
* FEATURE_FLAG_TABLE_NAME=feature_flags # Optional, defaults to 'feature_flags'
|
|
95
|
+
* DB_POOL_SIZE=10 # Optional, defaults to 10
|
|
96
|
+
* DB_TIMEOUT=30000 # Optional, defaults to 30000ms
|
|
97
|
+
* ```
|
|
98
|
+
*
|
|
99
|
+
* @example Generated Configuration:
|
|
100
|
+
* ```typescript
|
|
101
|
+
* {
|
|
102
|
+
* connectionString: 'https://your-project.supabase.co',
|
|
103
|
+
* tableName: 'feature_flags',
|
|
104
|
+
* poolSize: 10,
|
|
105
|
+
* timeout: 30000
|
|
106
|
+
* }
|
|
107
|
+
* ```
|
|
108
|
+
*/
|
|
109
|
+
private static getDatabaseConfig;
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=feature-flag.config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feature-flag.config.d.ts","sourceRoot":"","sources":["../../../../src/backend/featureFlags/config/feature-flag.config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,EAKL,KAAK,4BAA4B,EAGlC,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,wBAAwB;IACnC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgCG;IACH,MAAM,CAAC,eAAe,IAAI,4BAA4B;IAmBtD;;;;;OAKG;IACH,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,eAAe;IAI9B,OAAO,CAAC,MAAM,CAAC,WAAW;IAI1B,OAAO,CAAC,MAAM,CAAC,kBAAkB;IAIjC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAOhC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,MAAM,CAAC,iBAAiB;CAgBjC"}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Validation utilities for feature flag configuration in NestJS applications.
|
|
5
|
+
* Provides error reporting and environment-specific validation.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
import { type FeatureFlagEnvironmentConfig, type FeatureFlagValidationResult } from '@plyaz/types';
|
|
9
|
+
/**
|
|
10
|
+
* FeatureFlagConfigValidator - Comprehensive configuration validation for feature flags
|
|
11
|
+
*
|
|
12
|
+
* @description Validates feature flag configuration objects to ensure they meet system requirements
|
|
13
|
+
* and best practices. Provides detailed error reporting and warnings for potential issues.
|
|
14
|
+
*
|
|
15
|
+
* **Validation Categories:**
|
|
16
|
+
* - Provider validation (memory, file, redis, api, database)
|
|
17
|
+
* - Cache configuration validation
|
|
18
|
+
* - Database connection validation
|
|
19
|
+
* - Environment-specific settings validation
|
|
20
|
+
*
|
|
21
|
+
* **Usage Flow:**
|
|
22
|
+
* 1. Configuration is loaded from environment variables
|
|
23
|
+
* 2. Validator checks all settings for correctness
|
|
24
|
+
* 3. Errors prevent system startup
|
|
25
|
+
* 4. Warnings are logged but don't block startup
|
|
26
|
+
*
|
|
27
|
+
* @example Basic Validation
|
|
28
|
+
* ```typescript
|
|
29
|
+
* const config = {
|
|
30
|
+
* provider: 'database',
|
|
31
|
+
* isCacheEnabled: true,
|
|
32
|
+
* cacheTtl: 300,
|
|
33
|
+
* databaseConfig: {
|
|
34
|
+
* connectionString: 'https://project.supabase.co',
|
|
35
|
+
* tableName: 'feature_flags'
|
|
36
|
+
* }
|
|
37
|
+
* };
|
|
38
|
+
*
|
|
39
|
+
* const result = FeatureFlagConfigValidator.validate(config);
|
|
40
|
+
*
|
|
41
|
+
* if (result.isValid) {
|
|
42
|
+
* console.log('Configuration is valid!');
|
|
43
|
+
* } else {
|
|
44
|
+
* console.error('Configuration errors:', result.errors);
|
|
45
|
+
* }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example Error Handling
|
|
49
|
+
* ```typescript
|
|
50
|
+
* try {
|
|
51
|
+
* FeatureFlagConfigValidator.validateOrThrow(config);
|
|
52
|
+
* // Configuration is valid, proceed with initialization
|
|
53
|
+
* } catch (error) {
|
|
54
|
+
* console.error('Invalid configuration:', error.message);
|
|
55
|
+
* process.exit(1);
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class FeatureFlagConfigValidator {
|
|
60
|
+
/**
|
|
61
|
+
* Validates feature flag configuration and returns detailed results
|
|
62
|
+
*
|
|
63
|
+
* @description Performs comprehensive validation of feature flag configuration,
|
|
64
|
+
* checking all aspects including provider settings, cache configuration,
|
|
65
|
+
* database connections, and environment-specific settings.
|
|
66
|
+
*
|
|
67
|
+
* @param {FeatureFlagEnvironmentConfig} config - Configuration object to validate
|
|
68
|
+
* @returns {ValidationResult} Validation result with errors and warnings
|
|
69
|
+
*
|
|
70
|
+
* @example Successful Validation
|
|
71
|
+
* ```typescript
|
|
72
|
+
* const validConfig = {
|
|
73
|
+
* provider: 'memory',
|
|
74
|
+
* isCacheEnabled: true,
|
|
75
|
+
* cacheTtl: 300,
|
|
76
|
+
* refreshInterval: 60
|
|
77
|
+
* };
|
|
78
|
+
*
|
|
79
|
+
* const result = FeatureFlagConfigValidator.validate(validConfig);
|
|
80
|
+
* // result.isValid = true
|
|
81
|
+
* // result.errors = []
|
|
82
|
+
* // result.warnings = []
|
|
83
|
+
* ```
|
|
84
|
+
*
|
|
85
|
+
* @example Validation with Errors
|
|
86
|
+
* ```typescript
|
|
87
|
+
* const invalidConfig = {
|
|
88
|
+
* provider: 'invalid_provider', // Error: invalid provider
|
|
89
|
+
* cacheTtl: -100, // Error: negative TTL
|
|
90
|
+
* databaseConfig: { // Error: missing connection string
|
|
91
|
+
* tableName: 'flags'
|
|
92
|
+
* }
|
|
93
|
+
* };
|
|
94
|
+
*
|
|
95
|
+
* const result = FeatureFlagConfigValidator.validate(invalidConfig);
|
|
96
|
+
* // result.isValid = false
|
|
97
|
+
* // result.errors = [
|
|
98
|
+
* // { field: 'provider', message: 'Invalid provider...', code: 'INVALID_PROVIDER' },
|
|
99
|
+
* // { field: 'cacheTtl', message: 'Cache TTL must be non-negative', code: 'INVALID_CACHE_TTL' }
|
|
100
|
+
* // ]
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @example Validation with Warnings
|
|
104
|
+
* ```typescript
|
|
105
|
+
* const configWithWarnings = {
|
|
106
|
+
* provider: 'database',
|
|
107
|
+
* cacheTtl: 7200, // Warning: very high TTL
|
|
108
|
+
* isLoggingEnabled: true, // Warning: logging in production
|
|
109
|
+
* databaseConfig: {
|
|
110
|
+
* connectionString: 'https://project.supabase.co',
|
|
111
|
+
* tableName: 'feature_flags'
|
|
112
|
+
* }
|
|
113
|
+
* };
|
|
114
|
+
*
|
|
115
|
+
* process.env.NODE_ENV = 'production';
|
|
116
|
+
* const result = FeatureFlagConfigValidator.validate(configWithWarnings);
|
|
117
|
+
* // result.isValid = true (warnings don't fail validation)
|
|
118
|
+
* // result.warnings = [
|
|
119
|
+
* // { field: 'cacheTtl', message: 'Cache TTL is very high...', code: 'HIGH_CACHE_TTL' },
|
|
120
|
+
* // { field: 'isLoggingEnabled', message: 'Logging is enabled in production...', code: 'PRODUCTION_LOGGING_ENABLED' }
|
|
121
|
+
* // ]
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
static validate(config: FeatureFlagEnvironmentConfig): FeatureFlagValidationResult;
|
|
125
|
+
private static validateProvider;
|
|
126
|
+
private static validateCacheSettings;
|
|
127
|
+
private static validateDatabaseConfig;
|
|
128
|
+
private static validateConnectionString;
|
|
129
|
+
private static validateTableName;
|
|
130
|
+
private static validatePoolSize;
|
|
131
|
+
private static validateTimeout;
|
|
132
|
+
private static getWarnings;
|
|
133
|
+
/**
|
|
134
|
+
* Validates configuration and throws error if validation fails
|
|
135
|
+
*
|
|
136
|
+
* @description Convenience method that validates configuration and throws a detailed
|
|
137
|
+
* error if validation fails. This is typically used during application startup
|
|
138
|
+
* to ensure the system doesn't start with invalid configuration.
|
|
139
|
+
*
|
|
140
|
+
* @param {FeatureFlagEnvironmentConfig} config - Configuration to validate
|
|
141
|
+
* @throws {DatabaseError} When validation fails with detailed error messages
|
|
142
|
+
*
|
|
143
|
+
* @example Startup Validation
|
|
144
|
+
* ```typescript
|
|
145
|
+
* // In FeatureFlagService.onModuleInit()
|
|
146
|
+
* try {
|
|
147
|
+
* const config = FeatureFlagConfigFactory.fromEnvironment();
|
|
148
|
+
* FeatureFlagConfigValidator.validateOrThrow(config);
|
|
149
|
+
*
|
|
150
|
+
* // Configuration is valid, proceed with initialization
|
|
151
|
+
* this.provider = FeatureFlagProviderFactory.create(config, FEATURES);
|
|
152
|
+
* await this.provider.initialize();
|
|
153
|
+
* } catch (error) {
|
|
154
|
+
* this.logger.error('Configuration validation failed:', error.message);
|
|
155
|
+
* throw error; // Prevent service from starting
|
|
156
|
+
* }
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @example Error Output
|
|
160
|
+
* ```typescript
|
|
161
|
+
* // When validation fails, throws DatabaseError with message:
|
|
162
|
+
* // "Configuration validation failed:
|
|
163
|
+
* // provider: Invalid provider: invalid_type. Must be one of: memory, file, redis, api, database
|
|
164
|
+
* // cacheTtl: Cache TTL must be non-negative
|
|
165
|
+
* // databaseConfig.connectionString: Database connection string is required"
|
|
166
|
+
* ```
|
|
167
|
+
*
|
|
168
|
+
* @example Environment Variable Validation
|
|
169
|
+
* ```bash
|
|
170
|
+
* # Missing required environment variables:
|
|
171
|
+
* # SUPABASE_URL= # Empty/missing
|
|
172
|
+
* # FEATURE_FLAG_PROVIDER=database
|
|
173
|
+
*
|
|
174
|
+
* # Results in error:
|
|
175
|
+
* # "Configuration validation failed:
|
|
176
|
+
* # databaseConfig.connectionString: Database connection string is required"
|
|
177
|
+
* ```
|
|
178
|
+
*/
|
|
179
|
+
static validateOrThrow(config: FeatureFlagEnvironmentConfig): void;
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../../../../src/backend/featureFlags/config/validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAEL,KAAK,4BAA4B,EACjC,KAAK,2BAA2B,EAGjC,MAAM,cAAc,CAAC;AAKtB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiDG;AACH,qBAAa,0BAA0B;IACrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+DG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,4BAA4B,GAAG,2BAA2B;IAiClF,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAY/B,OAAO,CAAC,MAAM,CAAC,qBAAqB;IAkBpC,OAAO,CAAC,MAAM,CAAC,sBAAsB;IAiBrC,OAAO,CAAC,MAAM,CAAC,wBAAwB;IAoBvC,OAAO,CAAC,MAAM,CAAC,iBAAiB;IAUhC,OAAO,CAAC,MAAM,CAAC,gBAAgB;IAa/B,OAAO,CAAC,MAAM,CAAC,eAAe;IAU9B,OAAO,CAAC,MAAM,CAAC,WAAW;IA+B1B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6CG;IACH,MAAM,CAAC,eAAe,CAAC,MAAM,EAAE,4BAA4B,GAAG,IAAI;CAYnE"}
|
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
import { type DatabaseServiceInterface, type Transaction } from '@plyaz/types/db';
|
|
2
|
+
/**
|
|
3
|
+
* DatabaseConnectionManager - Singleton manager for feature flag database connections
|
|
4
|
+
*
|
|
5
|
+
* @description Manages Supabase database connections for the feature flag system using a singleton pattern.
|
|
6
|
+
* Handles connection initialization, table registration, transactions, and cleanup. This is the core
|
|
7
|
+
* database layer that all feature flag operations depend on.
|
|
8
|
+
*
|
|
9
|
+
* **Initialization Flow:**
|
|
10
|
+
* 1. FeatureFlagService calls initialize() during onModuleInit()
|
|
11
|
+
* 2. Reads Supabase credentials from environment variables
|
|
12
|
+
* 3. Creates database service with @plyaz/db
|
|
13
|
+
* 4. Registers feature flag tables
|
|
14
|
+
* 5. Enables caching and other optimizations
|
|
15
|
+
*
|
|
16
|
+
* **Required Environment Variables:**
|
|
17
|
+
* - SUPABASE_URL: Your Supabase project URL
|
|
18
|
+
* - SUPABASE_SERVICE_ROLE_KEY: Service role key for admin operations
|
|
19
|
+
* - SUPABASE_ANON_PUBLIC_KEY: Anonymous key for public operations
|
|
20
|
+
*
|
|
21
|
+
* @example Environment Setup (.env.local)
|
|
22
|
+
* ```bash
|
|
23
|
+
* SUPABASE_URL=https://your-project.supabase.co
|
|
24
|
+
* SUPABASE_SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
25
|
+
* SUPABASE_ANON_PUBLIC_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
|
|
26
|
+
* ```
|
|
27
|
+
*
|
|
28
|
+
* @example Basic Usage (Internal - called by FeatureFlagService)
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // During system initialization:
|
|
31
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
32
|
+
* await manager.initialize();
|
|
33
|
+
*
|
|
34
|
+
* // During runtime operations:
|
|
35
|
+
* const db = manager.getDatabase();
|
|
36
|
+
* const flags = await db.query('feature_flags', { limit: 100 });
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example Transaction Usage
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
42
|
+
*
|
|
43
|
+
* // Atomic flag creation with rules
|
|
44
|
+
* const result = await manager.transaction(async (tx) => {
|
|
45
|
+
* // Create flag
|
|
46
|
+
* const flag = await tx.create('feature_flags', {
|
|
47
|
+
* key: 'NEW_FEATURE',
|
|
48
|
+
* value: true,
|
|
49
|
+
* is_enabled: true
|
|
50
|
+
* });
|
|
51
|
+
*
|
|
52
|
+
* // Create associated rule
|
|
53
|
+
* const rule = await tx.create('feature_flag_rules', {
|
|
54
|
+
* flag_key: 'NEW_FEATURE',
|
|
55
|
+
* name: 'Premium Users Only',
|
|
56
|
+
* conditions: [{ field: 'userRole', operator: 'equals', value: 'premium' }]
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* return { flag, rule };
|
|
60
|
+
* });
|
|
61
|
+
* ```
|
|
62
|
+
*
|
|
63
|
+
*/
|
|
64
|
+
export declare class DatabaseConnectionManager {
|
|
65
|
+
private static instance;
|
|
66
|
+
private databaseService;
|
|
67
|
+
private constructor();
|
|
68
|
+
/**
|
|
69
|
+
* Gets the singleton instance of DatabaseConnectionManager
|
|
70
|
+
*
|
|
71
|
+
* @description Returns the single instance of the connection manager, creating it if it doesn't exist.
|
|
72
|
+
* This ensures only one database connection pool is maintained across the application.
|
|
73
|
+
*
|
|
74
|
+
* @returns {DatabaseConnectionManager} The singleton instance
|
|
75
|
+
*
|
|
76
|
+
* @example Getting the Instance
|
|
77
|
+
* ```typescript
|
|
78
|
+
* // Always returns the same instance
|
|
79
|
+
* const manager1 = DatabaseConnectionManager.getInstance();
|
|
80
|
+
* const manager2 = DatabaseConnectionManager.getInstance();
|
|
81
|
+
* console.log(manager1 === manager2); // true
|
|
82
|
+
*
|
|
83
|
+
* // Use in services
|
|
84
|
+
* class FeatureFlagRepository {
|
|
85
|
+
* private connectionManager = DatabaseConnectionManager.getInstance();
|
|
86
|
+
*
|
|
87
|
+
* async getFlags() {
|
|
88
|
+
* const db = this.connectionManager.getDatabase();
|
|
89
|
+
* return db.query('feature_flags');
|
|
90
|
+
* }
|
|
91
|
+
* }
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
static getInstance(): DatabaseConnectionManager;
|
|
95
|
+
/**
|
|
96
|
+
* Initializes the database connection and registers feature flag tables
|
|
97
|
+
*
|
|
98
|
+
* @description Sets up the Supabase connection using environment variables and registers
|
|
99
|
+
* all feature flag related tables. This method is idempotent - calling it multiple
|
|
100
|
+
* times won't create additional connections.
|
|
101
|
+
*
|
|
102
|
+
* **What it does:**
|
|
103
|
+
* 1. Validates required environment variables
|
|
104
|
+
* 2. Creates Supabase database service
|
|
105
|
+
* 3. Configures caching (5-minute TTL)
|
|
106
|
+
* 4. Registers feature flag tables with proper ID columns
|
|
107
|
+
* 5. Disables audit logging (until tables are created)
|
|
108
|
+
*
|
|
109
|
+
* @throws {DatabaseError} When environment variables are missing or connection fails
|
|
110
|
+
*
|
|
111
|
+
* @example Initialization Process
|
|
112
|
+
* ```typescript
|
|
113
|
+
* // Called automatically by FeatureFlagService.onModuleInit()
|
|
114
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
115
|
+
*
|
|
116
|
+
* try {
|
|
117
|
+
* await manager.initialize();
|
|
118
|
+
* console.log('Database connection established');
|
|
119
|
+
* } catch (error) {
|
|
120
|
+
* console.error('Failed to connect to database:', error.message);
|
|
121
|
+
* // Error: Missing environment variables for Supabase connection
|
|
122
|
+
* }
|
|
123
|
+
* ```
|
|
124
|
+
*
|
|
125
|
+
* @example Environment Variable Validation
|
|
126
|
+
* ```typescript
|
|
127
|
+
* // If any of these are missing, initialization fails:
|
|
128
|
+
* // SUPABASE_URL=undefined
|
|
129
|
+
* // SUPABASE_SERVICE_ROLE_KEY=undefined
|
|
130
|
+
* // SUPABASE_ANON_PUBLIC_KEY=undefined
|
|
131
|
+
*
|
|
132
|
+
* // Throws: DatabaseError with code CONFIG_REQUIRED
|
|
133
|
+
* ```
|
|
134
|
+
*
|
|
135
|
+
* @example Registered Tables
|
|
136
|
+
* ```typescript
|
|
137
|
+
* // These tables are automatically registered:
|
|
138
|
+
* // - feature_flags (ID: key)
|
|
139
|
+
* // - feature_flag_rules (ID: id)
|
|
140
|
+
* // - feature_flag_overrides (ID: id)
|
|
141
|
+
* // - feature_flag_evaluations (ID: id)
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
initialize(): Promise<void>;
|
|
145
|
+
/**
|
|
146
|
+
* Gets the initialized database service instance
|
|
147
|
+
*
|
|
148
|
+
* @description Returns the database service for performing queries. The database must be
|
|
149
|
+
* initialized first using initialize() method, otherwise this will throw an error.
|
|
150
|
+
*
|
|
151
|
+
* @returns {DatabaseServiceInterface} The database service instance
|
|
152
|
+
* @throws {DatabaseError} When database is not initialized
|
|
153
|
+
*
|
|
154
|
+
* @example Basic Usage
|
|
155
|
+
* ```typescript
|
|
156
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
157
|
+
* await manager.initialize(); // Must initialize first
|
|
158
|
+
*
|
|
159
|
+
* const db = manager.getDatabase();
|
|
160
|
+
*
|
|
161
|
+
* // Query feature flags
|
|
162
|
+
* const result = await db.query('feature_flags', {
|
|
163
|
+
* filters: [{ field: 'is_enabled', operator: 'eq', value: true }],
|
|
164
|
+
* sort: [{ field: 'key', direction: 'asc' }]
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* if (result.success) {
|
|
168
|
+
* console.log('Found flags:', result.value.data);
|
|
169
|
+
* }
|
|
170
|
+
* ```
|
|
171
|
+
*
|
|
172
|
+
* @example Error Handling
|
|
173
|
+
* ```typescript
|
|
174
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
175
|
+
* // Don't call initialize()
|
|
176
|
+
*
|
|
177
|
+
* try {
|
|
178
|
+
* const db = manager.getDatabase();
|
|
179
|
+
* } catch (error) {
|
|
180
|
+
* console.error(error.message);
|
|
181
|
+
* // "Database not initialized. Call initialize() first."
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
*
|
|
185
|
+
* @example CRUD Operations
|
|
186
|
+
* ```typescript
|
|
187
|
+
* const db = manager.getDatabase();
|
|
188
|
+
*
|
|
189
|
+
* // Create a flag
|
|
190
|
+
* const createResult = await db.create('feature_flags', {
|
|
191
|
+
* key: 'NEW_FEATURE',
|
|
192
|
+
* value: true,
|
|
193
|
+
* is_enabled: true
|
|
194
|
+
* });
|
|
195
|
+
*
|
|
196
|
+
* // Update a flag
|
|
197
|
+
* const updateResult = await db.update('feature_flags', 'NEW_FEATURE', {
|
|
198
|
+
* value: false
|
|
199
|
+
* });
|
|
200
|
+
*
|
|
201
|
+
* // Delete a flag
|
|
202
|
+
* const deleteResult = await db.delete('feature_flags', 'NEW_FEATURE');
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
getDatabase(): DatabaseServiceInterface;
|
|
206
|
+
/**
|
|
207
|
+
* Executes a database transaction with automatic rollback on failure
|
|
208
|
+
*
|
|
209
|
+
* @description Provides atomic database operations by wrapping multiple queries in a transaction.
|
|
210
|
+
* If any operation fails, all changes are rolled back automatically. This is essential for
|
|
211
|
+
* maintaining data consistency when creating flags with rules or performing bulk operations.
|
|
212
|
+
*
|
|
213
|
+
* @template T The return type of the transaction callback
|
|
214
|
+
* @param {Function} callback - Function that receives transaction object and performs operations
|
|
215
|
+
* @returns {Promise<T>} The result of the transaction callback
|
|
216
|
+
* @throws {DatabaseError} When transaction fails or returns no value
|
|
217
|
+
*
|
|
218
|
+
* @example Atomic Flag Creation with Rules
|
|
219
|
+
* ```typescript
|
|
220
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
221
|
+
*
|
|
222
|
+
* const result = await manager.transaction(async (tx) => {
|
|
223
|
+
* // Create the flag
|
|
224
|
+
* const flag = await tx.create('feature_flags', {
|
|
225
|
+
* key: 'PREMIUM_CHECKOUT',
|
|
226
|
+
* value: true,
|
|
227
|
+
* is_enabled: true,
|
|
228
|
+
* description: 'Premium checkout flow'
|
|
229
|
+
* });
|
|
230
|
+
*
|
|
231
|
+
* // Create targeting rule
|
|
232
|
+
* const rule = await tx.create('feature_flag_rules', {
|
|
233
|
+
* flag_key: 'PREMIUM_CHECKOUT',
|
|
234
|
+
* name: 'Premium Users Only',
|
|
235
|
+
* conditions: [
|
|
236
|
+
* { field: 'userRole', operator: 'equals', value: 'premium' },
|
|
237
|
+
* { field: 'subscriptionActive', operator: 'equals', value: true }
|
|
238
|
+
* ],
|
|
239
|
+
* value: true,
|
|
240
|
+
* priority: 100
|
|
241
|
+
* });
|
|
242
|
+
*
|
|
243
|
+
* return { flag, rule };
|
|
244
|
+
* });
|
|
245
|
+
*
|
|
246
|
+
* console.log('Created flag and rule:', result);
|
|
247
|
+
* ```
|
|
248
|
+
*
|
|
249
|
+
* @example Bulk Flag Updates
|
|
250
|
+
* ```typescript
|
|
251
|
+
* const flagsToUpdate = ['FEATURE_A', 'FEATURE_B', 'FEATURE_C'];
|
|
252
|
+
*
|
|
253
|
+
* await manager.transaction(async (tx) => {
|
|
254
|
+
* for (const flagKey of flagsToUpdate) {
|
|
255
|
+
* await tx.update('feature_flags', flagKey, {
|
|
256
|
+
* is_enabled: false,
|
|
257
|
+
* updated_at: new Date().toISOString()
|
|
258
|
+
* });
|
|
259
|
+
* }
|
|
260
|
+
*
|
|
261
|
+
* // Log the bulk update
|
|
262
|
+
* await tx.create('feature_flag_evaluations', {
|
|
263
|
+
* flag_key: 'BULK_UPDATE',
|
|
264
|
+
* result: { updatedFlags: flagsToUpdate },
|
|
265
|
+
* reason: 'bulk_disable',
|
|
266
|
+
* evaluated_at: new Date().toISOString()
|
|
267
|
+
* });
|
|
268
|
+
* });
|
|
269
|
+
* ```
|
|
270
|
+
*
|
|
271
|
+
* @example Error Handling and Rollback
|
|
272
|
+
* ```typescript
|
|
273
|
+
* try {
|
|
274
|
+
* await manager.transaction(async (tx) => {
|
|
275
|
+
* await tx.create('feature_flags', { key: 'TEST_FLAG', value: true });
|
|
276
|
+
*
|
|
277
|
+
* // This will cause the entire transaction to rollback
|
|
278
|
+
* throw new Error('Something went wrong');
|
|
279
|
+
*
|
|
280
|
+
* // This won't execute, and the flag creation above will be rolled back
|
|
281
|
+
* await tx.create('feature_flag_rules', { flag_key: 'TEST_FLAG' });
|
|
282
|
+
* });
|
|
283
|
+
* } catch (error) {
|
|
284
|
+
* console.log('Transaction failed, all changes rolled back');
|
|
285
|
+
* }
|
|
286
|
+
* ```
|
|
287
|
+
*/
|
|
288
|
+
transaction<T>(callback: (tx: Transaction) => Promise<T>): Promise<T>;
|
|
289
|
+
/**
|
|
290
|
+
* Closes the database connection and cleans up resources
|
|
291
|
+
*
|
|
292
|
+
* @description Properly closes the database connection and resets the singleton instance.
|
|
293
|
+
* This is typically called during application shutdown or in tests that need to reset
|
|
294
|
+
* the connection state.
|
|
295
|
+
*
|
|
296
|
+
* @example Application Shutdown
|
|
297
|
+
* ```typescript
|
|
298
|
+
* // In your NestJS module's onModuleDestroy
|
|
299
|
+
* export class FeatureFlagModule implements OnModuleDestroy {
|
|
300
|
+
* async onModuleDestroy() {
|
|
301
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
302
|
+
* await manager.close();
|
|
303
|
+
* console.log('Database connection closed');
|
|
304
|
+
* }
|
|
305
|
+
* }
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @example Test Cleanup
|
|
309
|
+
* ```typescript
|
|
310
|
+
* describe('Feature Flag Tests', () => {
|
|
311
|
+
* afterEach(async () => {
|
|
312
|
+
* // Clean up connection between tests
|
|
313
|
+
* const manager = DatabaseConnectionManager.getInstance();
|
|
314
|
+
* await manager.close();
|
|
315
|
+
* });
|
|
316
|
+
* });
|
|
317
|
+
* ```
|
|
318
|
+
*/
|
|
319
|
+
close(): Promise<void>;
|
|
320
|
+
}
|
|
321
|
+
//# sourceMappingURL=connection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../src/backend/featureFlags/database/connection.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,KAAK,wBAAwB,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAEjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6DG;AACH,qBAAa,yBAAyB;IACpC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAA4B;IACnD,OAAO,CAAC,eAAe,CAAyC;IAEhE,OAAO;IAEP;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,MAAM,CAAC,WAAW,IAAI,yBAAyB;IAO/C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgDG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA4DjC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2DG;IACH,WAAW,IAAI,wBAAwB;IAUvC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAiFG;IACG,WAAW,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAe3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAI7B"}
|