akamai-edgegrid 3.5.5 → 4.0.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 CHANGED
@@ -1,11 +1,38 @@
1
1
  # Release notes
2
2
 
3
+
4
+ ## 4.0.0 (Dec 4, 2025)
5
+
6
+ ### Breaking Changes
7
+
8
+ * Replaced `log4js` with `pino` for logging and removed the `log4js` dependency.
9
+ * Updated logging configuration with the following environment variables:
10
+ * `AKAMAI_LOG_LEVEL` - controls log severity. Possible values are: `fatal`, `error`, `warn`, `info`, `debug`, or `trace`. Defaults to `info`.
11
+ * `AKAMAI_LOG_PRETTY` - enables pretty-printed, human-readable log format when set to `true`. Defaults to `false`.
12
+ * Logging is now disabled by default, ensuring zero logging unless explicitly enabled.
13
+ * Introduced the `enableLogging(option)` function to programmatically control logging:
14
+ * Passing `true` enables logging based on environment variables.
15
+ * Passing a valid "pino-like" logger object sets the current logger. Custom loggers must implement the `info`, `debug`, `error`, and `warn` methods.
16
+ * Exported `enableLogging` for external use, replacing the previous default `logger` export.
17
+ * Removed support for the `EG_VERBOSE` environment variable; Axios interceptors now always log at the `debug` level.
18
+ * Removed support for the `debug` parameter from the EdgeGrid constructor; debugging is now fully managed through `enableLogging()`.
19
+
20
+ ### Features/Enhancements
21
+
22
+ * Updated various dependencies.
23
+
24
+ ## 3.5.6 (Oct 15, 2025)
25
+
26
+ ### Bug fixes
27
+
28
+ * Replaced `uuid` package with `crypto` after uuid v13 dropped CommonJS support, to fix the compatibility issues.
29
+
3
30
  ## 3.5.5 (Oct 8, 2025)
4
31
 
5
32
  ### Features/Enhancements
6
33
 
7
34
  * Updated various dependencies.
8
- * Removed support for Node.js versions 18, 21 and 23.
35
+ * Removed support for Node.js versions 18, 21, and 23.
9
36
 
10
37
  ## 3.5.4 (Jul 24, 2025)
11
38
 
package/README.md CHANGED
@@ -168,6 +168,72 @@ eg.auth({
168
168
  });
169
169
  ```
170
170
 
171
+ ### Logging
172
+ The library supports configurable logging through the `enableLogging()` method.
173
+
174
+ - `enableLogging()`
175
+ - Enable with Environment Variables:
176
+ - `AKAMAI_LOG_LEVEL` (Default: 'info')
177
+ - Valid values:
178
+ - 'error'
179
+ - 'warn'
180
+ - 'info'
181
+ - 'debug'
182
+ - 'fatal'
183
+ - 'trace'
184
+
185
+ - `AKAMAI_LOG_PRETTY` (Default: 'false')
186
+ - Valid values: 'true' or 'false'
187
+
188
+ ```javascript
189
+ const edgeGrid = require('akamai-edgegrid');
190
+
191
+ // Set environment variables before enabling
192
+ process.env.AKAMAI_LOG_LEVEL = 'debug';
193
+ process.env.AKAMAI_LOG_PRETTY = 'true';
194
+
195
+ var eg = new EdgeGrid({
196
+ path: '/path/to/.edgerc',
197
+ section: '<section-header>'
198
+ });
199
+ eg.enableLogging(true);
200
+ ```
201
+
202
+ - Disable Logging:
203
+ ```javascript
204
+ const edgeGrid = require('akamai-edgegrid');
205
+ var eg = new EdgeGrid({
206
+ path: '/path/to/.edgerc',
207
+ section: '<section-header>'
208
+ });
209
+ eg.enableLogging(false);
210
+ ```
211
+
212
+ - Custom Logger:
213
+ - You can also pass a custom logger object to enableLogging. The object must have info, debug, error and warn methods.
214
+ - If you pass an object that does not implement the required info, debug, error and warn methods, an error will be thrown.
215
+
216
+ ```javascript
217
+ const edgeGrid = require('akamai-edgegrid');
218
+ //custom logger
219
+ const logger = {
220
+ info: (msg, ...args) => console.log('INFO:', msg, ...args),
221
+ debug: (msg, ...args) => console.log('DEBUG:', msg, ...args),
222
+ error: (msg, ...args) => console.error('ERROR:', msg, ...args),
223
+ warn: (msg, ...args) => console.warn('WARN:', msg, ...args)
224
+ };
225
+
226
+ var eg = new EdgeGrid({
227
+ path: '/path/to/.edgerc',
228
+ section: '<section-header>'
229
+ });
230
+
231
+ eg.enableLogging(logger); // Pass the custom logger
232
+
233
+ logger.info('Using custom logger for logging.');
234
+ logger.error('An error occurred!');
235
+ ```
236
+
171
237
  ### Proxy
172
238
 
173
239
  To use edgegrid with proxy, you can configure it with one of these methods:
@@ -203,29 +269,6 @@ To use edgegrid with proxy, you can configure it with one of these methods:
203
269
  $ node myapp.js
204
270
  ```
