Skip to content

Commit 913fef9

Browse files
committed
Update config template string parsing and constructor options
1 parent 8b0e854 commit 913fef9

File tree

11 files changed

+59
-73
lines changed

11 files changed

+59
-73
lines changed

CHANGELOG.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
3939
#### Changed
4040
4141
- **[breaking]** Change the output of Data Dragon image and tarfile actions to a `Buffer` object.
42-
- Previous versions returned corrupted versions of the files which were unusable.
42+
- Previous versions returned corrupted versions of the files which were unusable.
43+
- Riot API keys are no longer required in the `GaleforceModule()` constructor, and the `options` parameter is now optional.
44+
45+
> ```typescript
46+
> import GaleforceModule from 'galeforce';
47+
>
48+
> const galeforce = new GaleforceModule(); // now OK, but requests requiring an API key will return a 401 Unauthorized error.
49+
> ```
4350
4451
### [0.2.0]
4552

package-lock.json

Lines changed: 16 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"bluebird": "^3.7.2",
4242
"chalk": "^4.1.1",
4343
"debug": "^4.3.1",
44+
"lodash": "^4.17.21",
4445
"node-cache": "^5.1.2",
4546
"redis": "^3.1.2",
4647
"support-color": "^7.1.0",
@@ -53,6 +54,7 @@
5354
"@types/bluebird": "^3.5.33",
5455
"@types/chai": "^4.2.17",
5556
"@types/debug": "^4.1.5",
57+
"@types/lodash": "^4.14.168",
5658
"@types/mocha": "^8.2.2",
5759
"@types/node": "^15.0.1",
5860
"@types/redis": "^2.8.28",

