@goatlab/node-backend 0.2.5 → 0.4.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.
Files changed (44) hide show
  1. package/README.md +146 -14
  2. package/dist/container/Container.d.ts +113 -25
  3. package/dist/container/Container.js +391 -168
  4. package/dist/container/Container.js.map +1 -1
  5. package/dist/container/examples/batch-operations.example.d.ts +1 -0
  6. package/dist/container/examples/batch-operations.example.js +165 -0
  7. package/dist/container/examples/batch-operations.example.js.map +1 -0
  8. package/dist/container/helpers.d.ts +8 -0
  9. package/dist/container/helpers.js +22 -0
  10. package/dist/container/helpers.js.map +1 -1
  11. package/dist/container/types.d.ts +60 -0
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/server/bootstraps/getExpressTrpcApp.d.ts +5 -1
  15. package/dist/server/bootstraps/getExpressTrpcApp.js +216 -12
  16. package/dist/server/bootstraps/getExpressTrpcApp.js.map +1 -1
  17. package/dist/server/middleware/memoryMonitor.example.d.ts +1 -0
  18. package/dist/server/middleware/memoryMonitor.example.js +109 -0
  19. package/dist/server/middleware/memoryMonitor.example.js.map +1 -0
  20. package/dist/server/middleware/memoryMonitor.middleware.d.ts +42 -0
  21. package/dist/server/middleware/memoryMonitor.middleware.js +134 -0
  22. package/dist/server/middleware/memoryMonitor.middleware.js.map +1 -0
  23. package/dist/server/middleware/productionError.middleware.d.ts +16 -0
  24. package/dist/server/middleware/productionError.middleware.js +94 -0
  25. package/dist/server/middleware/productionError.middleware.js.map +1 -0
  26. package/dist/server/middleware/security.middleware.d.ts +28 -0
  27. package/dist/server/middleware/security.middleware.js +151 -0
  28. package/dist/server/middleware/security.middleware.js.map +1 -0
  29. package/dist/server/services/secrets/examples/container-preload.example.d.ts +1 -0
  30. package/dist/server/services/secrets/examples/container-preload.example.js +148 -0
  31. package/dist/server/services/secrets/examples/container-preload.example.js.map +1 -0
  32. package/dist/server/services/secrets/index.d.ts +1 -0
  33. package/dist/server/services/secrets/index.js +6 -0
  34. package/dist/server/services/secrets/index.js.map +1 -0
  35. package/dist/server/services/secrets/secret.service.d.ts +48 -6
  36. package/dist/server/services/secrets/secret.service.js +280 -28
  37. package/dist/server/services/secrets/secret.service.js.map +1 -1
  38. package/dist/server/services/translations/translation.model.js +2 -1
  39. package/dist/server/services/translations/translation.model.js.map +1 -1
  40. package/dist/server/services/translations/translation.service.d.ts +8 -1
  41. package/dist/server/services/translations/translation.service.js +123 -13
  42. package/dist/server/services/translations/translation.service.js.map +1 -1
  43. package/dist/tsconfig.tsbuildinfo +1 -1
  44. package/package.json +13 -1
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sanitizeErrorForProduction = sanitizeErrorForProduction;
4
+ exports.productionErrorHandler = productionErrorHandler;
5
+ exports.asyncErrorHandler = asyncErrorHandler;
6
+ const js_utils_1 = require("@goatlab/js-utils");
7
+ /**
8
+ * Sanitize error messages for production environment
9
+ * Prevents leaking sensitive information in error responses
10
+ */
11
+ function sanitizeErrorForProduction(error) {
12
+ const isProduction = process.env.NODE_ENV === 'prod';
13
+ if (!isProduction) {
14
+ return error; // In development, return full error details
15
+ }
16
+ // Clone the error to avoid mutating the original
17
+ const sanitizedError = { ...error };
18
+ // For 5xx errors, hide internal details
19
+ if (error.data?.httpStatusCode && error.data.httpStatusCode >= 500) {
20
+ sanitizedError.message = 'Internal Server Error';
21
+ sanitizedError.stack = undefined;
22
+ // Keep only safe data
23
+ sanitizedError.data = {
24
+ httpStatusCode: error.data.httpStatusCode,
25
+ errorId: error.data.errorId,
26
+ timestamp: new Date().toISOString()
27
+ };
28
+ }
29
+ else if (error.data?.httpStatusCode && error.data.httpStatusCode >= 400) {
30
+ // For 4xx errors, keep the message but remove stack traces
31
+ sanitizedError.stack = undefined;
32
+ // Remove any potentially sensitive data
33
+ if (sanitizedError.data) {
34
+ const { httpStatusCode, errorId, message, code } = sanitizedError.data;
35
+ sanitizedError.data = {
36
+ httpStatusCode,
37
+ errorId,
38
+ message: message || sanitizedError.message,
39
+ code,
40
+ timestamp: new Date().toISOString()
41
+ };
42
+ }
43
+ }
44
+ return sanitizedError;
45
+ }
46
+ /**
47
+ * Production-ready error handler middleware
48
+ * Ensures no sensitive information is leaked in error responses
49
+ */
50
+ function productionErrorHandler() {
51
+ return (err, req, res, next) => {
52
+ // If headers are already sent, delegate to default Express error handler
53
+ if (res.headersSent) {
54
+ return next(err);
55
+ }
56
+ // Convert to error object
57
+ const error = js_utils_1.Errors.anyToError(err);
58
+ const httpError = error;
59
+ // Sanitize the error for production
60
+ const sanitizedError = sanitizeErrorForProduction(httpError);
61
+ // Set default status code if not provided
62
+ const statusCode = sanitizedError.data?.httpStatusCode || 500;
63
+ // Log the original error (for debugging)
64
+ if (statusCode >= 500) {
65
+ console.error('Server error:', {
66
+ error: err,
67
+ request: {
68
+ method: req.method,
69
+ url: req.originalUrl,
70
+ ip: req.ip,
71
+ userAgent: req.get('user-agent')
72
+ }
73
+ });
74
+ }
75
+ // Send sanitized response
76
+ res.status(statusCode).json({
77
+ error: {
78
+ message: sanitizedError.message,
79
+ code: sanitizedError.data?.code,
80
+ errorId: sanitizedError.data?.errorId,
81
+ timestamp: sanitizedError.data?.timestamp || new Date().toISOString()
82
+ }
83
+ });
84
+ };
85
+ }
86
+ /**
87
+ * Async error wrapper to catch errors in async route handlers
88
+ */
89
+ function asyncErrorHandler(fn) {
90
+ return (req, res, next) => {
91
+ Promise.resolve(fn(req, res, next)).catch(next);
92
+ };
93
+ }
94
+ //# sourceMappingURL=productionError.middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"productionError.middleware.js","sourceRoot":"","sources":["../../../src/server/middleware/productionError.middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { CorsOptions } from 'cors';
2
+ import type { HelmetOptions } from 'helmet';
3
+ import type { RateLimitRequestHandler } from 'express-rate-limit';
4
+ import rateLimit from 'express-rate-limit';
5
+ /**
6
+ * Get CORS configuration based on environment
7
+ */
8
+ export declare function getCorsOptions(): CorsOptions;
9
+ /**
10
+ * Get Helmet configuration for enhanced security headers
11
+ */
12
+ export declare function getHelmetOptions(): HelmetOptions;
13
+ /**
14
+ * Create rate limiter with default configuration
15
+ */
16
+ export declare function createRateLimiter(options?: Partial<Parameters<typeof rateLimit>[0]>): RateLimitRequestHandler;
17
+ /**
18
+ * Create stricter rate limiter for authentication endpoints
19
+ */
20
+ export declare function createAuthRateLimiter(): RateLimitRequestHandler;
21
+ /**
22
+ * Create rate limiter for API endpoints
23
+ */
24
+ export declare function createApiRateLimiter(): RateLimitRequestHandler;
25
+ /**
26
+ * Additional security headers not covered by Helmet
27
+ */
28
+ export declare function additionalSecurityHeaders(): (req: any, res: any, next: any) => void;
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCorsOptions = getCorsOptions;
4
+ exports.getHelmetOptions = getHelmetOptions;
5
+ exports.createRateLimiter = createRateLimiter;
6
+ exports.createAuthRateLimiter = createAuthRateLimiter;
7
+ exports.createApiRateLimiter = createApiRateLimiter;
8
+ exports.additionalSecurityHeaders = additionalSecurityHeaders;
9
+ const express_rate_limit_1 = require("express-rate-limit");
10
+ /**
11
+ * Get CORS configuration based on environment
12
+ */
13
+ function getCorsOptions() {
14
+ const allowedOrigins = process.env.ALLOWED_ORIGINS?.split(',').map(origin => origin.trim()) || [];
15
+ // In development, allow localhost origins
16
+ if (process.env.NODE_ENV !== 'prod' && allowedOrigins.length === 0) {
17
+ allowedOrigins.push('http://localhost:3000', 'http://localhost:3001', 'http://localhost:5173');
18
+ }
19
+ return {
20
+ origin: (origin, callback) => {
21
+ // Allow requests with no origin (like mobile apps or Postman)
22
+ if (!origin && process.env.NODE_ENV !== 'prod') {
23
+ return callback(null, true);
24
+ }
25
+ if (!origin || allowedOrigins.includes(origin)) {
26
+ callback(null, true);
27
+ }
28
+ else {
29
+ callback(new Error('Not allowed by CORS'));
30
+ }
31
+ },
32
+ credentials: true,
33
+ methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
34
+ allowedHeaders: ['Content-Type', 'Authorization', 'X-Request-ID'],
35
+ exposedHeaders: [
36
+ 'X-Request-ID',
37
+ 'X-RateLimit-Limit',
38
+ 'X-RateLimit-Remaining',
39
+ 'X-RateLimit-Reset'
40
+ ],
41
+ maxAge: 86400, // 24 hours
42
+ optionsSuccessStatus: 200 // Some legacy browsers choke on 204
43
+ };
44
+ }
45
+ /**
46
+ * Get Helmet configuration for enhanced security headers
47
+ */
48
+ function getHelmetOptions() {
49
+ const isDevelopment = process.env.NODE_ENV !== 'prod';
50
+ return {
51
+ contentSecurityPolicy: isDevelopment
52
+ ? false
53
+ : {
54
+ directives: {
55
+ defaultSrc: ["'self'"],
56
+ scriptSrc: ["'self'", "'unsafe-inline'"], // Consider removing unsafe-inline in production
57
+ styleSrc: ["'self'", "'unsafe-inline'"],
58
+ imgSrc: ["'self'", 'data:', 'https:'],
59
+ connectSrc: ["'self'"],
60
+ fontSrc: ["'self'"],
61
+ objectSrc: ["'none'"],
62
+ mediaSrc: ["'self'"],
63
+ frameSrc: ["'none'"],
64
+ baseUri: ["'self'"],
65
+ formAction: ["'self'"],
66
+ frameAncestors: ["'none'"],
67
+ upgradeInsecureRequests: []
68
+ }
69
+ },
70
+ hsts: {
71
+ maxAge: 31536000, // 1 year
72
+ includeSubDomains: true,
73
+ preload: true
74
+ },
75
+ noSniff: true,
76
+ xssFilter: true,
77
+ referrerPolicy: { policy: 'strict-origin-when-cross-origin' },
78
+ permittedCrossDomainPolicies: false,
79
+ hidePoweredBy: true,
80
+ ieNoOpen: true,
81
+ frameguard: { action: 'deny' }
82
+ };
83
+ }
84
+ /**
85
+ * Create rate limiter with default configuration
86
+ */
87
+ function createRateLimiter(options) {
88
+ return (0, express_rate_limit_1.default)({
89
+ windowMs: 15 * 60 * 1000, // 15 minutes
90
+ max: 100, // Limit each IP to 100 requests per windowMs
91
+ message: 'Too many requests from this IP, please try again later.',
92
+ standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
93
+ legacyHeaders: false, // Disable the `X-RateLimit-*` headers
94
+ skipSuccessfulRequests: false,
95
+ // Skip rate limiting validation errors in test environment
96
+ validate: process.env.NODE_ENV === 'test' ? false : undefined,
97
+ handler: (_req, res) => {
98
+ res.status(429).json({
99
+ error: {
100
+ code: 'RATE_LIMIT_EXCEEDED',
101
+ message: 'Too many requests, please try again later.',
102
+ retryAfter: res.getHeader('Retry-After')
103
+ }
104
+ });
105
+ },
106
+ ...options
107
+ });
108
+ }
109
+ /**
110
+ * Create stricter rate limiter for authentication endpoints
111
+ */
112
+ function createAuthRateLimiter() {
113
+ return createRateLimiter({
114
+ windowMs: 15 * 60 * 1000, // 15 minutes
115
+ max: 5, // Limit each IP to 5 requests per windowMs
116
+ skipSuccessfulRequests: true, // Don't count successful requests
117
+ message: 'Too many authentication attempts, please try again later.'
118
+ });
119
+ }
120
+ /**
121
+ * Create rate limiter for API endpoints
122
+ */
123
+ function createApiRateLimiter() {
124
+ const maxRequests = process.env.API_RATE_LIMIT
125
+ ? parseInt(process.env.API_RATE_LIMIT, 10)
126
+ : 100;
127
+ return createRateLimiter({
128
+ windowMs: 15 * 60 * 1000, // 15 minutes
129
+ max: maxRequests,
130
+ message: 'API rate limit exceeded, please try again later.'
131
+ });
132
+ }
133
+ /**
134
+ * Additional security headers not covered by Helmet
135
+ */
136
+ function additionalSecurityHeaders() {
137
+ return (req, res, next) => {
138
+ // Permissions Policy (formerly Feature Policy)
139
+ res.setHeader('Permissions-Policy', 'geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), accelerometer=()');
140
+ // Additional security headers
141
+ res.setHeader('X-Content-Type-Options', 'nosniff');
142
+ res.setHeader('X-Frame-Options', 'DENY');
143
+ res.setHeader('X-XSS-Protection', '1; mode=block');
144
+ // Clear site data on logout (if logout endpoint)
145
+ if (req.path === '/logout' || req.path === '/api/logout') {
146
+ res.setHeader('Clear-Site-Data', '"cache", "cookies", "storage"');
147
+ }
148
+ next();
149
+ };
150
+ }
151
+ //# sourceMappingURL=security.middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.middleware.js","sourceRoot":"","sources":["../../../src/server/middleware/security.middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ // Example: Using SecretService with preloading in Container
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const Container_1 = require("../../../../container/Container");
5
+ const secret_service_1 = require("../secret.service");
6
+ // Define your service factories (mock for example)
7
+ const factories = {
8
+ secrets: (secret_service_1.SecretService),
9
+ database: class MockDatabaseService {
10
+ tenantId;
11
+ config;
12
+ constructor(tenantId, config) {
13
+ this.tenantId = tenantId;
14
+ this.config = config;
15
+ }
16
+ async connect() { console.log('Connected to DB'); }
17
+ async query(sql) { return []; }
18
+ },
19
+ api: class MockApiService {
20
+ tenantId;
21
+ config;
22
+ constructor(tenantId, config) {
23
+ this.tenantId = tenantId;
24
+ this.config = config;
25
+ }
26
+ async getUser(userId, apiKey) { return { id: userId }; }
27
+ async processData(apiKey) { return { processed: true }; }
28
+ }
29
+ };
30
+ // Create container with preloading pattern
31
+ const container = new Container_1.Container(factories, async (preload, meta) => {
32
+ // Create secret service instance
33
+ const secretService = preload.secrets(meta.tenantId, {
34
+ provider: 'FILE', // or 'VAULT', 'ENV'
35
+ location: meta.secretsLocation,
36
+ encryptionKey: meta.encryptionKey,
37
+ vaultConfig: meta.vaultConfig
38
+ });
39
+ // Preload secrets before using them
40
+ await secretService.preload();
41
+ // Now we can use synchronous methods to get secrets
42
+ const dbConnectionString = secretService.getSecretSync('DB_CONNECTION_STRING');
43
+ const jwtSecret = secretService.getSecretSync('JWT_SECRET');
44
+ // Create other services using the preloaded secrets
45
+ const database = preload.database(meta.tenantId, meta.tenantId, {
46
+ connectionString: dbConnectionString
47
+ });
48
+ const api = preload.api(meta.tenantId, meta.tenantId, {
49
+ database,
50
+ jwtSecret
51
+ });
52
+ return {
53
+ secrets: secretService,
54
+ database,
55
+ api
56
+ };
57
+ });
58
+ // Usage example
59
+ async function processRequest(tenantMeta, userId) {
60
+ await container.bootstrap(tenantMeta, async () => {
61
+ const { api, secrets } = container.context;
62
+ // Secrets are already preloaded, so we can use sync methods
63
+ const apiKey = secrets.getSecretSync('API_KEY');
64
+ // Use services
65
+ const user = await api.getUser(userId, apiKey);
66
+ return user;
67
+ });
68
+ }
69
+ // Example with multiple providers
70
+ async function multiProviderExample() {
71
+ // FILE provider for development
72
+ const devTenant = {
73
+ tenantId: 'dev-tenant',
74
+ secretsLocation: '/secrets/dev.json',
75
+ encryptionKey: 'dev-encryption-key-32chars'
76
+ };
77
+ // VAULT provider for production
78
+ const prodTenant = {
79
+ tenantId: 'prod-tenant',
80
+ secretsLocation: 'production/secrets',
81
+ encryptionKey: 'prod-encryption-key-32chars',
82
+ vaultConfig: {
83
+ endpoint: 'https://vault.company.com',
84
+ token: process.env.VAULT_TOKEN
85
+ }
86
+ };
87
+ // ENV provider for CI/CD
88
+ const ciTenant = {
89
+ tenantId: 'ci-tenant',
90
+ secretsLocation: 'CI', // Will look for CI_API_KEY, CI_DB_CONNECTION_STRING, etc.
91
+ encryptionKey: 'ci-encryption-key-32chars'
92
+ };
93
+ }
94
+ // Example with automatic invalidation (FILE provider)
95
+ async function fileWatchingExample() {
96
+ const container = new Container_1.Container(factories, async (preload, meta) => {
97
+ const secretService = preload.secrets(meta.tenantId, {
98
+ provider: 'FILE',
99
+ location: meta.secretsLocation,
100
+ encryptionKey: meta.encryptionKey,
101
+ cacheTTL: 60000 // 1 minute cache
102
+ });
103
+ // Enable automatic reload on file changes
104
+ await secretService.preload();
105
+ // Secrets will automatically reload if the file changes
106
+ return { secrets: secretService };
107
+ });
108
+ // The secret service will watch for file changes and reload automatically
109
+ }
110
+ // Example with batch operations
111
+ async function batchTenantProcessing() {
112
+ const tenants = [
113
+ { tenantId: 'tenant1', secretsLocation: '/secrets/tenant1.json', encryptionKey: 'key1' },
114
+ { tenantId: 'tenant2', secretsLocation: '/secrets/tenant2.json', encryptionKey: 'key2' },
115
+ { tenantId: 'tenant3', secretsLocation: '/secrets/tenant3.json', encryptionKey: 'key3' }
116
+ ];
117
+ const results = await container.bootstrapBatch(tenants.map(meta => ({
118
+ metadata: meta,
119
+ fn: async () => {
120
+ const { secrets, api } = container.context;
121
+ // Each tenant has its own preloaded secrets
122
+ const apiKey = secrets.getSecretSync('API_KEY');
123
+ // Process tenant data
124
+ return api.processData(apiKey);
125
+ }
126
+ })), {
127
+ concurrency: 5,
128
+ continueOnError: true,
129
+ onProgress: (completed, total) => {
130
+ console.log(`Processed ${completed}/${total} tenants`);
131
+ }
132
+ });
133
+ // Check results
134
+ for (const result of results) {
135
+ if (result.status === 'success') {
136
+ console.log(`Tenant ${result.metadata.tenantId} processed successfully`);
137
+ }
138
+ else {
139
+ console.error(`Tenant ${result.metadata.tenantId} failed:`, result.error);
140
+ }
141
+ }
142
+ }
143
+ // Cleanup when done
144
+ async function cleanup() {
145
+ // Dispose all services (including secret watchers)
146
+ await container.disposeAll();
147
+ }
148
+ //# sourceMappingURL=container-preload.example.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"container-preload.example.js","sourceRoot":"","sources":["../../../../../src/server/services/secrets/examples/container-preload.example.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export { SecretService, SecretServiceConfig, SecretProvider, VaultConfig } from './secret.service';
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SecretService = void 0;
4
+ var secret_service_1 = require("./secret.service");
5
+ Object.defineProperty(exports, "SecretService", { enumerable: true, get: function () { return secret_service_1.SecretService; } });
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/server/services/secrets/index.ts"],"names":[],"mappings":";;;AAAA,mDAAkG;AAAzF,+GAAA,aAAa,OAAA"}
@@ -5,17 +5,44 @@ export interface VaultConfig {
5
5
  mount?: string;
6
6
  namespace?: string;
7
7
  }
