@aligent/microservice-util-lib 1.3.1 → 1.3.3
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aligent/microservice-util-lib",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.3",
|
|
4
4
|
"description": "A set of utility functions for Aligent Microservices",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"main": "./src/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"@aws-sdk/client-ssm": "^3.922.0",
|
|
16
16
|
"oauth-sign": "^0.9.0",
|
|
17
17
|
"object-hash": "^3.0.0",
|
|
18
|
-
"openapi-fetch": "^0.
|
|
18
|
+
"openapi-fetch": "^0.17.0"
|
|
19
19
|
},
|
|
20
20
|
"author": "Aligent",
|
|
21
21
|
"license": "MIT",
|
package/src/index.d.ts
CHANGED
|
@@ -3,9 +3,10 @@ import fetchSsmParams from './fetch-ssm-params/fetch-ssm-params';
|
|
|
3
3
|
import getAwsIdFromArn from './get-aws-id-from-arn/get-aws-id-from-arn';
|
|
4
4
|
import hasDefinedProperties from './has-properties-defined/has-properties-defined';
|
|
5
5
|
import { ApiKey, Basic, OAuth10a, OAuth20, apiKeyAuthMiddleware, basicAuthMiddleware, oAuth10aAuthMiddleware, oAuth20AuthMiddleware } from './openapi-fetch-middlewares/authentications';
|
|
6
|
+
import { LogLevel, Logger, logMiddleware } from './openapi-fetch-middlewares/log';
|
|
6
7
|
import { RetryConfig as RetryMiddlewareConfig, retryMiddleware } from './openapi-fetch-middlewares/retry';
|
|
7
8
|
import remap, { ObjectMap, Remap } from './remap/remap';
|
|
8
9
|
import retryWrapper, { RetryConfig } from './retry-wrapper/retry-wrapper';
|
|
9
10
|
import S3Dao from './s3/s3';
|
|
10
|
-
export type { ApiKey, Basic, OAuth10a, OAuth20, ObjectMap, Remap, RetryConfig, RetryMiddlewareConfig, S3Dao, };
|
|
11
|
-
export { apiKeyAuthMiddleware, basicAuthMiddleware, chunkBy, fetchSsmParams, getAwsIdFromArn, hasDefinedProperties, oAuth10aAuthMiddleware, oAuth20AuthMiddleware, remap, retryMiddleware, retryWrapper, };
|
|
11
|
+
export type { ApiKey, Basic, LogLevel, Logger, OAuth10a, OAuth20, ObjectMap, Remap, RetryConfig, RetryMiddlewareConfig, S3Dao, };
|
|
12
|
+
export { apiKeyAuthMiddleware, basicAuthMiddleware, chunkBy, fetchSsmParams, getAwsIdFromArn, hasDefinedProperties, logMiddleware, oAuth10aAuthMiddleware, oAuth20AuthMiddleware, remap, retryMiddleware, retryWrapper, };
|
package/src/index.js
CHANGED
|
@@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.retryWrapper = exports.retryMiddleware = exports.remap = exports.oAuth20AuthMiddleware = exports.oAuth10aAuthMiddleware = exports.hasDefinedProperties = exports.getAwsIdFromArn = exports.fetchSsmParams = exports.chunkBy = exports.basicAuthMiddleware = exports.apiKeyAuthMiddleware = void 0;
|
|
6
|
+
exports.retryWrapper = exports.retryMiddleware = exports.remap = exports.oAuth20AuthMiddleware = exports.oAuth10aAuthMiddleware = exports.logMiddleware = exports.hasDefinedProperties = exports.getAwsIdFromArn = exports.fetchSsmParams = exports.chunkBy = exports.basicAuthMiddleware = exports.apiKeyAuthMiddleware = void 0;
|
|
7
7
|
/* v8 ignore start */
|
|
8
8
|
const chunk_by_1 = __importDefault(require("./chunk-by/chunk-by"));
|
|
9
9
|
exports.chunkBy = chunk_by_1.default;
|
|
@@ -18,6 +18,8 @@ Object.defineProperty(exports, "apiKeyAuthMiddleware", { enumerable: true, get:
|
|
|
18
18
|
Object.defineProperty(exports, "basicAuthMiddleware", { enumerable: true, get: function () { return authentications_1.basicAuthMiddleware; } });
|
|
19
19
|
Object.defineProperty(exports, "oAuth10aAuthMiddleware", { enumerable: true, get: function () { return authentications_1.oAuth10aAuthMiddleware; } });
|
|
20
20
|
Object.defineProperty(exports, "oAuth20AuthMiddleware", { enumerable: true, get: function () { return authentications_1.oAuth20AuthMiddleware; } });
|
|
21
|
+
const log_1 = require("./openapi-fetch-middlewares/log");
|
|
22
|
+
Object.defineProperty(exports, "logMiddleware", { enumerable: true, get: function () { return log_1.logMiddleware; } });
|
|
21
23
|
const retry_1 = require("./openapi-fetch-middlewares/retry");
|
|
22
24
|
Object.defineProperty(exports, "retryMiddleware", { enumerable: true, get: function () { return retry_1.retryMiddleware; } });
|
|
23
25
|
const remap_1 = __importDefault(require("./remap/remap"));
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Middleware } from 'openapi-fetch';
|
|
2
|
+
/**
|
|
3
|
+
* Logger interface to support various logging implementations
|
|
4
|
+
* (console, winston, pino, bunyan, etc.)
|
|
5
|
+
*/
|
|
6
|
+
interface Logger {
|
|
7
|
+
info(message: string, ...args: unknown[]): void;
|
|
8
|
+
debug?(message: string, ...args: unknown[]): void;
|
|
9
|
+
}
|
|
10
|
+
type LogLevel = 'INFO' | 'DEBUG';
|
|
11
|
+
/**
|
|
12
|
+
* Creates a logging middleware for openapi-fetch clients.
|
|
13
|
+
*
|
|
14
|
+
* This middleware logs HTTP requests and responses with Content-Type handling.
|
|
15
|
+
* It supports various logger implementations and configurable log levels (INFO or DEBUG).
|
|
16
|
+
*
|
|
17
|
+
* Features:
|
|
18
|
+
* - Automatic Content-Type detection and appropriate parsing
|
|
19
|
+
* - Support for JSON, text, XML, form data, and binary content
|
|
20
|
+
* - Configurable log levels (INFO/DEBUG)
|
|
21
|
+
* - Compatible with multiple logging libraries
|
|
22
|
+
*
|
|
23
|
+
* @param clientName - A descriptive name for the API client (used in log messages)
|
|
24
|
+
* @param logLevel - The logging level to use: 'INFO' (default) or 'DEBUG'
|
|
25
|
+
* @param logger - Logger instance implementing the Logger interface (defaults to console)
|
|
26
|
+
* @returns An openapi-fetch middleware that logs requests and responses
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // Basic usage with default console logger at INFO level
|
|
31
|
+
* import createClient from 'openapi-fetch';
|
|
32
|
+
*
|
|
33
|
+
* const client = createClient({ baseUrl: 'https://api.example.com' });
|
|
34
|
+
* client.use(logMiddleware('MyAPI'));
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* // Using DEBUG level with console
|
|
40
|
+
* client.use(logMiddleware('MyAPI', 'DEBUG'));
|
|
41
|
+
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* // Custom logger implementation
|
|
46
|
+
* const customLogger = {
|
|
47
|
+
* info: (msg, ...args) => console.log('[INFO]', msg, ...args),
|
|
48
|
+
* debug: (msg, ...args) => console.log('[DEBUG]', msg, ...args)
|
|
49
|
+
* };
|
|
50
|
+
*
|
|
51
|
+
* client.use(logMiddleware('MyAPI', 'DEBUG', customLogger));
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
declare function logMiddleware(clientName: string, logLevel?: LogLevel, logger?: Logger): Middleware;
|
|
55
|
+
export { logMiddleware };
|
|
56
|
+
export type { Logger, LogLevel };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logMiddleware = logMiddleware;
|
|
4
|
+
/**
|
|
5
|
+
* Parse request/response body based on Content-Type header
|
|
6
|
+
*/
|
|
7
|
+
async function parseBody(source, contentType) {
|
|
8
|
+
const normalizedContentType = contentType ? contentType.toLowerCase() : 'application/json';
|
|
9
|
+
try {
|
|
10
|
+
// JSON content
|
|
11
|
+
if (normalizedContentType.includes('application/json')) {
|
|
12
|
+
return await source.clone().json();
|
|
13
|
+
}
|
|
14
|
+
// Text content
|
|
15
|
+
if (normalizedContentType.includes('text/') ||
|
|
16
|
+
normalizedContentType.includes('application/xml') ||
|
|
17
|
+
normalizedContentType.includes('application/x-www-form-urlencoded')) {
|
|
18
|
+
return await source.clone().text();
|
|
19
|
+
}
|
|
20
|
+
// Binary or multipart content - don't parse
|
|
21
|
+
if (normalizedContentType.includes('multipart/form-data') ||
|
|
22
|
+
normalizedContentType.includes('application/octet-stream') ||
|
|
23
|
+
normalizedContentType.includes('image/') ||
|
|
24
|
+
normalizedContentType.includes('video/') ||
|
|
25
|
+
normalizedContentType.includes('audio/')) {
|
|
26
|
+
return `[Binary content: ${contentType}]`;
|
|
27
|
+
}
|
|
28
|
+
// Unknown content type, try JSON as default
|
|
29
|
+
return await source.clone().json();
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
return `[Unable to parse ${contentType} body: ${error instanceof Error ? error.message : 'Unknown error'}]`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Creates a logging middleware for openapi-fetch clients.
|
|
37
|
+
*
|
|
38
|
+
* This middleware logs HTTP requests and responses with Content-Type handling.
|
|
39
|
+
* It supports various logger implementations and configurable log levels (INFO or DEBUG).
|
|
40
|
+
*
|
|
41
|
+
* Features:
|
|
42
|
+
* - Automatic Content-Type detection and appropriate parsing
|
|
43
|
+
* - Support for JSON, text, XML, form data, and binary content
|
|
44
|
+
* - Configurable log levels (INFO/DEBUG)
|
|
45
|
+
* - Compatible with multiple logging libraries
|
|
46
|
+
*
|
|
47
|
+
* @param clientName - A descriptive name for the API client (used in log messages)
|
|
48
|
+
* @param logLevel - The logging level to use: 'INFO' (default) or 'DEBUG'
|
|
49
|
+
* @param logger - Logger instance implementing the Logger interface (defaults to console)
|
|
50
|
+
* @returns An openapi-fetch middleware that logs requests and responses
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* // Basic usage with default console logger at INFO level
|
|
55
|
+
* import createClient from 'openapi-fetch';
|
|
56
|
+
*
|
|
57
|
+
* const client = createClient({ baseUrl: 'https://api.example.com' });
|
|
58
|
+
* client.use(logMiddleware('MyAPI'));
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```typescript
|
|
63
|
+
* // Using DEBUG level with console
|
|
64
|
+
* client.use(logMiddleware('MyAPI', 'DEBUG'));
|
|
65
|
+
* ```
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* // Custom logger implementation
|
|
70
|
+
* const customLogger = {
|
|
71
|
+
* info: (msg, ...args) => console.log('[INFO]', msg, ...args),
|
|
72
|
+
* debug: (msg, ...args) => console.log('[DEBUG]', msg, ...args)
|
|
73
|
+
* };
|
|
74
|
+
*
|
|
75
|
+
* client.use(logMiddleware('MyAPI', 'DEBUG', customLogger));
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
function logMiddleware(clientName, logLevel = 'INFO', logger = console) {
|
|
79
|
+
const log = (message, ...args) => {
|
|
80
|
+
if (logLevel === 'DEBUG' && logger.debug) {
|
|
81
|
+
logger.debug(message, ...args);
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
logger.info(message, ...args);
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
async onRequest({ options, params, request }) {
|
|
88
|
+
const contentType = request.headers.get('Content-Type');
|
|
89
|
+
log(`${request.method} request to ${clientName}`, {
|
|
90
|
+
method: request.method,
|
|
91
|
+
baseUrl: options.baseUrl,
|
|
92
|
+
url: request.url,
|
|
93
|
+
params: params,
|
|
94
|
+
body: await parseBody(request, contentType),
|
|
95
|
+
});
|
|
96
|
+
},
|
|
97
|
+
async onResponse({ response }) {
|
|
98
|
+
const contentType = response.headers.get('Content-Type');
|
|
99
|
+
log(`Response from ${clientName}`, {
|
|
100
|
+
status: response.status,
|
|
101
|
+
body: await parseBody(response, contentType),
|
|
102
|
+
});
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
}
|
|
@@ -140,8 +140,14 @@ function shouldGenerateBodyHash(body, method, includeBodyHash) {
|
|
|
140
140
|
async function generateOauthParams(request, options, params, config) {
|
|
141
141
|
const { algorithm, includeBodyHash = 'auto', realm, callback, verifier } = config;
|
|
142
142
|
const { consumerKey, consumerSecret, token, tokenSecret } = await config.credentials();
|
|
143
|
-
|
|
144
|
-
|
|
143
|
+
// Due to the way that openapi-fetch & fetch API are implemented in NodeJS (undici),
|
|
144
|
+
// each request only can be used ONCE. We have to clone the request like this to extract information
|
|
145
|
+
// Otherwise, undici will not be able to create & send the request.
|
|
146
|
+
const clonedRequest = request.clone();
|
|
147
|
+
const method = (clonedRequest.method || 'GET').toUpperCase();
|
|
148
|
+
const url = combineUrlAndPathParams(clonedRequest.url, params.path);
|
|
149
|
+
const contentType = clonedRequest.headers.get('Content-Type');
|
|
150
|
+
const body = await clonedRequest.text();
|
|
145
151
|
const oauthParams = {
|
|
146
152
|
oauth_consumer_key: consumerKey,
|
|
147
153
|
oauth_nonce: crypto_1.default.randomUUID(),
|
|
@@ -165,22 +171,18 @@ async function generateOauthParams(request, options, params, config) {
|
|
|
165
171
|
if (params.query) {
|
|
166
172
|
addParamsToSign(paramsToSign, params.query);
|
|
167
173
|
}
|
|
168
|
-
const body = await request.text();
|
|
169
174
|
// If user submit a form, then include form parameters in the
|
|
170
175
|
// signature as parameters rather than the body hash
|
|
171
|
-
if (
|
|
176
|
+
if (contentType === 'application/x-www-form-urlencoded') {
|
|
172
177
|
addParamsToSign(paramsToSign, new URLSearchParams(body));
|
|
173
|
-
console.log(JSON.stringify(paramsToSign));
|
|
174
178
|
}
|
|
175
|
-
else {
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
addParamToSign(paramsToSign, 'oauth_body_hash', bodyHash);
|
|
183
|
-
}
|
|
179
|
+
else if (shouldGenerateBodyHash(body, method, includeBodyHash)) {
|
|
180
|
+
const bodyHash = crypto_1.default
|
|
181
|
+
.createHash(algorithm === 'HMAC-SHA1' ? 'sha1' : 'sha256')
|
|
182
|
+
.update(Buffer.from(body))
|
|
183
|
+
.digest('base64');
|
|
184
|
+
oauthParams.oauth_body_hash = bodyHash;
|
|
185
|
+
addParamToSign(paramsToSign, 'oauth_body_hash', bodyHash);
|
|
184
186
|
}
|
|
185
187
|
const oauthUrl = getOAuthUrl(options.baseUrl, url);
|
|
186
188
|
oauthParams.oauth_signature = (0, oauth_sign_1.sign)(algorithm, method, oauthUrl, paramsToSign, consumerSecret, tokenSecret);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"5.9.3"}
|