src/galeforce/actions/action.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,8 +121,10 @@ export default class Action<TResult> {
121121
} catch (e) {
122122
if (e.response?.status) {
123123
actionDebug(`${chalk.bold.magenta(this.payload._id)} | ${chalk.bold.yellow('return')} \u00AB ${chalk.bold.red(e.response.status)}`);
124-
if (e.response.status === 403) {
125-
throw new Error('[galeforce]: The provided Riot API key is invalid or has expired. Please verify its authenticity. (sc-403)');
124+
if (e.response.status === 401) {
125+
throw new Error('[galeforce]: No Riot API key was provided. Please ensure that your key is present in your configuration file or object. (401 Unauthorized)');
126+
} else if (e.response.status === 403) {
127+
throw new Error('[galeforce]: The provided Riot API key is invalid or has expired. Please verify its authenticity. (403 Forbidden)');
126128
} else {
127129
throw new Error(`[galeforce]: Data fetch failed with status code ${e.response.status}`);
128130
}

src/galeforce/configs/default.ts

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as TJS from 'typescript-json-schema';
66
import debug from 'debug';
77
import chalk from 'chalk';
88
import path from 'path';
9+
import _ from 'lodash';
910
import { ConfigInterface } from '../interfaces/config';
1011

1112
const initDebug = debug('galeforce:init');
@@ -18,52 +19,23 @@ const ConfigSchema = TJS.generateSchema(program, 'ConfigInterface', { required:
1819
const ajv = new Ajv();
1920
export const validate = ajv.compile(ConfigSchema);
2021

21-
/**
22-
* @private
23-
*
24-
* @param {String} template A list of string templates that are filled in with environment variables.
25-
*
26-
* @return {[String]} Substituted version of template with parameter values from match.
27-
*/
28-
function generateTemplateString(template: string): string {
29-
return template.replace(/\$\{([\s]*[^;\s{]+[\s]*)\}/g, (mt: string) => {
30-
const key = mt.substring(2, mt.length - 1);
31-
if (!Object.keys(process.env).includes(key)) {
32-
throw new Error(`[galeforce]: process.env.${key} is required in config file but is undefined.`);
33-
}
34-
return process.env[key] as string;
35-
});
36-
}
37-
38-
/**
39-
* @param {Record<string, unknown>} obj An object to substitute values from process.env for
40-
*
41-
* @return {Record<string, unknown>} Substituted version of template with process.env replaced values
42-
*/
43-
function recursivelySubstitute(obj: Record<string, string | object>): Record<string, string | object> {
44-
const newObj: Record<string, string | object> = JSON.parse(JSON.stringify(obj));
45-
46-
Object.keys(newObj).forEach((key) => {
47-
if (typeof newObj[key] === 'string') {
48-
newObj[key] = generateTemplateString(newObj[key] as string);
49-
}
50-
51-
if (typeof newObj[key] === 'object') {
52-
newObj[key] = recursivelySubstitute(newObj[key] as Record<string, string | object>);
53-
}
54-
});
55-
56-
return newObj as Record<string, string | object>;
57-
}
58-
5922
/**
6023
*
6124
* @param {string} filename The filename of the config file.
6225
*
6326
* @return {ConfigInterface} The corresponding config object.
6427
*/
6528
export function getConfig(filename: string): ConfigInterface {
66-
const configObject = recursivelySubstitute(yaml.parse(fs.readFileSync(filename, 'utf8')));
29+
const configObject = _.cloneDeepWith(yaml.parse(fs.readFileSync(filename, 'utf8')), (value: any) => {
30+
if(typeof value === 'string') {
31+
try {
32+
return _.template(value)(process.env);
33+
} catch (e) {
34+
throw new Error(`[galeforce]: process.env.${e.message.split(' ')[0]} is required in config file but is undefined.`);
35+
}
36+
}
37+
});
38+
6739
if (validate(configObject)) return configObject;
6840
throw new Error('Invalid config provided (config failed JSON schema validation).');
6941
}

src/galeforce/interfaces/config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
export interface ConfigInterface {
2-
'riot-api': {
2+
'riot-api'?: {
33
key: string;
44
};
55
cache?: {

src/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ class Galeforce {
104104
* @param options A JSON configuration object or a path to a valid YAML file.
105105
* @throws Will throw an Error if provided an invalid configuration file or object.
106106
*/
107-
constructor(options: ConfigInterface | string) {
107+
constructor(options: ConfigInterface | string = {}) {
108108
this.config = typeof options === 'string' ? getConfig(options) : options;
109109

110110
if (this.config.debug) {
@@ -118,7 +118,7 @@ class Galeforce {
118118

119119
let cache: Cache;
120120

121-
const RiotAPI = new RiotAPIModule(this.config['riot-api'].key);
121+
const RiotAPI: RiotAPIModule = new RiotAPIModule(this.config['riot-api']?.key || '');
122122

123123
if (this.config.cache) {
124124
if (this.config.cache.type === 'redis' && typeof this.config.cache.uri !== 'undefined') {

src/riot-api/requests/request.ts

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@
66
import axios, { AxiosRequestConfig } from 'axios';
77
import debug from 'debug';
88
import chalk from 'chalk';
9+
import _ from 'lodash';
910

1011
const requestDebug = debug('galeforce:riot-api');
1112

1213
export default class Request {
13-
protected targetURL: string;
14+
public readonly targetURL: string;
1415

1516
protected body: object;
1617

@@ -32,13 +33,11 @@ export default class Request {
3233
* @return {[String]} Substituted version of template with parameter values from match.
3334
*/
3435
protected static generateTemplateString(template: string, match: Record<string, unknown>): string {
35-
return template.replace(/\$\{([\s]*[^;\s{]+[\s]*)\}/g, (mt: string): string => {
36-
const key = mt.substring(2, mt.length - 1);
37-
if (!Object.keys(match).includes(key)) {
38-
throw new Error(`[galeforce]: Action payload ${key} is required but undefined.`);
39-
}
40-
return match[key] as string;
41-
});
36+
try {
37+
return _.template(template)(match);
38+
} catch (e) {
39+
throw new Error(`[galeforce]: Action payload ${e.message.split(' ')[0]} is required but undefined.`);
40+
}
4241
}
4342

4443
/**

test/actions.spec.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,8 @@ const na1API = nock('https://na1.api.riotgames.com')
149149
.reply(404)
150150
.get('/lol/summoner/v4/summoners/by-name/403')
151151
.reply(403)
152+
.get('/lol/summoner/v4/summoners/by-name/401')
153+
.reply(401)
152154
.get('/lol/summoner/v4/summoners/l3ZbR4AKKKK47w170ZOqcu7kmSV2qb38RV7zK_4n1GucI0w')
153155
.reply(200, replyValues.v4.summoner)
154156
.get('/lol/summoner/v4/summoners/by-account/xG5uPpEaSFc8LvOmi4wIumQZHbTlI6WJqECcgsW-_qu_BG4')
@@ -398,7 +400,9 @@ describe('/galeforce/actions', () => {
398400
it('should reject with correct error message when receiving a 404 status code', () => expect(Galeforce.lol.summoner().region(Galeforce.regions.lol.NORTH_AMERICA).name('404').exec())
399401
.to.eventually.be.rejectedWith('[galeforce]: Data fetch failed with status code 404'));
400402
it('should reject with correct error message when receiving a 403 status code', () => expect(Galeforce.lol.summoner().region(Galeforce.regions.lol.NORTH_AMERICA).name('403').exec())
401-
.to.eventually.be.rejectedWith('[galeforce]: The provided Riot API key is invalid or has expired. Please verify its authenticity. (sc-403)'));
403+
.to.eventually.be.rejectedWith('[galeforce]: The provided Riot API key is invalid or has expired. Please verify its authenticity. (403 Forbidden)'));
404+
it('should reject with correct error message when receiving a 403 status code', () => expect(Galeforce.lol.summoner().region(Galeforce.regions.lol.NORTH_AMERICA).name('401').exec())
405+
.to.eventually.be.rejectedWith('[galeforce]: No Riot API key was provided. Please ensure that your key is present in your configuration file or object. (401 Unauthorized)'));
402406
it('should timeout when rate limit exceeded', () => new Promise((resolve, reject) => {
403407
const GaleforceRL = new GaleforceModule('./test/test-configs/1.yaml');
404408
const autoTimeout = setTimeout(resolve, 500);

test/initialization.spec.js

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -90,20 +90,8 @@ describe('/galeforce', () => {
9090
it('should initialize properly from config file with environment variables', () => {
9191
expect(() => new GaleforceModule('./test/test-configs/2.yaml')).to.not.throw();
9292
});
93-
it('should error when passed an invalid config (1)', () => {
94-
expect(() => new GaleforceModule({
95-
cache: {
96-
type: 'redis',
97-
uri: 'redis://127.0.0.1:6379',
98-
},
99-
'rate-limit': {
100-
prefix: 'riotapi-ratelimit-',
101-
intervals: {
102-
120: 100,
103-
1: 20,
104-
},
105-
},
106-
})).to.throw();
93+
it('should initialize properly without being passed a config', () => {
94+
expect(() => new GaleforceModule()).to.not.throw();
10795
});
10896
it('should error when passed an invalid config (2)', () => {
10997
expect(() => new GaleforceModule({

0 commit comments

Comments
 (0)