205
271
 
206
- ### Debug
207
-
208
- Enable debugging to get additional information about a request. You can configure this with one of these methods:
209
-
210
- - Add the `debug` argument to the `EdgeGrid()` method.
211
-
212
- ```javascript
213
- var eg = new EdgeGrid({
214
- path: '/path/to/.edgerc',
215
- section: 'section-header'
216
- debug: true
217
- });
218
- ```
219
-
220
- - Set the `EG_VERBOSE` environment variable.
221
-
222
- ```shell
223
- $ export EG_VERBOSE=true
224
- $ node src/main.js
225
- ```
226
-
227
-
228
-
229
272
  ## Reporting issues
230
273
 
231
274
  To report an issue or make a suggestion, create a new [GitHub issue](https://github.com/akamai/AkamaiOPEN-edgegrid-node/issues).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akamai-edgegrid",
3
- "version": "3.5.5",
3
+ "version": "4.0.0",
4
4
  "description": "Authentication handler for the Akamai OPEN EdgeGrid Authentication scheme in Node.js",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -17,17 +17,20 @@
17
17
  "api",
18
18
  "edgegrid"
19
19
  ],
20
+ "exports": {
21
+ ".": "./index.js"
22
+ },
20
23
  "license": "Apache-2.0",
21
24
  "dependencies": {
22
25
  "axios": "^1.1.2",
23
- "log4js": "^6.4.0",
24
- "uuid": "^13.0.0"
26
+ "pino": "^9.6.0"
25
27
  },
26
28
  "devDependencies": {
27
29
  "mocha": "^11.0.1",
28
30
  "mocha-junit-reporter": "^2.1.0",
29
31
  "nock": "^14.0.6",
30
32
  "nyc": "^17.0.0",
33
+ "pino-pretty": "^13.0.0",
31
34
  "tsd": "^0.33.0"
32
35
  }
33
- }
36
+ }
package/src/api.js CHANGED
@@ -2,7 +2,7 @@ const axios = require('axios'),
2
2
  auth = require('./auth'),
3
3
  edgerc = require('./edgerc'),
4
4
  helpers = require('./helpers'),
5
- logger = require('./logger');
5
+ { enableLogging, getLogger } = require('./logger');
6
6
 
7
7
  /**
8
8
  *
@@ -10,12 +10,11 @@ const axios = require('axios'),
10
10
  * @param {String} client_secret The client secret value from the .edgerc file.
11
11
  * @param {String} access_token The access token value from the .edgerc file.
12
12
  * @param {String} host The host a unique string followed by luna.akamaiapis.net from the .edgerc file.
13
- * @param {Boolean} debug The debug value allows to enable debugging.
14
13
  * @param {Number} max_body This value is deprecated.
15
14
  * @constructor
16
15
  * @deprecated max_body
17
16
  */
