@tsdevstack/nest-common 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/auth/auth-user.interface.d.ts +62 -0
- package/dist/auth/auth.guard.d.ts +181 -0
- package/dist/auth/auth.guard.test.d.ts +1 -0
- package/dist/auth/auth.module.d.ts +45 -0
- package/dist/auth/index.d.ts +17 -0
- package/dist/auth/partner-api.decorator.d.ts +42 -0
- package/dist/auth/partner.decorator.d.ts +60 -0
- package/dist/auth/partner.decorator.test.d.ts +1 -0
- package/dist/auth/public.decorator.d.ts +42 -0
- package/dist/auth/public.decorator.test.d.ts +1 -0
- package/dist/auth/utils/extract-user-from-headers.d.ts +45 -0
- package/dist/auth/utils/extract-user-from-headers.test.d.ts +1 -0
- package/dist/auth/utils/index.d.ts +8 -0
- package/dist/auth/utils/parse-header-value.d.ts +40 -0
- package/dist/auth/utils/parse-header-value.test.d.ts +1 -0
- package/dist/auth/utils/to-camel-case.d.ts +18 -0
- package/dist/auth/utils/to-camel-case.test.d.ts +1 -0
- package/dist/bootstrap/create-app.d.ts +31 -0
- package/dist/bootstrap/create-app.test.d.ts +1 -0
- package/dist/bootstrap/start-worker.d.ts +24 -0
- package/dist/bootstrap/start-worker.test.d.ts +1 -0
- package/dist/bull/bull-config.module.d.ts +22 -0
- package/dist/bull/bull-config.module.test.d.ts +1 -0
- package/dist/bull/index.d.ts +1 -0
- package/dist/config/load-framework-config.d.ts +32 -0
- package/dist/config/load-framework-config.test.d.ts +1 -0
- package/dist/database/prisma-connection.d.ts +48 -0
- package/dist/database/prisma-connection.test.d.ts +1 -0
- package/dist/email-rate-limit/email-rate-limit.decorator.d.ts +8 -0
- package/dist/email-rate-limit/email-rate-limit.decorator.test.d.ts +1 -0
- package/dist/email-rate-limit/email-rate-limit.guard.d.ts +11 -0
- package/dist/email-rate-limit/email-rate-limit.guard.test.d.ts +1 -0
- package/dist/email-rate-limit/email-rate-limit.module.d.ts +2 -0
- package/dist/health/health.controller.d.ts +11 -0
- package/dist/health/health.controller.test.d.ts +1 -0
- package/dist/health/health.interface.d.ts +31 -0
- package/dist/health/health.module.d.ts +5 -0
- package/dist/health/health.service.d.ts +12 -0
- package/dist/health/health.service.test.d.ts +1 -0
- package/dist/health/index.d.ts +6 -0
- package/dist/health/indicators/memory.indicator.d.ts +7 -0
- package/dist/health/indicators/memory.indicator.test.d.ts +1 -0
- package/dist/health/indicators/redis.indicator.d.ts +7 -0
- package/dist/health/indicators/redis.indicator.test.d.ts +1 -0
- package/dist/index.d.ts +40 -0
- package/dist/index.js +9 -0
- package/dist/index.mjs +9 -0
- package/dist/logging/index.d.ts +6 -0
- package/dist/logging/logger.interface.d.ts +29 -0
- package/dist/logging/logger.module.d.ts +14 -0
- package/dist/logging/logger.service.d.ts +31 -0
- package/dist/logging/logger.service.test.d.ts +1 -0
- package/dist/logging/logging.interceptor.d.ts +8 -0
- package/dist/logging/logging.interceptor.test.d.ts +1 -0
- package/dist/metrics/index.d.ts +5 -0
- package/dist/metrics/metrics.controller.d.ts +7 -0
- package/dist/metrics/metrics.controller.test.d.ts +1 -0
- package/dist/metrics/metrics.interceptor.d.ts +9 -0
- package/dist/metrics/metrics.interceptor.test.d.ts +1 -0
- package/dist/metrics/metrics.interface.d.ts +17 -0
- package/dist/metrics/metrics.module.d.ts +5 -0
- package/dist/metrics/metrics.service.d.ts +79 -0
- package/dist/metrics/metrics.service.test.d.ts +1 -0
- package/dist/notifications/index.d.ts +15 -0
- package/dist/notifications/interfaces/email-options.interface.d.ts +23 -0
- package/dist/notifications/interfaces/index.d.ts +6 -0
- package/dist/notifications/interfaces/push-options.interface.d.ts +16 -0
- package/dist/notifications/interfaces/sms-options.interface.d.ts +12 -0
- package/dist/notifications/notification.module.d.ts +2 -0
- package/dist/notifications/notification.module.test.d.ts +1 -0
- package/dist/notifications/notification.service.d.ts +28 -0
- package/dist/notifications/notification.service.test.d.ts +1 -0
- package/dist/notifications/providers/email/console.provider.d.ts +9 -0
- package/dist/notifications/providers/email/console.provider.test.d.ts +1 -0
- package/dist/notifications/providers/email/resend.provider.d.ts +24 -0
- package/dist/notifications/providers/email/resend.provider.test.d.ts +1 -0
- package/dist/notifications/providers/email-provider.interface.d.ts +17 -0
- package/dist/observability/index.d.ts +2 -0
- package/dist/observability/observability.interface.d.ts +32 -0
- package/dist/observability/observability.module.d.ts +24 -0
- package/dist/observability/observability.module.test.d.ts +1 -0
- package/dist/open-api-docs/create-swagger-document.d.ts +10 -0
- package/dist/open-api-docs/create-swagger-document.test.d.ts +1 -0
- package/dist/open-api-docs/generate-swagger-docs.d.ts +12 -0
- package/dist/open-api-docs/generate-swagger-docs.test.d.ts +1 -0
- package/dist/rate-limit/rate-limit-headers.interceptor.d.ts +5 -0
- package/dist/rate-limit/rate-limit-headers.interceptor.test.d.ts +1 -0
- package/dist/rate-limit/rate-limit.decorator.d.ts +11 -0
- package/dist/rate-limit/rate-limit.decorator.test.d.ts +1 -0
- package/dist/rate-limit/rate-limit.guard.d.ts +13 -0
- package/dist/rate-limit/rate-limit.guard.test.d.ts +1 -0
- package/dist/rate-limit/rate-limit.module.d.ts +2 -0
- package/dist/redis/redis.module.d.ts +2 -0
- package/dist/redis/redis.service.d.ts +17 -0
- package/dist/redis/redis.service.test.d.ts +1 -0
- package/dist/scheduler/index.d.ts +1 -0
- package/dist/scheduler/scheduler.guard.d.ts +73 -0
- package/dist/scheduler/scheduler.guard.test.d.ts +1 -0
- package/dist/secrets/index.d.ts +10 -0
- package/dist/secrets/providers/aws.provider.d.ts +56 -0
- package/dist/secrets/providers/aws.provider.test.d.ts +1 -0
- package/dist/secrets/providers/azure.provider.d.ts +70 -0
- package/dist/secrets/providers/azure.provider.test.d.ts +1 -0
- package/dist/secrets/providers/cloud-provider-adapter.d.ts +50 -0
- package/dist/secrets/providers/cloud-provider-adapter.test.d.ts +1 -0
- package/dist/secrets/providers/cloud-provider.interface.d.ts +86 -0
- package/dist/secrets/providers/gcp.provider.d.ts +64 -0
- package/dist/secrets/providers/gcp.provider.test.d.ts +1 -0
- package/dist/secrets/providers/local.provider.d.ts +82 -0
- package/dist/secrets/providers/local.provider.test.d.ts +1 -0
- package/dist/secrets/providers/provider-factory.d.ts +39 -0
- package/dist/secrets/providers/provider-factory.test.d.ts +1 -0
- package/dist/secrets/secrets.interface.d.ts +93 -0
- package/dist/secrets/secrets.module.d.ts +24 -0
- package/dist/secrets/secrets.service.d.ts +70 -0
- package/dist/secrets/secrets.service.test.d.ts +1 -0
- package/dist/service-client/base-service-client.d.ts +113 -0
- package/dist/service-client/base-service-client.test.d.ts +1 -0
- package/dist/service-client/filter-forward-headers.d.ts +11 -0
- package/dist/service-client/filter-forward-headers.test.d.ts +1 -0
- package/dist/telemetry/index.d.ts +4 -0
- package/dist/telemetry/telemetry.interface.d.ts +33 -0
- package/dist/telemetry/telemetry.module.d.ts +5 -0
- package/dist/telemetry/telemetry.service.d.ts +39 -0
- package/dist/telemetry/telemetry.service.test.d.ts +1 -0
- package/dist/telemetry/tracing.interceptor.d.ts +11 -0
- package/dist/telemetry/tracing.interceptor.test.d.ts +1 -0
- package/dist/utils/package-json.d.ts +25 -0
- package/package.json +102 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SecretsProvider } from '../secrets.interface';
|
|
2
|
+
import { CloudSecretsProvider } from './cloud-provider.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Adapter to make CloudSecretsProvider compatible with SecretsProvider interface
|
|
5
|
+
*
|
|
6
|
+
* The CloudSecretsProvider interface is designed for cloud-native operations
|
|
7
|
+
* (get, set, remove, list, exists) while SecretsProvider is the legacy interface
|
|
8
|
+
* used throughout the application.
|
|
9
|
+
*
|
|
10
|
+
* This adapter bridges the two interfaces, allowing cloud providers to work
|
|
11
|
+
* with the existing SecretsService implementation.
|
|
12
|
+
*/
|
|
13
|
+
export declare class CloudProviderAdapter implements SecretsProvider {
|
|
14
|
+
private cloudProvider;
|
|
15
|
+
private serviceName;
|
|
16
|
+
constructor(cloudProvider: CloudSecretsProvider, serviceName: string);
|
|
17
|
+
/**
|
|
18
|
+
* Get a single secret by key
|
|
19
|
+
* Delegates to cloud provider's get() which handles service-scoped → shared fallback
|
|
20
|
+
*/
|
|
21
|
+
get(key: string): Promise<string>;
|
|
22
|
+
/**
|
|
23
|
+
* Get all secrets for a service
|
|
24
|
+
* Lists all secrets and filters by service name
|
|
25
|
+
*
|
|
26
|
+
* Note: This is less efficient than the local provider's getAll()
|
|
27
|
+
* since cloud providers need to fetch each secret individually.
|
|
28
|
+
* Consider caching at the application level if this becomes a bottleneck.
|
|
29
|
+
*/
|
|
30
|
+
getAll(): Promise<Record<string, string>>;
|
|
31
|
+
/**
|
|
32
|
+
* Set a secret value
|
|
33
|
+
* Adds metadata to indicate it's a user-managed secret
|
|
34
|
+
*/
|
|
35
|
+
set(key: string, value: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Delete a secret
|
|
38
|
+
*/
|
|
39
|
+
delete(key: string): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Get provider name
|
|
42
|
+
*/
|
|
43
|
+
getName(): string;
|
|
44
|
+
/**
|
|
45
|
+
* Clear cache
|
|
46
|
+
* Cloud providers don't expose cache clearing, so this is a no-op
|
|
47
|
+
* The cache will expire naturally based on TTL
|
|
48
|
+
*/
|
|
49
|
+
clearCache(): void;
|
|
50
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cloud Secrets Provider Interface
|
|
3
|
+
*
|
|
4
|
+
* Common interface for all cloud secret providers (GCP, AWS, Azure).
|
|
5
|
+
* Providers handle cloud-specific API calls and caching.
|
|
6
|
+
*/
|
|
7
|
+
export interface CloudSecretsProvider {
|
|
8
|
+
/**
|
|
9
|
+
* Get secret value by key
|
|
10
|
+
*
|
|
11
|
+
* Provider handles:
|
|
12
|
+
* - Service-scoped lookup: {project}-{service}-{key}
|
|
13
|
+
* - Shared fallback: {project}-shared-{key}
|
|
14
|
+
* - Caching (5-minute TTL)
|
|
15
|
+
*
|
|
16
|
+
* @param key Secret key (e.g., 'DATABASE_URL')
|
|
17
|
+
* @returns Secret value or null if not found
|
|
18
|
+
*/
|
|
19
|
+
get(key: string): Promise<string | null>;
|
|
20
|
+
/**
|
|
21
|
+
* Set secret value
|
|
22
|
+
*
|
|
23
|
+
* Provider determines scope (service vs shared) and creates/updates secret.
|
|
24
|
+
*
|
|
25
|
+
* @param key Secret key
|
|
26
|
+
* @param value Secret value
|
|
27
|
+
* @param metadata Optional metadata tags/labels
|
|
28
|
+
*/
|
|
29
|
+
set(key: string, value: string, metadata?: Record<string, string>): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Remove secret from cloud
|
|
32
|
+
*
|
|
33
|
+
* @param key Secret key
|
|
34
|
+
*/
|
|
35
|
+
remove(key: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* List all secret keys managed by tsdevstack
|
|
38
|
+
*
|
|
39
|
+
* Filters by: managed-by=tsdevstack
|
|
40
|
+
*
|
|
41
|
+
* @returns Array of secret keys (without project/scope prefix)
|
|
42
|
+
*/
|
|
43
|
+
list(): Promise<string[]>;
|
|
44
|
+
/**
|
|
45
|
+
* Check if secret exists in cloud
|
|
46
|
+
*
|
|
47
|
+
* @param key Secret key
|
|
48
|
+
* @returns True if exists
|
|
49
|
+
*/
|
|
50
|
+
exists(key: string): Promise<boolean>;
|
|
51
|
+
/**
|
|
52
|
+
* Get provider name
|
|
53
|
+
*
|
|
54
|
+
* @returns 'gcp' | 'aws' | 'azure' | 'local'
|
|
55
|
+
*/
|
|
56
|
+
getProviderName(): string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Configuration for cloud providers
|
|
60
|
+
*/
|
|
61
|
+
export interface CloudProviderConfig {
|
|
62
|
+
/**
|
|
63
|
+
* Project name from .tsdevstack/config.json
|
|
64
|
+
* Used as prefix for all secrets
|
|
65
|
+
*/
|
|
66
|
+
projectName: string;
|
|
67
|
+
/**
|
|
68
|
+
* Service name (e.g., 'auth-service', 'bff-service')
|
|
69
|
+
* Used for service-scoped secrets
|
|
70
|
+
*/
|
|
71
|
+
serviceName: string;
|
|
72
|
+
/**
|
|
73
|
+
* Provider-specific configuration
|
|
74
|
+
* - GCP: { projectId, credentialsPath }
|
|
75
|
+
* - AWS: { region, credentialsPath }
|
|
76
|
+
* - Azure: { vaultUrl, credentialsPath }
|
|
77
|
+
*/
|
|
78
|
+
providerConfig?: Record<string, unknown>;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Cache entry for secret values
|
|
82
|
+
*/
|
|
83
|
+
export interface CacheEntry {
|
|
84
|
+
value: string;
|
|
85
|
+
expiresAt: number;
|
|
86
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { CloudSecretsProvider, CloudProviderConfig } from './cloud-provider.interface';
|
|
2
|
+
export declare class GCPSecretsProvider implements CloudSecretsProvider {
|
|
3
|
+
private readonly logger;
|
|
4
|
+
private client;
|
|
5
|
+
private projectName;
|
|
6
|
+
private serviceName;
|
|
7
|
+
private gcpProjectId;
|
|
8
|
+
private cache;
|
|
9
|
+
private readonly CACHE_TTL_MS;
|
|
10
|
+
constructor(config: CloudProviderConfig);
|
|
11
|
+
/**
|
|
12
|
+
* Get secret with service-scoped → shared fallback and caching
|
|
13
|
+
*/
|
|
14
|
+
get(key: string): Promise<string | null>;
|
|
15
|
+
/**
|
|
16
|
+
* Set a secret with optional metadata labels
|
|
17
|
+
*/
|
|
18
|
+
set(key: string, value: string, metadata?: Record<string, string>): Promise<void>;
|
|
19
|
+
/**
|
|
20
|
+
* Remove a secret
|
|
21
|
+
*/
|
|
22
|
+
remove(key: string): Promise<void>;
|
|
23
|
+
/**
|
|
24
|
+
* List all secrets for this service (both service-scoped and shared)
|
|
25
|
+
*/
|
|
26
|
+
list(): Promise<string[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Check if a secret exists (checks both service-scoped and shared)
|
|
29
|
+
*/
|
|
30
|
+
exists(key: string): Promise<boolean>;
|
|
31
|
+
getProviderName(): string;
|
|
32
|
+
/**
|
|
33
|
+
* Build secret name following convention: {projectName}-{scope}-{KEY}
|
|
34
|
+
*/
|
|
35
|
+
private buildSecretName;
|
|
36
|
+
/**
|
|
37
|
+
* Extract secret ID from full secret name
|
|
38
|
+
* Input: "tsdevstack-auth-service-DATABASE_URL"
|
|
39
|
+
* Output: "tsdevstack-auth-service-DATABASE_URL"
|
|
40
|
+
*/
|
|
41
|
+
private extractSecretId;
|
|
42
|
+
/**
|
|
43
|
+
* Extract key from secret ID
|
|
44
|
+
* Input: "tsdevstack-auth-service-DATABASE_URL"
|
|
45
|
+
* Output: "DATABASE_URL"
|
|
46
|
+
*/
|
|
47
|
+
private extractKeyFromSecretId;
|
|
48
|
+
/**
|
|
49
|
+
* Fetch secret value from GCP
|
|
50
|
+
*/
|
|
51
|
+
private fetchSecretFromGCP;
|
|
52
|
+
/**
|
|
53
|
+
* Build GCP labels from metadata
|
|
54
|
+
* GCP supports up to 64 labels per secret
|
|
55
|
+
*/
|
|
56
|
+
private buildLabels;
|
|
57
|
+
/**
|
|
58
|
+
* Cache management methods
|
|
59
|
+
*/
|
|
60
|
+
private getFromCache;
|
|
61
|
+
private setCache;
|
|
62
|
+
private isUrlValue;
|
|
63
|
+
private invalidateCache;
|
|
64
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { SecretsProvider } from "../secrets.interface";
|
|
2
|
+
/**
|
|
3
|
+
* Local Secrets Provider
|
|
4
|
+
*
|
|
5
|
+
* Reads secrets from .secrets.local.json file in the project root.
|
|
6
|
+
* Implements caching with 1-minute TTL for performance.
|
|
7
|
+
*
|
|
8
|
+
* File format:
|
|
9
|
+
* {
|
|
10
|
+
* "auth-service": {
|
|
11
|
+
* "DATABASE_URL": "postgresql://...",
|
|
12
|
+
* "AUTH_SECRET": "..."
|
|
13
|
+
* },
|
|
14
|
+
* "shared": {
|
|
15
|
+
* "API_KEY": "...",
|
|
16
|
+
* "REDIS_PASSWORD": "..."
|
|
17
|
+
* }
|
|
18
|
+
* }
|
|
19
|
+
*/
|
|
20
|
+
export declare class LocalSecretsProvider implements SecretsProvider {
|
|
21
|
+
private secrets;
|
|
22
|
+
private secretsFilePath;
|
|
23
|
+
private cache;
|
|
24
|
+
private serviceCache;
|
|
25
|
+
private readonly cacheTtl;
|
|
26
|
+
private serviceName?;
|
|
27
|
+
constructor(secretsFilePath?: string, cacheTtl?: number);
|
|
28
|
+
/**
|
|
29
|
+
* Set the service name for scoped secret access
|
|
30
|
+
* Used when getting secrets without specifying service name
|
|
31
|
+
*
|
|
32
|
+
* Also injects DATABASE_URL into process.env for Prisma
|
|
33
|
+
* (Prisma schema uses env("DATABASE_URL") before SecretsService is available)
|
|
34
|
+
*/
|
|
35
|
+
setServiceName(serviceName: string): void;
|
|
36
|
+
/**
|
|
37
|
+
* Find the project root by looking for .secrets.local.json
|
|
38
|
+
* Walks up the directory tree from current working directory
|
|
39
|
+
*/
|
|
40
|
+
private findProjectRoot;
|
|
41
|
+
/**
|
|
42
|
+
* Load and parse the secrets file
|
|
43
|
+
*/
|
|
44
|
+
private loadSecretsFile;
|
|
45
|
+
/**
|
|
46
|
+
* Get all secrets for a service
|
|
47
|
+
*
|
|
48
|
+
* All references are pre-resolved in .secrets.local.json, so we just load the values directly.
|
|
49
|
+
* No need to resolve "secrets" array - it doesn't exist in the final merged file.
|
|
50
|
+
*
|
|
51
|
+
* Note: All secrets are now flat (no nested objects like REDIS)
|
|
52
|
+
*/
|
|
53
|
+
getAll(serviceName: string): Promise<Record<string, string>>;
|
|
54
|
+
/**
|
|
55
|
+
* Get provider name
|
|
56
|
+
*/
|
|
57
|
+
getName(): string;
|
|
58
|
+
/**
|
|
59
|
+
* Get the path to the secrets file (for debugging)
|
|
60
|
+
*/
|
|
61
|
+
getSecretsFilePath(): string;
|
|
62
|
+
/**
|
|
63
|
+
* Get a single secret by key with caching
|
|
64
|
+
* Searches in current service's secrets or top-level secrets
|
|
65
|
+
*/
|
|
66
|
+
get(key: string): Promise<string>;
|
|
67
|
+
/**
|
|
68
|
+
* Set a secret value
|
|
69
|
+
* Updates .secrets.user.json and triggers regeneration
|
|
70
|
+
*/
|
|
71
|
+
set(key: string, value: string): Promise<void>;
|
|
72
|
+
/**
|
|
73
|
+
* Delete a secret
|
|
74
|
+
* Removes from .secrets.user.json and triggers regeneration
|
|
75
|
+
*/
|
|
76
|
+
delete(key: string): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Clear all cached secrets
|
|
79
|
+
* Forces next get() to reload from file
|
|
80
|
+
*/
|
|
81
|
+
clearCache(): void;
|
|
82
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { CloudSecretsProvider } from './cloud-provider.interface';
|
|
2
|
+
export type SecretsProviderType = 'local' | 'gcp' | 'aws' | 'azure';
|
|
3
|
+
/**
|
|
4
|
+
* Factory for creating cloud secrets providers
|
|
5
|
+
*
|
|
6
|
+
* IMPORTANT: This runtime factory ONLY reads environment variables.
|
|
7
|
+
* It does NOT read files or configs. All configuration must be set via env vars.
|
|
8
|
+
*
|
|
9
|
+
* Required environment variables:
|
|
10
|
+
* - SECRETS_PROVIDER: 'local' | 'gcp' | 'aws' | 'azure'
|
|
11
|
+
* - PROJECT_NAME: Your project name (required for cloud providers)
|
|
12
|
+
* - SERVICE_NAME: Set by bootstrap
|
|
13
|
+
*
|
|
14
|
+
* Provider-specific env vars:
|
|
15
|
+
* - GCP: GCP_PROJECT_ID, GOOGLE_APPLICATION_CREDENTIALS (or K_SERVICE on Cloud Run)
|
|
16
|
+
* - AWS: AWS_REGION (credentials from task role on ECS, or AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY)
|
|
17
|
+
* - Azure: AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, AZURE_TENANT_ID, AZURE_KEYVAULT_NAME
|
|
18
|
+
*
|
|
19
|
+
* The CLI (cloud:init, cloud-secrets:*) handles all file operations.
|
|
20
|
+
* Runtime just reads env vars and fails fast if missing.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SecretsProviderFactory {
|
|
23
|
+
/**
|
|
24
|
+
* Create a secrets provider based on environment variables ONLY
|
|
25
|
+
*/
|
|
26
|
+
static createProvider(serviceName: string): CloudSecretsProvider | null;
|
|
27
|
+
/**
|
|
28
|
+
* Get provider type from environment variable ONLY
|
|
29
|
+
*/
|
|
30
|
+
private static getProviderType;
|
|
31
|
+
/**
|
|
32
|
+
* Get project name from environment variable ONLY
|
|
33
|
+
*/
|
|
34
|
+
private static getProjectName;
|
|
35
|
+
/**
|
|
36
|
+
* Validate provider-specific environment variables
|
|
37
|
+
*/
|
|
38
|
+
private static validateProviderEnvVars;
|
|
39
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets Provider Interface
|
|
3
|
+
*
|
|
4
|
+
* All secret providers (local, AWS, GCP, Azure) must implement this interface.
|
|
5
|
+
*/
|
|
6
|
+
export interface SecretsProvider {
|
|
7
|
+
/**
|
|
8
|
+
* Get all secrets for a specific service
|
|
9
|
+
* @param serviceName - The name of the service (e.g., 'auth-service', 'shared')
|
|
10
|
+
* @returns Object containing all secrets for the service
|
|
11
|
+
*/
|
|
12
|
+
getAll(serviceName: string): Promise<Record<string, string>>;
|
|
13
|
+
/**
|
|
14
|
+
* Get a single secret by key
|
|
15
|
+
* Supports caching with TTL for performance
|
|
16
|
+
* @param key - The secret key to retrieve
|
|
17
|
+
* @returns The secret value
|
|
18
|
+
* @throws Error if secret not found
|
|
19
|
+
*/
|
|
20
|
+
get(key: string): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
* Set a secret value
|
|
23
|
+
* For local provider: Updates .secrets.user.json and triggers regeneration
|
|
24
|
+
* For cloud providers: Updates the secret in the cloud provider
|
|
25
|
+
* @param key - The secret key
|
|
26
|
+
* @param value - The secret value
|
|
27
|
+
*/
|
|
28
|
+
set(key: string, value: string): Promise<void>;
|
|
29
|
+
/**
|
|
30
|
+
* Delete a secret
|
|
31
|
+
* For local provider: Removes from .secrets.user.json and triggers regeneration
|
|
32
|
+
* For cloud providers: Deletes from the cloud provider
|
|
33
|
+
* @param key - The secret key to delete
|
|
34
|
+
*/
|
|
35
|
+
delete(key: string): Promise<void>;
|
|
36
|
+
/**
|
|
37
|
+
* Get the provider name (for logging/debugging)
|
|
38
|
+
*/
|
|
39
|
+
getName(): string;
|
|
40
|
+
/**
|
|
41
|
+
* Clear any cached secrets
|
|
42
|
+
* Forces next get() to reload from source
|
|
43
|
+
*/
|
|
44
|
+
clearCache(): void;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Cloud provider types supported by the framework
|
|
48
|
+
*/
|
|
49
|
+
export type CloudProvider = 'local' | 'aws' | 'gcp' | 'azure';
|
|
50
|
+
/**
|
|
51
|
+
* Secrets strategy types
|
|
52
|
+
*/
|
|
53
|
+
export type SecretsStrategy = 'local' | 'aws-secrets-manager' | 'gcp-secret-manager' | 'azure-key-vault';
|
|
54
|
+
/**
|
|
55
|
+
* Configuration for secrets service
|
|
56
|
+
*/
|
|
57
|
+
export interface SecretsConfig {
|
|
58
|
+
/**
|
|
59
|
+
* The service name (e.g., 'auth-service')
|
|
60
|
+
*/
|
|
61
|
+
serviceName: string;
|
|
62
|
+
/**
|
|
63
|
+
* Path to framework config file (for detecting cloud provider)
|
|
64
|
+
* @default '.tsdevstack/config.json'
|
|
65
|
+
*/
|
|
66
|
+
configPath?: string;
|
|
67
|
+
/**
|
|
68
|
+
* Force a specific provider (useful for testing)
|
|
69
|
+
* If not specified, provider is auto-detected
|
|
70
|
+
*/
|
|
71
|
+
forceProvider?: SecretsProvider;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Result of loading secrets
|
|
75
|
+
*/
|
|
76
|
+
export interface SecretsLoadResult {
|
|
77
|
+
/**
|
|
78
|
+
* Whether secrets were loaded successfully
|
|
79
|
+
*/
|
|
80
|
+
success: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* The provider that was used
|
|
83
|
+
*/
|
|
84
|
+
provider: string;
|
|
85
|
+
/**
|
|
86
|
+
* Number of secrets loaded
|
|
87
|
+
*/
|
|
88
|
+
count: number;
|
|
89
|
+
/**
|
|
90
|
+
* Error message if loading failed
|
|
91
|
+
*/
|
|
92
|
+
error?: string;
|
|
93
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secrets Module
|
|
3
|
+
*
|
|
4
|
+
* Global module that provides SecretsService for runtime secret access.
|
|
5
|
+
* Automatically available in all modules without importing.
|
|
6
|
+
*
|
|
7
|
+
* Usage in any service:
|
|
8
|
+
* ```typescript
|
|
9
|
+
* @Injectable()
|
|
10
|
+
* export class MyService {
|
|
11
|
+
* constructor(private secrets: SecretsService) {}
|
|
12
|
+
*
|
|
13
|
+
* async doSomething() {
|
|
14
|
+
* const apiKey = await this.secrets.get('API_KEY');
|
|
15
|
+
* // Cached for 1 minute, refreshes automatically
|
|
16
|
+
* }
|
|
17
|
+
* }
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* Note: This module must be imported in AppModule for dependency injection to work.
|
|
21
|
+
* The SecretsService is then available globally in all services.
|
|
22
|
+
*/
|
|
23
|
+
export declare class SecretsModule {
|
|
24
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { SecretsProvider } from './secrets.interface';
|
|
2
|
+
import type { SecretsConfig } from './secrets.interface';
|
|
3
|
+
/**
|
|
4
|
+
* Secrets Service
|
|
5
|
+
*
|
|
6
|
+
* Service for runtime secret access through provider abstraction.
|
|
7
|
+
* Detects provider based on SECRETS_PROVIDER environment variable.
|
|
8
|
+
*
|
|
9
|
+
* Usage pattern:
|
|
10
|
+
* ```typescript
|
|
11
|
+
* @Injectable()
|
|
12
|
+
* class MyService {
|
|
13
|
+
* constructor(private secrets: SecretsService) {}
|
|
14
|
+
*
|
|
15
|
+
* async doSomething() {
|
|
16
|
+
* const apiKey = await this.secrets.get('API_KEY');
|
|
17
|
+
* // Cached for 1 minute (local), 5 minutes (cloud)
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*
|
|
22
|
+
* IMPORTANT: Apps should NEVER use process.env to access secrets.
|
|
23
|
+
* Always inject SecretsService and use await this.secrets.get('KEY').
|
|
24
|
+
*
|
|
25
|
+
* Requires SECRETS_PROVIDER env var to be set to: local, aws, gcp, or azure
|
|
26
|
+
*/
|
|
27
|
+
export declare class SecretsService {
|
|
28
|
+
private provider;
|
|
29
|
+
private config;
|
|
30
|
+
constructor(config: SecretsConfig);
|
|
31
|
+
/**
|
|
32
|
+
* Get the current provider
|
|
33
|
+
*/
|
|
34
|
+
getProvider(): SecretsProvider;
|
|
35
|
+
/**
|
|
36
|
+
* Get a single secret by key with caching
|
|
37
|
+
* Supports runtime secret refresh (cached for 1 minute in local provider)
|
|
38
|
+
*
|
|
39
|
+
* @param key - The secret key to retrieve
|
|
40
|
+
* @returns The secret value
|
|
41
|
+
* @throws Error if secret not found
|
|
42
|
+
*/
|
|
43
|
+
get(key: string): Promise<string>;
|
|
44
|
+
/**
|
|
45
|
+
* Set a secret value
|
|
46
|
+
* For local provider: Updates .secrets.user.json and triggers regeneration
|
|
47
|
+
* For cloud providers: Updates the secret in the cloud provider
|
|
48
|
+
*
|
|
49
|
+
* @param key - The secret key
|
|
50
|
+
* @param value - The secret value
|
|
51
|
+
*/
|
|
52
|
+
set(key: string, value: string): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Delete a secret
|
|
55
|
+
* For local provider: Removes from .secrets.user.json and triggers regeneration
|
|
56
|
+
* For cloud providers: Deletes from the cloud provider
|
|
57
|
+
*
|
|
58
|
+
* @param key - The secret key to delete
|
|
59
|
+
*/
|
|
60
|
+
delete(key: string): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Clear any cached secrets
|
|
63
|
+
* Forces next get() to reload from source
|
|
64
|
+
*/
|
|
65
|
+
clearCache(): void;
|
|
66
|
+
/**
|
|
67
|
+
* Auto-detect which secrets provider to use based on SECRETS_PROVIDER env var
|
|
68
|
+
*/
|
|
69
|
+
private detectProvider;
|
|
70
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for initializing a service client.
|
|
4
|
+
*
|
|
5
|
+
* @template TApi - The generated API client type (e.g., Api from swagger-typescript-api)
|
|
6
|
+
*/
|
|
7
|
+
export interface ServiceClientConfig<TApi> {
|
|
8
|
+
/**
|
|
9
|
+
* The service base URL
|
|
10
|
+
*/
|
|
11
|
+
baseURL: string;
|
|
12
|
+
/**
|
|
13
|
+
* The service API key for authentication
|
|
14
|
+
*/
|
|
15
|
+
apiKey: string;
|
|
16
|
+
/**
|
|
17
|
+
* Factory function to create the API client instance
|
|
18
|
+
* @param baseURL - The service base URL
|
|
19
|
+
* @param apiKey - The service API key
|
|
20
|
+
* @returns Instance of the generated API client
|
|
21
|
+
*/
|
|
22
|
+
createClient: (baseURL: string, apiKey: string) => TApi;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Base class for service-to-service HTTP client wrappers.
|
|
26
|
+
*
|
|
27
|
+
* This class standardizes the pattern for initializing generated TypeScript API clients
|
|
28
|
+
* with proper authentication for service-to-service communication.
|
|
29
|
+
*
|
|
30
|
+
* ## Features
|
|
31
|
+
* - Automatic initialization during module init
|
|
32
|
+
* - API key injection for service-to-service authentication
|
|
33
|
+
* - Support for JWT forwarding via securityWorker (user context)
|
|
34
|
+
* - Standardized error handling and logging
|
|
35
|
+
* - Type-safe client access
|
|
36
|
+
*
|
|
37
|
+
* ## Usage
|
|
38
|
+
*
|
|
39
|
+
* @example Basic service client
|
|
40
|
+
* ```typescript
|
|
41
|
+
* import { Injectable, OnModuleInit } from '@nestjs/common';
|
|
42
|
+
* import { BaseServiceClient } from '@tsdevstack/nest-common';
|
|
43
|
+
* import { Api } from '@shared/auth-service-client';
|
|
44
|
+
* import { SecretsService } from '@tsdevstack/nest-common';
|
|
45
|
+
*
|
|
46
|
+
* @Injectable()
|
|
47
|
+
* export class AuthClientService extends BaseServiceClient<Api<{ token: string }>> implements OnModuleInit {
|
|
48
|
+
* constructor(private secrets: SecretsService) {
|
|
49
|
+
* super();
|
|
50
|
+
* }
|
|
51
|
+
*
|
|
52
|
+
* async onModuleInit(): Promise<void> {
|
|
53
|
+
* const baseURL = await this.secrets.get('AUTH_SERVICE_URL');
|
|
54
|
+
* const apiKey = await this.secrets.get('AUTH_SERVICE_API_KEY');
|
|
55
|
+
*
|
|
56
|
+
* this.initialize({
|
|
57
|
+
* baseURL,
|
|
58
|
+
* apiKey,
|
|
59
|
+
* createClient: (baseURL, apiKey) =>
|
|
60
|
+
* new Api({
|
|
61
|
+
* baseURL,
|
|
62
|
+
* headers: { 'x-api-key': apiKey },
|
|
63
|
+
* securityWorker: (securityData) =>
|
|
64
|
+
* securityData?.token
|
|
65
|
+
* ? { headers: { Authorization: `Bearer ${securityData.token}` } }
|
|
66
|
+
* : {},
|
|
67
|
+
* }),
|
|
68
|
+
* });
|
|
69
|
+
* }
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*
|
|
73
|
+
* @example Using the client in a controller
|
|
74
|
+
* ```typescript
|
|
75
|
+
* @Controller('users')
|
|
76
|
+
* export class UsersController {
|
|
77
|
+
* constructor(private authClient: AuthClientService) {}
|
|
78
|
+
*
|
|
79
|
+
* @Get('account')
|
|
80
|
+
* async getAccount(@Request() req: AuthenticatedRequest) {
|
|
81
|
+
* // Forward user JWT for user-specific requests
|
|
82
|
+
* const user = await this.authClient.client.v1.getUserAccount();
|
|
83
|
+
* return user.data;
|
|
84
|
+
* }
|
|
85
|
+
*
|
|
86
|
+
* @Get('internal')
|
|
87
|
+
* async internalOperation() {
|
|
88
|
+
* // Service-to-service call (uses API key automatically)
|
|
89
|
+
* const result = await this.authClient.client.v1.someInternalEndpoint();
|
|
90
|
+
* return result.data;
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* @template TApi - The generated API client type
|
|
96
|
+
*/
|
|
97
|
+
export declare abstract class BaseServiceClient<TApi> {
|
|
98
|
+
/**
|
|
99
|
+
* The initialized API client instance.
|
|
100
|
+
* Available after initialization.
|
|
101
|
+
*/
|
|
102
|
+
client: TApi;
|
|
103
|
+
protected readonly logger: Logger;
|
|
104
|
+
constructor();
|
|
105
|
+
/**
|
|
106
|
+
* Initializes the service client with the provided configuration.
|
|
107
|
+
* Should be called in the subclass's onModuleInit() method.
|
|
108
|
+
*
|
|
109
|
+
* @param config - Configuration containing baseURL, apiKey, and client factory
|
|
110
|
+
* @throws Error if configuration is invalid
|
|
111
|
+
*/
|
|
112
|
+
protected initialize(config: ServiceClientConfig<TApi>): void;
|
|
113
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from 'node:http';
|
|
2
|
+
/**
|
|
3
|
+
* Filters request headers for forwarding in service-to-service calls.
|
|
4
|
+
*
|
|
5
|
+
* Use this when making internal service calls to forward authentication
|
|
6
|
+
* and context headers while excluding headers that would break routing.
|
|
7
|
+
*
|
|
8
|
+
* @param headers - The incoming request headers (from Express/NestJS request object)
|
|
9
|
+
* @returns Filtered headers safe to forward to internal services
|
|
10
|
+
*/
|
|
11
|
+
export declare function filterForwardHeaders(headers: IncomingHttpHeaders): Record<string, string>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|