@aifabrix/miso-client 4.0.0 → 4.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/CHANGELOG.md +73 -6
- package/dist/api/types/encryption.types.d.ts +4 -0
- package/dist/api/types/encryption.types.d.ts.map +1 -1
- package/dist/express/client-token-endpoint.d.ts +0 -12
- package/dist/express/client-token-endpoint.d.ts.map +1 -1
- package/dist/express/client-token-endpoint.js +97 -218
- package/dist/express/client-token-endpoint.js.map +1 -1
- package/dist/express/error-handler.d.ts +1 -4
- package/dist/express/error-handler.d.ts.map +1 -1
- package/dist/express/error-handler.js +39 -84
- package/dist/express/error-handler.js.map +1 -1
- package/dist/express/error-response.d.ts.map +1 -1
- package/dist/express/error-response.js +2 -0
- package/dist/express/error-response.js.map +1 -1
- package/dist/express/error-types.d.ts +1 -3
- package/dist/express/error-types.d.ts.map +1 -1
- package/dist/express/error-types.js +17 -37
- package/dist/express/error-types.js.map +1 -1
- package/dist/express/logger-context.middleware.d.ts +7 -21
- package/dist/express/logger-context.middleware.d.ts.map +1 -1
- package/dist/express/logger-context.middleware.js +25 -62
- package/dist/express/logger-context.middleware.js.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/services/auth.service.d.ts +18 -20
- package/dist/services/auth.service.d.ts.map +1 -1
- package/dist/services/auth.service.js +63 -38
- package/dist/services/auth.service.js.map +1 -1
- package/dist/services/encryption.service.d.ts +15 -3
- package/dist/services/encryption.service.d.ts.map +1 -1
- package/dist/services/encryption.service.js +22 -3
- package/dist/services/encryption.service.js.map +1 -1
- package/dist/services/permission.service.d.ts +8 -1
- package/dist/services/permission.service.d.ts.map +1 -1
- package/dist/services/permission.service.js +49 -60
- package/dist/services/permission.service.js.map +1 -1
- package/dist/services/role.service.d.ts +8 -1
- package/dist/services/role.service.d.ts.map +1 -1
- package/dist/services/role.service.js +44 -47
- package/dist/services/role.service.js.map +1 -1
- package/dist/types/config.types.d.ts +2 -0
- package/dist/types/config.types.d.ts.map +1 -1
- package/dist/types/config.types.js.map +1 -1
- package/dist/utils/config-loader.d.ts.map +1 -1
- package/dist/utils/config-loader.js +79 -94
- package/dist/utils/config-loader.js.map +1 -1
- package/dist/utils/data-client.d.ts +6 -0
- package/dist/utils/data-client.d.ts.map +1 -1
- package/dist/utils/data-client.js +40 -39
- package/dist/utils/data-client.js.map +1 -1
- package/dist/utils/encryption-error.d.ts +5 -5
- package/dist/utils/encryption-error.d.ts.map +1 -1
- package/dist/utils/encryption-error.js +2 -2
- package/dist/utils/encryption-error.js.map +1 -1
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +39 -60
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/http-client.d.ts +47 -2
- package/dist/utils/http-client.d.ts.map +1 -1
- package/dist/utils/http-client.js +47 -7
- package/dist/utils/http-client.js.map +1 -1
- package/dist/utils/internal-http-client.d.ts +54 -2
- package/dist/utils/internal-http-client.d.ts.map +1 -1
- package/dist/utils/internal-http-client.js +93 -76
- package/dist/utils/internal-http-client.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,12 +5,71 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [4.2.0] - 2026-01-26
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **User Info Caching** - Added caching for `getUserInfo()` to reduce redundant controller API calls
|
|
13
|
+
- Cache key format: `user:{userId}` with configurable TTL (default 300 seconds / 5 minutes)
|
|
14
|
+
- Automatically extracts userId from JWT token for cache key generation
|
|
15
|
+
- Falls back to controller when cache miss or Redis unavailable
|
|
16
|
+
- New `clearUserCache(token)` method to invalidate cached user info
|
|
17
|
+
- `logout()` now clears user cache in addition to token cache
|
|
18
|
+
- New `userTTL` configuration option in `cache` settings
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
|
|
22
|
+
- **RFC 7807 Compliance** - Improved error responses in `client-token-endpoint.ts`
|
|
23
|
+
- All 11 error responses now use RFC 7807 Problem Details format
|
|
24
|
+
- Added 504 Gateway Timeout to error type mappings
|
|
25
|
+
- Error responses include `type`, `title`, `status`, `detail`, and `instance` fields
|
|
26
|
+
|
|
27
|
+
### Technical
|
|
28
|
+
|
|
29
|
+
- **Code Quality Refactoring** - Refactored 13 methods across 11 files to comply with 30-line method limit
|
|
30
|
+
- `auth.service.ts`: Extracted `extractTokenFromEnvResponse()` helper
|
|
31
|
+
- `internal-http-client.ts`: Extracted `createHttpAgent()`, `extractTokenFromResponse()`, `formatTokenFetchError()`
|
|
32
|
+
- `client-token-endpoint.ts`: Extracted `extractHttpStatus()`, `isNetworkOrTimeoutError()`, `handleTokenError()`, `buildConfigResponse()`
|
|
33
|
+
- `role.service.ts`: Extracted `buildAuthStrategy()`, `getEnvironmentParams()`, `resolveUserId()`, `fetchRolesFromController()`
|
|
34
|
+
- `permission.service.ts`: Similar helper extraction pattern
|
|
35
|
+
- `config-loader.ts`: Extracted `loadRedisConfig()`, `loadAuthStrategy()`, `loadKeycloakConfig()`, `loadAllowedOrigins()`
|
|
36
|
+
- `errors.ts`: Extracted `transformErrorEnvelope()`, `transformDirectError()`
|
|
37
|
+
- `error-handler.ts`: Added lookup tables `PRISMA_ERROR_MAP`, `MESSAGE_PATTERN_MAP`, extracted `logError()`
|
|
38
|
+
- `error-types.ts`: Extracted `ERROR_TYPE_MAP`, `ERROR_TITLE_MAP` lookup tables
|
|
39
|
+
- `data-client.ts`: Extracted `checkCircuitBreaker()`, `recordFailure()`, `executeRequest()`
|
|
40
|
+
- `logger-context.middleware.ts`: Extracted `buildLoggerContext()`
|
|
41
|
+
- File size reduction in `auth.service.ts` from 515 to 500 lines via JSDoc consolidation
|
|
42
|
+
|
|
43
|
+
## [4.1.0] - 2026-01-21
|
|
44
|
+
|
|
45
|
+
### Changed
|
|
46
|
+
|
|
47
|
+
- **Encryption Key Parameter** - `encryptionKey` is now sent to the controller for server-side validation
|
|
48
|
+
- Added `encryptionKey` field to `EncryptRequest` and `DecryptRequest` interfaces
|
|
49
|
+
- `EncryptionService` validates encryption key is configured before API calls
|
|
50
|
+
- Throws `ENCRYPTION_KEY_REQUIRED` error with helpful message if key is missing
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- `ENCRYPTION_KEY_REQUIRED` error code in `EncryptionError` class
|
|
55
|
+
- Tests for encryption key validation in `EncryptionService`
|
|
56
|
+
- Tests for `MISO_ENCRYPTION_KEY` environment variable loading in `config-loader`
|
|
57
|
+
|
|
58
|
+
### Technical
|
|
59
|
+
|
|
60
|
+
- `EncryptionError.parameterName` is now optional (not applicable for `ENCRYPTION_KEY_REQUIRED` errors)
|
|
61
|
+
- `EncryptionService` constructor accepts optional `encryptionKey` parameter
|
|
62
|
+
- `MisoClient` passes `config.encryptionKey` to `EncryptionService`
|
|
63
|
+
|
|
8
64
|
## [4.0.0] - 2026-01-20
|
|
9
65
|
|
|
10
66
|
### Breaking Changes
|
|
11
67
|
|
|
12
68
|
- **Removed `EncryptionUtil` class** - Local encryption via `EncryptionUtil.encrypt()`/`decrypt()` is no longer supported. Use the new controller-based `client.encryption` service instead.
|
|
13
|
-
- **
|
|
69
|
+
- **Encryption Key Required** - The `encryptionKey` config option is now required for encryption operations
|
|
70
|
+
- Load from `MISO_ENCRYPTION_KEY` environment variable
|
|
71
|
+
- Or provide `encryptionKey` in `MisoClientConfig`
|
|
72
|
+
- Throws `ENCRYPTION_KEY_REQUIRED` error if not configured when using encrypt/decrypt
|
|
14
73
|
|
|
15
74
|
### Migration Guide
|
|
16
75
|
|
|
@@ -27,12 +86,18 @@ const decrypted = EncryptionUtil.decrypt(encrypted);
|
|
|
27
86
|
**After (v4.0) - Controller-based encryption:**
|
|
28
87
|
|
|
29
88
|
```typescript
|
|
30
|
-
import { MisoClient } from '@aifabrix/miso-client';
|
|
89
|
+
import { MisoClient, loadConfig } from '@aifabrix/miso-client';
|
|
90
|
+
|
|
91
|
+
// Option 1: Use environment variable (recommended)
|
|
92
|
+
// Set MISO_ENCRYPTION_KEY in your .env file
|
|
93
|
+
const client = new MisoClient(loadConfig());
|
|
31
94
|
|
|
95
|
+
// Option 2: Provide in config
|
|
32
96
|
const client = new MisoClient({
|
|
33
97
|
controllerUrl: 'https://miso-controller.example.com',
|
|
34
98
|
clientId: 'my-app',
|
|
35
99
|
clientSecret: 'secret',
|
|
100
|
+
encryptionKey: 'your-encryption-key', // Required for encryption operations
|
|
36
101
|
});
|
|
37
102
|
|
|
38
103
|
const result = await client.encryption.encrypt('my-secret', 'param-name');
|
|
@@ -44,24 +109,26 @@ const decrypted = await client.encryption.decrypt(result.value, 'param-name');
|
|
|
44
109
|
|
|
45
110
|
### Why This Change?
|
|
46
111
|
|
|
47
|
-
- **Centralized key management** - Encryption keys are managed by the controller,
|
|
112
|
+
- **Centralized key management** - Encryption keys are managed by the controller, validated server-side
|
|
48
113
|
- **Azure Key Vault support** - Production environments can use Azure Key Vault for secure secret storage
|
|
49
114
|
- **Application isolation** - Each application can only access its own encrypted parameters
|
|
50
115
|
- **Audit logging** - All encryption/decryption operations are logged by the controller
|
|
116
|
+
- **Security** - Encryption key prevents misuse of rotated or leaked application credentials
|
|
51
117
|
|
|
52
118
|
### Added
|
|
53
119
|
|
|
54
120
|
- `client.encryption.encrypt(plaintext, parameterName)` - Encrypt a value via controller
|
|
55
121
|
- `client.encryption.decrypt(value, parameterName)` - Decrypt a value via controller
|
|
56
|
-
- `EncryptionService` class - Service layer with parameter validation
|
|
57
|
-
- `EncryptionError` class - Error class with codes: `ENCRYPTION_FAILED`, `DECRYPTION_FAILED`, `INVALID_PARAMETER_NAME`, `ACCESS_DENIED`, `PARAMETER_NOT_FOUND`
|
|
122
|
+
- `EncryptionService` class - Service layer with parameter and encryption key validation
|
|
123
|
+
- `EncryptionError` class - Error class with codes: `ENCRYPTION_FAILED`, `DECRYPTION_FAILED`, `INVALID_PARAMETER_NAME`, `ACCESS_DENIED`, `PARAMETER_NOT_FOUND`, `ENCRYPTION_KEY_REQUIRED`
|
|
58
124
|
- `EncryptResult` type - Return type for encrypt operations
|
|
59
125
|
- `EncryptionApi` class - API layer for controller communication
|
|
126
|
+
- `encryptionKey` config option - For server-side encryption key validation
|
|
127
|
+
- `MISO_ENCRYPTION_KEY` environment variable support in `loadConfig()`
|
|
60
128
|
|
|
61
129
|
### Removed
|
|
62
130
|
|
|
63
131
|
- `EncryptionUtil` class - Use `client.encryption` instead
|
|
64
|
-
- `encryptionKey` config option - No longer needed
|
|
65
132
|
|
|
66
133
|
### Technical
|
|
67
134
|
|
|
@@ -14,6 +14,8 @@ export interface EncryptRequest {
|
|
|
14
14
|
plaintext: string;
|
|
15
15
|
/** Name identifier for the parameter (alphanumeric, dots, underscores, hyphens, 1-128 chars) */
|
|
16
16
|
parameterName: string;
|
|
17
|
+
/** Encryption key for server-side validation (from MISO_ENCRYPTION_KEY) */
|
|
18
|
+
encryptionKey: string;
|
|
17
19
|
}
|
|
18
20
|
/**
|
|
19
21
|
* Encrypt response with storage reference
|
|
@@ -32,6 +34,8 @@ export interface DecryptRequest {
|
|
|
32
34
|
value: string;
|
|
33
35
|
/** Name identifier for the parameter (must match encryption) */
|
|
34
36
|
parameterName: string;
|
|
37
|
+
/** Encryption key for server-side validation (from MISO_ENCRYPTION_KEY) */
|
|
38
|
+
encryptionKey: string;
|
|
35
39
|
}
|
|
36
40
|
/**
|
|
37
41
|
* Decrypt response with plaintext value
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"encryption.types.d.ts","sourceRoot":"","sources":["../../../src/api/types/encryption.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
1
|
+
{"version":3,"file":"encryption.types.d.ts","sourceRoot":"","sources":["../../../src/api/types/encryption.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG,UAAU,GAAG,OAAO,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,gDAAgD;IAChD,SAAS,EAAE,MAAM,CAAC;IAClB,gGAAgG;IAChG,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,8DAA8D;IAC9D,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,gEAAgE;IAChE,aAAa,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -56,21 +56,9 @@ export declare function hasConfig(response: ClientTokenResponse): response is Cl
|
|
|
56
56
|
};
|
|
57
57
|
/**
|
|
58
58
|
* Create Express route handler for client-token endpoint
|
|
59
|
-
* Automatically enriches response with DataClient configuration
|
|
60
|
-
*
|
|
61
59
|
* @param misoClient - MisoClient instance (must be initialized)
|
|
62
60
|
* @param options - Optional configuration
|
|
63
61
|
* @returns Express route handler function
|
|
64
|
-
*
|
|
65
|
-
* @example
|
|
66
|
-
* ```typescript
|
|
67
|
-
* import { MisoClient, createClientTokenEndpoint } from '@aifabrix/miso-client';
|
|
68
|
-
*
|
|
69
|
-
* const misoClient = new MisoClient(loadConfig());
|
|
70
|
-
* await misoClient.initialize();
|
|
71
|
-
*
|
|
72
|
-
* app.post('/api/v1/auth/client-token', createClientTokenEndpoint(misoClient));
|
|
73
|
-
* ```
|
|
74
62
|
*/
|
|
75
63
|
export declare function createClientTokenEndpoint(misoClient: MisoClient, options?: ClientTokenEndpointOptions): (req: Request, res: Response) => Promise<void>;
|
|
76
64
|
//# sourceMappingURL=client-token-endpoint.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-token-endpoint.d.ts","sourceRoot":"","sources":["../../src/express/client-token-endpoint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"client-token-endpoint.d.ts","sourceRoot":"","sources":["../../src/express/client-token-endpoint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AAKtC;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC,0CAA0C;IAC1C,OAAO,EAAE,MAAM,CAAC;IAEhB,mDAAmD;IACnD,aAAa,EAAE,MAAM,CAAC;IAEtB,8DAA8D;IAC9D,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAE7B,yCAAyC;IACzC,QAAQ,EAAE,MAAM,CAAC;IAEjB,gCAAgC;IAChC,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IAEd,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;IAElB,qEAAqE;IACrE,MAAM,CAAC,EAAE,wBAAwB,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,cAAc,CAAC,EAAE,MAAM,CAAC;IAExB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,uEAAuE;IACvE,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,mBAAmB,GAAG,QAAQ,IAAI,mBAAmB,GAAG;IAAE,MAAM,EAAE,wBAAwB,CAAA;CAAE,CAE/H;AAsED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,UAAU,EACtB,OAAO,CAAC,EAAE,0BAA0B,GACnC,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CA0ChD"}
|
|
@@ -10,6 +10,7 @@ exports.hasConfig = hasConfig;
|
|
|
10
10
|
exports.createClientTokenEndpoint = createClientTokenEndpoint;
|
|
11
11
|
const environment_token_1 = require("../utils/environment-token");
|
|
12
12
|
const controller_url_resolver_1 = require("../utils/controller-url-resolver");
|
|
13
|
+
const error_response_1 = require("./error-response");
|
|
13
14
|
/**
|
|
14
15
|
* Type guard to check if response includes config
|
|
15
16
|
*
|
|
@@ -19,258 +20,136 @@ const controller_url_resolver_1 = require("../utils/controller-url-resolver");
|
|
|
19
20
|
function hasConfig(response) {
|
|
20
21
|
return response.config !== undefined;
|
|
21
22
|
}
|
|
23
|
+
/** Extract HTTP status from error message or axios error chain */
|
|
24
|
+
function extractHttpStatus(tokenError) {
|
|
25
|
+
const errorMessage = tokenError instanceof Error ? tokenError.message : "Unknown error";
|
|
26
|
+
const httpStatusMatch = errorMessage.match(/status:\s*(\d+)/i) || errorMessage.match(/status code\s+(\d+)/i) || errorMessage.match(/status\s+(\d+)/i);
|
|
27
|
+
let status = httpStatusMatch ? parseInt(httpStatusMatch[1], 10) : undefined;
|
|
28
|
+
let isNetworkError = false;
|
|
29
|
+
// Walk error chain for axios details
|
|
30
|
+
let currentError = tokenError;
|
|
31
|
+
for (let i = 0; i < 5 && currentError; i++) {
|
|
32
|
+
if (currentError && typeof currentError === "object" && "isAxiosError" in currentError && currentError.isAxiosError) {
|
|
33
|
+
const axiosError = currentError;
|
|
34
|
+
if (axiosError.response) {
|
|
35
|
+
status = axiosError.response.status;
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
if (axiosError.request && !axiosError.response) {
|
|
39
|
+
isNetworkError = true;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
if (currentError && typeof currentError === "object" && "cause" in currentError) {
|
|
44
|
+
currentError = currentError.cause;
|
|
45
|
+
}
|
|
46
|
+
else
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
return { status, isNetworkError };
|
|
50
|
+
}
|
|
51
|
+
/** Check if error message indicates network/timeout error */
|
|
52
|
+
function isNetworkOrTimeoutError(errorMessage, isAxiosNetworkError) {
|
|
53
|
+
const isNetwork = isAxiosNetworkError || /ECONNREFUSED|ENOTFOUND|ETIMEDOUT|connect|Network Error|network error|getaddrinfo/i.test(errorMessage);
|
|
54
|
+
const isTimeout = errorMessage.includes("Request timeout: Failed to get environment token") || /timeout/i.test(errorMessage);
|
|
55
|
+
return { isNetwork, isTimeout };
|
|
56
|
+
}
|
|
57
|
+
/** Handle token fetch error and send appropriate response */
|
|
58
|
+
function handleTokenError(tokenError, req, res, misoClient) {
|
|
59
|
+
const errorMessage = tokenError instanceof Error ? tokenError.message : "Unknown error";
|
|
60
|
+
if (errorMessage.includes("Origin validation failed")) {
|
|
61
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(errorMessage, 403, req));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const { status, isNetworkError } = extractHttpStatus(tokenError);
|
|
65
|
+
if (status) {
|
|
66
|
+
const msg = status === 401 ? "Failed to get environment token: Invalid client credentials or application not found"
|
|
67
|
+
: status === 403 ? "Failed to get environment token: Access denied" : errorMessage;
|
|
68
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(msg, status, req));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const { isNetwork, isTimeout } = isNetworkOrTimeoutError(errorMessage, isNetworkError);
|
|
72
|
+
if (isNetwork || isTimeout) {
|
|
73
|
+
const config = misoClient.getConfig();
|
|
74
|
+
let controllerUrl;
|
|
75
|
+
try {
|
|
76
|
+
controllerUrl = (0, controller_url_resolver_1.resolveControllerUrl)(config);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
controllerUrl = config.controllerPrivateUrl || config.controllerUrl || "NOT CONFIGURED";
|
|
80
|
+
}
|
|
81
|
+
const detail = isNetwork ? `Controller is unreachable. URL: ${controllerUrl}.` : `Controller request timed out. URL: ${controllerUrl}.`;
|
|
82
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(`Failed to get environment token: ${detail}`, 504, req));
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(errorMessage, 500, req));
|
|
86
|
+
}
|
|
87
|
+
/** Build DataClient config response */
|
|
88
|
+
function buildConfigResponse(req, misoClient, clientTokenUri) {
|
|
89
|
+
const config = misoClient.getConfig();
|
|
90
|
+
const controllerUrl = config.controllerPublicUrl || config.controllerUrl;
|
|
91
|
+
if (!controllerUrl)
|
|
92
|
+
return null;
|
|
93
|
+
return {
|
|
94
|
+
baseUrl: `${req.protocol}://${req.get("host") || "localhost"}`,
|
|
95
|
+
controllerUrl, controllerPublicUrl: config.controllerPublicUrl,
|
|
96
|
+
clientId: config.clientId, clientTokenUri,
|
|
97
|
+
};
|
|
98
|
+
}
|
|
22
99
|
/**
|
|
23
100
|
* Create Express route handler for client-token endpoint
|
|
24
|
-
* Automatically enriches response with DataClient configuration
|
|
25
|
-
*
|
|
26
101
|
* @param misoClient - MisoClient instance (must be initialized)
|
|
27
102
|
* @param options - Optional configuration
|
|
28
103
|
* @returns Express route handler function
|
|
29
|
-
*
|
|
30
|
-
* @example
|
|
31
|
-
* ```typescript
|
|
32
|
-
* import { MisoClient, createClientTokenEndpoint } from '@aifabrix/miso-client';
|
|
33
|
-
*
|
|
34
|
-
* const misoClient = new MisoClient(loadConfig());
|
|
35
|
-
* await misoClient.initialize();
|
|
36
|
-
*
|
|
37
|
-
* app.post('/api/v1/auth/client-token', createClientTokenEndpoint(misoClient));
|
|
38
|
-
* ```
|
|
39
104
|
*/
|
|
40
105
|
function createClientTokenEndpoint(misoClient, options) {
|
|
41
|
-
const opts = {
|
|
42
|
-
clientTokenUri: "/api/v1/auth/client-token",
|
|
43
|
-
expiresIn: 1800,
|
|
44
|
-
includeConfig: true,
|
|
45
|
-
...options,
|
|
46
|
-
};
|
|
106
|
+
const opts = { clientTokenUri: "/api/v1/auth/client-token", expiresIn: 1800, includeConfig: true, ...options };
|
|
47
107
|
return async (req, res) => {
|
|
48
|
-
// Helper to check if response was already sent
|
|
49
108
|
const isResponseSent = () => res.headersSent || res.writableEnded;
|
|
50
109
|
try {
|
|
51
|
-
// Check if misoClient is initialized
|
|
52
110
|
if (!misoClient.isInitialized()) {
|
|
53
|
-
if (!isResponseSent())
|
|
54
|
-
res.
|
|
55
|
-
error: "Service Unavailable",
|
|
56
|
-
message: "MisoClient is not initialized",
|
|
57
|
-
});
|
|
58
|
-
}
|
|
111
|
+
if (!isResponseSent())
|
|
112
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)("MisoClient is not initialized", 503, req));
|
|
59
113
|
return;
|
|
60
114
|
}
|
|
61
|
-
//
|
|
62
|
-
|
|
63
|
-
// Fail fast after 5 seconds if controller is unreachable
|
|
64
|
-
const timeoutMs = 5000; // 5 seconds - fail fast if controller is unreachable
|
|
65
|
-
const tokenPromise = (0, environment_token_1.getEnvironmentToken)(misoClient, req);
|
|
66
|
-
const timeoutPromise = new Promise((_, reject) => {
|
|
67
|
-
setTimeout(() => {
|
|
68
|
-
reject(new Error("Request timeout: Failed to get environment token within 5 seconds"));
|
|
69
|
-
}, timeoutMs);
|
|
70
|
-
});
|
|
115
|
+
// Fetch token with timeout
|
|
116
|
+
const timeoutPromise = new Promise((_, reject) => setTimeout(() => reject(new Error("Request timeout: Failed to get environment token within 5 seconds")), 5000));
|
|
71
117
|
let token;
|
|
72
118
|
try {
|
|
73
|
-
token = await Promise.race([
|
|
119
|
+
token = await Promise.race([(0, environment_token_1.getEnvironmentToken)(misoClient, req), timeoutPromise]);
|
|
74
120
|
}
|
|
75
121
|
catch (tokenError) {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
const errorMessage = tokenError instanceof Error ? tokenError.message : "Unknown error";
|
|
81
|
-
// Debug logging (can be removed after fixing)
|
|
82
|
-
if (process.env.NODE_ENV === 'development') {
|
|
83
|
-
console.log('[client-token-endpoint] Error caught:', {
|
|
84
|
-
errorMessage,
|
|
85
|
-
errorType: tokenError instanceof Error ? tokenError.constructor.name : typeof tokenError,
|
|
86
|
-
hasCause: tokenError && typeof tokenError === 'object' && 'cause' in tokenError,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
// Check if it's an origin validation error (403)
|
|
90
|
-
if (errorMessage.includes("Origin validation failed")) {
|
|
91
|
-
res.status(403).json({
|
|
92
|
-
error: "Forbidden",
|
|
93
|
-
message: errorMessage,
|
|
94
|
-
});
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
// Check if it's our timeout wrapper error (specific message from timeout promise)
|
|
98
|
-
const isTimeoutWrapperError = errorMessage.includes("Request timeout: Failed to get environment token within 5 seconds");
|
|
99
|
-
// Check if error message contains HTTP status codes (indicates HTTP error, not timeout)
|
|
100
|
-
// AuthService wraps axios errors with status info like "status: 401"
|
|
101
|
-
// Also check for axios error messages like "Request failed with status code 401"
|
|
102
|
-
const httpStatusMatch = errorMessage.match(/status:\s*(\d+)/i) ||
|
|
103
|
-
errorMessage.match(/status code\s+(\d+)/i) ||
|
|
104
|
-
errorMessage.match(/status\s+(\d+)/i);
|
|
105
|
-
const httpStatus = httpStatusMatch ? parseInt(httpStatusMatch[1], 10) : undefined;
|
|
106
|
-
const isHttpError = httpStatus !== undefined;
|
|
107
|
-
// Also try to extract axios error details from the error chain
|
|
108
|
-
let extractedHttpStatus = httpStatus;
|
|
109
|
-
let httpStatusText;
|
|
110
|
-
let isAxiosNetworkError = false;
|
|
111
|
-
// Try to extract axios error details from the error chain
|
|
112
|
-
let currentError = tokenError;
|
|
113
|
-
for (let i = 0; i < 5 && currentError; i++) {
|
|
114
|
-
if (currentError &&
|
|
115
|
-
typeof currentError === "object" &&
|
|
116
|
-
"isAxiosError" in currentError &&
|
|
117
|
-
currentError.isAxiosError) {
|
|
118
|
-
const axiosError = currentError;
|
|
119
|
-
if (axiosError.response) {
|
|
120
|
-
// Has response = HTTP error (not timeout)
|
|
121
|
-
extractedHttpStatus = axiosError.response.status;
|
|
122
|
-
httpStatusText = axiosError.response.statusText;
|
|
123
|
-
break;
|
|
124
|
-
}
|
|
125
|
-
// No response but has request = network/timeout error
|
|
126
|
-
if (axiosError.request && !axiosError.response) {
|
|
127
|
-
// This is a network/timeout error
|
|
128
|
-
isAxiosNetworkError = true;
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Check if error has a cause (for chained errors)
|
|
133
|
-
if (currentError && typeof currentError === "object" && "cause" in currentError) {
|
|
134
|
-
currentError = currentError.cause;
|
|
135
|
-
}
|
|
136
|
-
else {
|
|
137
|
-
break;
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// Use extracted status if available, otherwise use parsed status
|
|
141
|
-
const finalHttpStatus = extractedHttpStatus || httpStatus;
|
|
142
|
-
// If it's an HTTP error (like 401), return appropriate status code
|
|
143
|
-
if (isHttpError && finalHttpStatus) {
|
|
144
|
-
// Map common HTTP errors to appropriate status codes
|
|
145
|
-
if (finalHttpStatus === 401) {
|
|
146
|
-
res.status(401).json({
|
|
147
|
-
error: "Unauthorized",
|
|
148
|
-
message: "Failed to get environment token: Invalid client credentials or application not found",
|
|
149
|
-
});
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
if (finalHttpStatus === 403) {
|
|
153
|
-
res.status(403).json({
|
|
154
|
-
error: "Forbidden",
|
|
155
|
-
message: "Failed to get environment token: Access denied",
|
|
156
|
-
});
|
|
157
|
-
return;
|
|
158
|
-
}
|
|
159
|
-
// Other HTTP errors
|
|
160
|
-
res.status(finalHttpStatus).json({
|
|
161
|
-
error: httpStatusText || "Error",
|
|
162
|
-
message: errorMessage,
|
|
163
|
-
});
|
|
164
|
-
return;
|
|
165
|
-
}
|
|
166
|
-
// Check if it's a network error (controller unreachable)
|
|
167
|
-
// These errors indicate the controller is not reachable and should be treated as gateway timeout
|
|
168
|
-
const isNetworkError = isAxiosNetworkError ||
|
|
169
|
-
errorMessage.includes("ECONNREFUSED") ||
|
|
170
|
-
errorMessage.includes("ENOTFOUND") ||
|
|
171
|
-
errorMessage.includes("ETIMEDOUT") ||
|
|
172
|
-
errorMessage.includes("connect") ||
|
|
173
|
-
errorMessage.includes("Network Error") ||
|
|
174
|
-
errorMessage.includes("network error") ||
|
|
175
|
-
errorMessage.includes("getaddrinfo ENOTFOUND") ||
|
|
176
|
-
errorMessage.includes("getaddrinfo EAI_AGAIN");
|
|
177
|
-
// Check if it's a timeout error (from our wrapper or axios timeout)
|
|
178
|
-
const isTimeoutError = isTimeoutWrapperError ||
|
|
179
|
-
errorMessage.includes("timeout") ||
|
|
180
|
-
errorMessage.includes("Timeout");
|
|
181
|
-
if (isNetworkError || isTimeoutError) {
|
|
182
|
-
const config = misoClient.getConfig();
|
|
183
|
-
// Use resolveControllerUrl to get the resolved URL (with localhost -> 127.0.0.1 conversion)
|
|
184
|
-
let controllerUrl;
|
|
185
|
-
try {
|
|
186
|
-
controllerUrl = (0, controller_url_resolver_1.resolveControllerUrl)(config);
|
|
187
|
-
}
|
|
188
|
-
catch {
|
|
189
|
-
controllerUrl = config.controllerPrivateUrl || config.controllerUrl || "NOT CONFIGURED";
|
|
190
|
-
}
|
|
191
|
-
res.status(504).json({
|
|
192
|
-
error: "Gateway Timeout",
|
|
193
|
-
message: isNetworkError
|
|
194
|
-
? "Failed to get environment token: Controller is unreachable"
|
|
195
|
-
: "Failed to get environment token: Controller request timed out",
|
|
196
|
-
details: {
|
|
197
|
-
controllerUrl: controllerUrl || "NOT CONFIGURED",
|
|
198
|
-
timeout: "4 seconds",
|
|
199
|
-
suggestion: controllerUrl && controllerUrl !== "NOT CONFIGURED"
|
|
200
|
-
? `Controller at ${controllerUrl} is not responding. Please check if the controller is running and accessible.`
|
|
201
|
-
: "Controller URL is not configured. Please set MISO_CONTROLLER_URL environment variable.",
|
|
202
|
-
},
|
|
203
|
-
});
|
|
204
|
-
return;
|
|
205
|
-
}
|
|
206
|
-
// Other errors (500)
|
|
207
|
-
res.status(500).json({
|
|
208
|
-
error: "Internal Server Error",
|
|
209
|
-
message: errorMessage,
|
|
210
|
-
});
|
|
122
|
+
if (!isResponseSent())
|
|
123
|
+
handleTokenError(tokenError, req, res, misoClient);
|
|
211
124
|
return;
|
|
212
125
|
}
|
|
213
126
|
// Build response
|
|
214
|
-
const response = {
|
|
215
|
-
token,
|
|
216
|
-
expiresIn: opts.expiresIn,
|
|
217
|
-
};
|
|
218
|
-
// Include config if requested
|
|
127
|
+
const response = { token, expiresIn: opts.expiresIn };
|
|
219
128
|
if (opts.includeConfig) {
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
const controllerUrl = config.controllerPublicUrl || config.controllerUrl;
|
|
225
|
-
if (!controllerUrl) {
|
|
226
|
-
if (!isResponseSent()) {
|
|
227
|
-
res.status(500).json({
|
|
228
|
-
error: "Internal Server Error",
|
|
229
|
-
message: "Controller URL not configured",
|
|
230
|
-
});
|
|
231
|
-
}
|
|
129
|
+
const configResponse = buildConfigResponse(req, misoClient, opts.clientTokenUri);
|
|
130
|
+
if (!configResponse) {
|
|
131
|
+
if (!isResponseSent())
|
|
132
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)("Controller URL not configured", 500, req));
|
|
232
133
|
return;
|
|
233
134
|
}
|
|
234
|
-
response.config =
|
|
235
|
-
baseUrl,
|
|
236
|
-
controllerUrl,
|
|
237
|
-
controllerPublicUrl: config.controllerPublicUrl,
|
|
238
|
-
clientId: config.clientId,
|
|
239
|
-
clientTokenUri: opts.clientTokenUri,
|
|
240
|
-
};
|
|
135
|
+
response.config = configResponse;
|
|
241
136
|
}
|
|
242
|
-
|
|
243
|
-
if (!isResponseSent()) {
|
|
137
|
+
if (!isResponseSent())
|
|
244
138
|
res.json(response);
|
|
245
|
-
}
|
|
246
139
|
}
|
|
247
140
|
catch (error) {
|
|
248
|
-
|
|
249
|
-
if (isResponseSent()) {
|
|
141
|
+
if (isResponseSent())
|
|
250
142
|
return;
|
|
251
|
-
}
|
|
252
143
|
const errorMessage = error instanceof Error ? error.message : "Unknown error";
|
|
253
|
-
// Check if it's an origin validation error (403)
|
|
254
144
|
if (errorMessage.includes("Origin validation failed")) {
|
|
255
|
-
res.
|
|
256
|
-
error: "Forbidden",
|
|
257
|
-
message: errorMessage,
|
|
258
|
-
});
|
|
145
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(errorMessage, 403, req));
|
|
259
146
|
return;
|
|
260
147
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
res.status(504).json({
|
|
264
|
-
error: "Gateway Timeout",
|
|
265
|
-
message: "Failed to get environment token: Request timed out",
|
|
266
|
-
});
|
|
148
|
+
if (/timeout/i.test(errorMessage)) {
|
|
149
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)("Failed to get environment token: Request timed out", 504, req));
|
|
267
150
|
return;
|
|
268
151
|
}
|
|
269
|
-
|
|
270
|
-
res.status(500).json({
|
|
271
|
-
error: "Internal Server Error",
|
|
272
|
-
message: errorMessage,
|
|
273
|
-
});
|
|
152
|
+
(0, error_response_1.sendErrorResponse)(res, (0, error_response_1.createErrorResponse)(errorMessage, 500, req));
|
|
274
153
|
}
|
|
275
154
|
};
|
|
276
155
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-token-endpoint.js","sourceRoot":"","sources":["../../src/express/client-token-endpoint.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;
|
|
1
|
+
{"version":3,"file":"client-token-endpoint.js","sourceRoot":"","sources":["../../src/express/client-token-endpoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,9 +15,6 @@ export interface ErrorLogger {
|
|
|
15
15
|
* @param logger - Custom logger implementing ErrorLogger interface, or null to use stderr
|
|
16
16
|
*/
|
|
17
17
|
export declare function setErrorLogger(logger: ErrorLogger | null): void;
|
|
18
|
-
/**
|
|
19
|
-
* Generic route error handler
|
|
20
|
-
* Logs error and sends RFC 7807 compliant error response
|
|
21
|
-
*/
|
|
18
|
+
/** Generic route error handler - logs error and sends RFC 7807 compliant response */
|
|
22
19
|
export declare function handleRouteError(error: unknown, req: Request, res: Response, operation?: string): Promise<void>;
|
|
23
20
|
//# sourceMappingURL=error-handler.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/express/error-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAW5C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnE;AAKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE/D;
|
|
1
|
+
{"version":3,"file":"error-handler.d.ts","sourceRoot":"","sources":["../../src/express/error-handler.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAW5C;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACnE;AAKD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAE/D;AAqGD,qFAAqF;AACrF,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAarH"}
|