8
+ export interface SecretServiceConfig {
9
+ provider: SecretProvider;
10
+ location: string;
11
+ encryptionKey: string;
12
+ vaultConfig?: VaultConfig;
13
+ cacheTTL?: number;
14
+ }
8
15
  export declare class SecretService<SecretType> {
9
16
  provider: SecretProvider;
10
17
  location: string;
11
18
  encryptionKey: string;
12
19
  vaultConfig?: VaultConfig;
13
- constructor({ provider, location, encryptionKey, vaultConfig }: {
14
- provider: SecretProvider;
15
- location: string;
16
- encryptionKey: string;
17
- vaultConfig?: VaultConfig;
18
- });
20
+ cacheTTL: number;
21
+ protected preloadedSecrets?: SecretType;
22
+ protected isPreloaded: boolean;
23
+ private fileWatcher?;
24
+ constructor(config: SecretServiceConfig);
25
+ /**
26
+ * Preload secrets asynchronously for synchronous access later
27
+ * This method loads secrets once and stores them in the instance
28
+ */
29
+ preload(): Promise<void>;
30
+ /**
31
+ * Invalidate preloaded secrets and stop file watching
32
+ */
33
+ invalidate(): Promise<void>;
34
+ /**
35
+ * Set up file watching for automatic invalidation
36
+ */
37
+ private setupFileWatcher;
38
+ /**
39
+ * Load secrets asynchronously with decryption for all providers
40
+ */
41
+ private loadSecretsAsync;
42
+ private isCacheValid;
43
+ private setCache;
44
+ private getCache;
45
+ loadSecretsFromFileAsync(): Promise<SecretType>;
19
46
  loadSecretsFromFile(): SecretType;
20
47
  loadSecretsFromGCP(): SecretType;
21
48
  loadEncryptionKeyFromGCP(): string;
@@ -24,9 +51,24 @@ export declare class SecretService<SecretType> {
24
51
  storeSecretsToVault(secrets: Partial<SecretType>): Promise<void>;
25
52
  loadSecrets(): SecretType | Promise<SecretType>;
26
53
  loadEncryptionKey(): string;
54
+ getSecretAsync(secretName: keyof SecretType): Promise<string>;
55
+ getSecretJsonAsync<T = any>(secretName: keyof SecretType): Promise<T>;
27
56
  getSecret(secretName: keyof SecretType): Promise<string>;
28
57
  getSecretJson<T = any>(secretName: keyof SecretType): Promise<T>;
58
+ /**
59
+ * Get a secret synchronously (requires preload() to be called first)
60
+ */
29
61
  getSecretSync(secretName: keyof SecretType): string;
62
+ /**
63
+ * Get a JSON secret synchronously (requires preload() to be called first)
64
+ */
30
65
  getSecretJsonSync<T = any>(secretName: keyof SecretType): T;
66
+ getSecretSyncLegacy(secretName: keyof SecretType): string;
67
+ getSecretJsonSyncLegacy<T = any>(secretName: keyof SecretType): T;
31
68
  static clearCache(): void;
69
+ static cleanupExpiredCache(): void;
70
+ /**
71
+ * Clean up resources (file watchers, etc.) when service is no longer needed
72
+ */
73
+ dispose(): void;
32
74
  }