18
- const EdgeGrid = function (client_token, client_secret, access_token, host, debug, max_body) {
17
+ const EdgeGrid = function (client_token, client_secret, access_token, host, max_body) {
19
18
  // accepting an object containing a path to .edgerc and a config section
20
19
  if (typeof arguments[0] === 'object') {
21
20
  let edgercPath = arguments[0];
@@ -23,16 +22,16 @@ const EdgeGrid = function (client_token, client_secret, access_token, host, debu
23
22
  } else {
24
23
  this._setConfigFromStrings(client_token, client_secret, access_token, host);
25
24
  }
26
- if (process.env.EG_VERBOSE || debug || (typeof arguments[0] === 'object' && arguments[0].debug)) {
27
- axios.interceptors.request.use(request => {
28
- console.log('Starting Request', request);
29
- return request;
30
- });
31
- axios.interceptors.response.use(response => {
32
- console.log('Response:', response);
33
- return response;
34
- });
35
- }
25
+
26
+ axios.interceptors.request.use(request => {
27
+ getLogger().debug({ request }, 'Starting request');
28
+ return request;
29
+ });
30
+
31
+ axios.interceptors.response.use(response => {
32
+ getLogger().debug({ response }, 'Received response');
33
+ return response;
34
+ });
36
35
  };
37
36
 
38
37
  /**
@@ -143,7 +142,7 @@ function validatedArgs(args) {
143
142
 
144
143
  expected.forEach(function (arg, i) {
145
144
  if (!args[i]) {
146
- logger.error('No defined ' + arg);
145
+ getLogger().error({ arg }, 'No defined argument');
147
146
  valid = false;
148
147
  }
149
148
  });
@@ -161,4 +160,17 @@ EdgeGrid.prototype._setConfigFromObj = function (obj) {
161
160
  this.config = edgerc(obj.path, obj.section);
162
161
  };
163
162
 
163
+ /**
164
+ * Enables logging based on the provided option.
165
+ *
166
+ * @param {boolean|object} option - If true, configures the logger using environment variables.
167
+ * If a valid object, uses it as the logger instance.
168
+ * If false, disables logging.
169
+ * @return EdgeGrid object (self)
170
+ */
171
+ EdgeGrid.prototype.enableLogging = function(option) {
172
+ enableLogging(option);
173
+ return this;
174
+ };
175
+
164
176
  module.exports = EdgeGrid;
package/src/auth.js CHANGED
@@ -1,6 +1,6 @@
1
- const uuid = require('uuid'),
1
+ const { randomUUID } = require('crypto'),
2
2
  helpers = require('./helpers'),
3
- logger = require('./logger'),
3
+ { getLogger } = require('./logger'),
4
4
  url = require('url');
5
5
 
6
6
  /**
@@ -36,11 +36,11 @@ function makeAuthHeader(request, clientToken, accessToken, clientSecret, timesta
36
36
 
37
37
  authHeader = 'EG1-HMAC-SHA256 ' + joinedPairs;
38
38
 
39
- logger.info('Unsigned authorization header: ' + authHeader + '\n');
39
+ getLogger().info({ authHeader }, 'Unsigned authorization header');
40
40
 
41
41
  signedAuthHeader = authHeader + 'signature=' + helpers.signRequest(request, timestamp, clientSecret, authHeader, maxBody);
42
42
 
43
- logger.info('Signed authorization header: ' + signedAuthHeader + '\n');
43
+ getLogger().info({ signedAuthHeader }, 'Signed authorization header');
44
44
 
45
45
  return signedAuthHeader;
46
46
  }
@@ -76,7 +76,7 @@ module.exports = {
76
76
  * @deprecated maxBody
77
77
  */
78
78
  generateAuth: function (request, clientToken, clientSecret, accessToken, host, maxBody, guid, timestamp) {
79
- guid = guid || uuid.v4();
79
+ guid = guid || randomUUID();
80
80
  timestamp = timestamp || helpers.createTimestamp();
81
81
 
82
82
  if (!request.hasOwnProperty('headers')) {
package/src/edgerc.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const fs = require('fs'),
2
- logger = require('./logger'),
2
+ { getLogger } = require('./logger'),
3
3
  helpers = require('./helpers');
4
4
 
5
5
  function getSection(lines, sectionName) {
@@ -41,7 +41,7 @@ function validatedConfig(config) {
41
41
  errorMessage += "\nMissing: " + token;
42
42
  }
43
43
  });
44
- console.log('Missing part of the configuration:\n' + errorMessage);
44
+ getLogger().error({ errorMessage }, 'Missing part of the configuration');
45
45
  return {};
46
46
  }
47
47
 
@@ -91,6 +91,7 @@ function buildObj(configs) {
91
91
  }
92
92
 
93
93
  function readEnv(section) {
94
+ var logger = getLogger();
94
95
  const requiredKeys = ["HOST", "ACCESS_TOKEN", "CLIENT_TOKEN", "CLIENT_SECRET"],
95
96
  prefix = !section || section === "default" ? "AKAMAI_" : "AKAMAI_" + section.toUpperCase() + "_",
96
97
  envConfig = {};
@@ -99,7 +100,7 @@ function readEnv(section) {
99
100
  for (const key of requiredKeys) {
100
101
  const varName = prefix + key;
101
102
  if (!process.env[varName]) {
102
- logger.debug("Environment variable not set: " + varName);
103
+ logger.debug({ varName }, 'Environment variable not set');
103
104
  continue;
104
105
  }
105
106
  envConfig[key.toLowerCase()] = process.env[prefix + key];
@@ -107,7 +108,7 @@ function readEnv(section) {
107
108
  if (Object.keys(envConfig).length < requiredKeys.length) {
108
109
  return {};
109
110
  }
110
- console.log("Using configuration from environment variables");
111
+ logger.info('Using configuration from environment variables');
111
112
  return validatedConfig(envConfig);
112
113
  }
113
114
 
package/src/helpers.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const crypto = require('crypto'),
2
- logger = require('./logger'),
2
+ { getLogger } = require('./logger'),
3
3
  path = require('path'),
4
4
  os = require('os');
5
5
  const MAX_BODY = 131072
@@ -29,7 +29,7 @@ module.exports = {
29
29
  '+0000';
30
30
  },
31
31
  contentHash: function (request) {
32
-
32
+ var logger = getLogger()
33
33
  let contentHash = '',
34
34
  preparedBody = request.body || '',
35
35
  isTarball = preparedBody instanceof Uint8Array && request.headers['Content-Type'] === 'application/gzip';
@@ -51,27 +51,31 @@ module.exports = {
51
51
  request.body = preparedBody; // Is this required or being used?
52
52
  }
53
53
 
54
- logger.info('Body is \"' + preparedBody + '\"');
55
- logger.debug('PREPARED BODY LENGTH', preparedBody.length);
54
+ logger.info({ body: preparedBody }, 'Body');
55
+ logger.debug({ length: preparedBody.length }, 'Prepared body length');
56
56
 
57
57
  if (request.method === 'POST' && preparedBody.length > 0) {
58
58
 
59
- logger.info('Signing content: \"' + preparedBody + '\"');
59
+ logger.info({ body: preparedBody }, 'Signing content');
60
60
 
61
61
  // If body data is too large, cut down to max-body size which is const value
62
62
  if (preparedBody.length > MAX_BODY) {
63
- logger.warn('Data length (' + preparedBody.length + ') is larger than maximum ' + MAX_BODY);
63
+ logger.warn({
64
+ length: preparedBody.length,
65
+ maxAllowed: MAX_BODY,
66
+ }, 'Data length exceeds maximum allowed');
67
+
64
68
  if (isTarball)
65
69
  preparedBody = preparedBody.slice(0, MAX_BODY);
66
70
  else
67
71
  preparedBody = preparedBody.substring(0, MAX_BODY);
68
- logger.info('Body truncated. New value \"' + preparedBody + '\"');
72
+ logger.info({ newBody: preparedBody }, 'Body truncated');
69
73
  }
70
74
 
71
- logger.debug('PREPARED BODY', preparedBody);
75
+ logger.debug({ preparedBody }, 'Prepared body content');
72
76
 
73
77
  contentHash = this.base64Sha256(preparedBody);
74
- logger.info('Content hash is \"' + contentHash + '\"');
78
+ logger.info({ hash: contentHash }, 'Content hash is');
75
79
  }
76
80
 
77
81
  return contentHash;
@@ -100,7 +104,7 @@ module.exports = {
100
104
 
101
105
  const dataToSignStr = dataToSign.join('\t').toString();
102
106
 
103
- logger.info('Data to sign: "' + dataToSignStr + '" \n');
107
+ getLogger().info({ data: dataToSignStr }, 'Data to sign');
104
108
 
105
109
  return dataToSignStr;
106
110
  },
@@ -180,7 +184,7 @@ module.exports = {
180
184
  signingKey: function (timestamp, clientSecret) {
181
185
  const key = this.base64HmacSha256(timestamp, clientSecret);
182
186
 
183
- logger.info('Signing key: ' + key + '\n');
187
+ getLogger().info({ key }, 'Signing key used');
184
188
 
185
189
  return key;
186
190
  },
package/src/logger.js CHANGED
@@ -1,12 +1,82 @@
1
- const log4js = require('log4js'),
2
- logger = log4js.getLogger();
1
+ const pino = require('pino');
3
2
 
4
- if (!process.env.LOG4JS_CONFIG) {
5
- logger.level = log4js.levels.ERROR;
3
+ const VALID_LEVELS = ['fatal', 'error', 'warn', 'info', 'debug', 'trace', 'silent'];
4
+
5
+ const silentLogger = createLogger({level: 'silent'});
6
+
7
+ // zero logging by default.
8
+ let currentLogger = silentLogger;
9
+
10
+ /**
11
+ * Enables logging based on the provided option.
12
+ *
13
+ * @param {boolean|object} option - If true, configures the logger using environment variables.
14
+ * If an valid object, uses it as the logger instance.
15
+ * Otherwise, reverts to silent logging.
16
+ */
17
+ function enableLogging(option) {
18
+ if (option === true) {
19
+ const envLogLevel = process.env.AKAMAI_LOG_LEVEL || 'info';
20
+ if (!VALID_LEVELS.includes(envLogLevel)) {
21
+ throw new Error(`Invalid AKAMAI_LOG_LEVEL value "${envLogLevel}". Expected one of: ${VALID_LEVELS.join(', ')}.`);
22
+ }
23
+ currentLogger = createLogger({
24
+ level: envLogLevel,
25
+ pretty: process.env.AKAMAI_LOG_PRETTY === 'true'
26
+ });
27
+ } else if (option === false) {
28
+ currentLogger = silentLogger;
29
+ } else if (isValidLoggerObject(option)) {
30
+ currentLogger = option;
31
+ } else {
32
+ throw new Error('Invalid argument passed to enableLogging. Expected true, false, or a logger object.');
33
+ }
34
+ }
35
+
36
+ /**
37
+ * Checks if the provided object implements the necessary logger methods.
38
+ *
39
+ * @param {Object} option - The object to validate.
40
+ * @returns {boolean} - Returns true if the object is a valid logger, false otherwise.
41
+ */
42
+ function isValidLoggerObject(option) {
43
+ return ['info', 'debug', 'error', 'warn'].every(fn => typeof option[fn] === 'function');
44
+ }
45
+
46
+ /**
47
+ * Creates and configures a Pino logger instance.
48
+ *
49
+ * @param {Object} options - Configuration options for the logger.
50
+ * @param {string} [options.level='info'] - The minimum level of logs to output.
51
+ * @param {boolean} [options.pretty=false] - Whether to enable pretty-printing of logs.
52
+ * @returns {Object} - Configured Pino logger instance.
53
+ */
54
+ function createLogger({level = 'info', pretty = false} = {}) {
55
+ return pino({
56
+ level,
57
+ timestamp: () => `,"time":"${new Date().toISOString()}"`,
58
+ transport: pretty ? {
59
+ target: 'pino-pretty',
60
+ options: {
61
+ colorize: true,
62
+ translateTime: 'yyyy-mm-dd HH:MM:ss.l',
63
+ ignore: 'pid,hostname'
64
+ }
65
+ } : undefined
66
+ });
67
+ }
68
+
69
+ /**
70
+ * Returns the current logger instance.
71
+ */
72
+ function getLogger() {
73
+ return currentLogger;
6
74
  }
7
75
 
8
- if (process.env.EDGEGRID_ENV === 'test') {
9
- logger.level = log4js.levels.OFF;
76
+ if (process.env.EDGEGRID_ENV !== 'test') {
77
+ if (process.env.AKAMAI_LOG_LEVEL || process.env.AKAMAI_LOG_PRETTY) {
78
+ enableLogging(true);
79
+ }
10
80
  }
11
81
 
12
- module.exports = logger;
82
+ module.exports = { enableLogging, getLogger };
@@ -0,0 +1,40 @@
1
+ const assert = require('assert');
2
+ const logger = require('../../src/logger');
3
+
4
+ describe('enableLogging', function () {
5
+ it('should accept a custom logger object', function () {
6
+ const logs = [];
7
+ const customLogger = {
8
+ info: (msg) => logs.push(`INFO: ${msg}`),
9
+ debug: (msg) => logs.push(`DEBUG: ${msg}`),
10
+ error: (msg) => logs.push(`ERROR: ${msg}`),
11
+ warn: (msg) => logs.push(`WARN: ${msg}`)
12
+ };
13
+
14
+ logger.enableLogging(customLogger);
15
+
16
+ const log = logger.getLogger();
17
+ log.info('test info');
18
+ log.debug('test debug');
19
+ log.error('test error');
20
+ log.warn('test warn');
21
+
22
+ assert.strictEqual(logs[0], 'INFO: test info');
23
+ assert.strictEqual(logs[1], 'DEBUG: test debug');
24
+ assert.strictEqual(logs[2], 'ERROR: test error');
25
+ assert.strictEqual(logs[3], 'WARN: test warn');
26
+ });
27
+
28
+ it('should throw an error for an invalid custom logger object', function () {
29
+ const invalidLogger = {
30
+ info: () => {} // Missing 'debug', 'error', 'warn' methods
31
+ };
32
+
33
+ try {
34
+ logger.enableLogging(invalidLogger);
35
+ assert.fail('Expected error to be thrown'); // If no error is thrown, this will fail
36
+ } catch (error) {
37
+ assert.strictEqual(error.message, 'Invalid argument passed to enableLogging. Expected true, false, or a logger object.');
38
+ }
39
+ });
40
+ });