@govuk-pay/cli 0.0.31 → 0.0.33

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": "@govuk-pay/cli",
3
- "version": "0.0.31",
3
+ "version": "0.0.33",
4
4
  "description": "GOV.UK Pay Command Line Interface",
5
5
  "bin": {
6
6
  "pay": "bin/cli.js",
@@ -22,8 +22,8 @@
22
22
  "openurl": "^1.1.1",
23
23
  "semver": "^7.6.3",
24
24
  "totp-generator": "^1.0.0",
25
- "ts-standard": "^12.0.2",
26
- "yaml": "^2.5.1"
25
+ "yaml": "^2.5.1",
26
+ "yargs": "^17.7.2"
27
27
  },
28
28
  "files": [
29
29
  "resources",
@@ -146,6 +146,9 @@ services:
146
146
  {{#ifBoth ../mountLocalNodeApps localBuild}}
147
147
  volumes:
148
148
  - "$WORKSPACE/pay-{{../name}}:/app"
149
+ {{#if ../../mountPayJSCommons}}
150
+ - "$WORKSPACE/pay-js-commons:/pay-js-commons"
151
+ {{/if}}
149
152
  {{/ifBoth}}
150
153
  environment:
151
154
  - BIND_HOST=0.0.0.0
@@ -178,7 +181,7 @@ services:
178
181
  {{#ifBoth localBuild entrypointOverrideLocal}}
179
182
  entrypoint: {{{../entrypointOverrideLocal}}}
180
183
  {{else}}
181
- entrypoint: "npx nodemon --inspect=0.0.0.0:{{../debugPort}} start.js"
184
+ entrypoint: "npx nodemon --inspect=0.0.0.0:{{../debugPort}}"
182
185
  {{/ifBoth}}
183
186
  ports:
184
187
  - "{{port}}:{{port}}"
@@ -1,33 +1,8 @@
1
1
  "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || function (mod) {
19
- if (mod && mod.__esModule) return mod;
20
- var result = {};
21
- if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
- __setModuleDefault(result, mod);
23
- return result;
24
- };
25
2
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.logBrowseCommands = void 0;
27
- const path = __importStar(require("path"));
3
+ exports.handler = exports.builder = exports.desc = exports.command = void 0;
28
4
  const standardContent_js_1 = require("../core/standardContent.js");
29
5
  const moduleFunctionWrapper_js_1 = require("../util/moduleFunctionWrapper.js");
30
- const constants_1 = require("../core/constants");
31
6
  const requestableItems = new Map();
32
7
  requestableItems.set('concourse', {
33
8
  name: 'concourse page',
@@ -45,51 +20,25 @@ requestableItems.set('status', {
45
20
  name: 'status page',
46
21
  url: 'https://payments.statuspage.io/'
47
22
  });
48
- function logBrowseCommands() {
49
- console.log(`Commands:
50
- pay browse concourse # browses the concourse page
51
- pay browse help [COMMAND] # Describe subcommands or one specific subcommand
52
- pay browse manual # browses the pay team manual
53
- pay browse repo # browses the pay-infra github repo
54
- pay browse status # browses the pay status page`);
55
- }
56
- exports.logBrowseCommands = logBrowseCommands;
57
- function logNoCommand(argumentName) {
58
- console.error(`Could not find command "${argumentName}".`);
59
- console.log(`The available options are: "${Array.from(requestableItems.keys()).join('", "')}".`);
60
- }
61
- async function browseHandler(options) {
23
+ exports.command = 'browse <location>';
24
+ exports.desc = 'Open a web browser to useful locations';
25
+ const builder = (yargs) => {
26
+ return yargs.positional('location', {
27
+ choices: [...requestableItems.keys()]
28
+ });
29
+ };
30
+ exports.builder = builder;
31
+ exports.handler = browseHandler;
32
+ async function browseHandler(argv) {
33
+ console.log(argv);
62
34
  await (0, standardContent_js_1.showHeader)();
63
- if (options.arguments.length === 0) {
64
- logBrowseCommands();
65
- return;
66
- }
67
- if (options.arguments[0] === 'help') {
68
- const argumentName = options.arguments[1];
69
- if (argumentName === undefined || argumentName.trim() === '') {
70
- logBrowseCommands();
71
- return;
72
- }
73
- const requestedItem = requestableItems.get(argumentName);
74
- if (requestedItem != null) {
75
- console.log('Usage:');
76
- console.log(` npx --package=${path.resolve(constants_1.rootDir)} browse ${argumentName}`);
77
- console.log(`browses the ${requestedItem.name}`);
78
- return;
35
+ const location = argv.location;
36
+ const requestedItem = requestableItems.get(location);
37
+ console.log(`Opening the ${requestedItem.name}`);
38
+ moduleFunctionWrapper_js_1.moduleFunctionWrapper.open(requestedItem.url, (err) => {
39
+ if (err != null) {
40
+ console.log(`Failed to open browser, please visit ${requestedItem.url}`);
79
41
  }
80
- logNoCommand(argumentName);
81
- return;
82
- }
83
- const requestedItem = requestableItems.get(options.arguments[0]);
84
- if (requestedItem != null) {
85
- console.log(`Opening the ${requestedItem.name}`);
86
- moduleFunctionWrapper_js_1.moduleFunctionWrapper.open(requestedItem.url, (err) => {
87
- if (err != null) {
88
- console.log(`Failed to open browser, please visit ${requestedItem.url}`);
89
- }
90
- });
91
- return;
92
- }
93
- logNoCommand(options.arguments[0]);
42
+ });
94
43
  }
95
44
  exports.default = browseHandler;
@@ -5,77 +5,44 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  // import * as open from 'open'
7
7
  const globals_1 = require("@jest/globals");
8
- const moduleFunctionWrapper_js_1 = require("../util/moduleFunctionWrapper.js");
9
- const browse_js_1 = __importDefault(require("./browse.js"));
10
- const commandsText = `Commands:
11
- pay browse concourse # browses the concourse page
12
- pay browse help [COMMAND] # Describe subcommands or one specific subcommand
13
- pay browse manual # browses the pay team manual
14
- pay browse repo # browses the pay-infra github repo
15
- pay browse status # browses the pay status page`;
8
+ const moduleFunctionWrapper_1 = require("../util/moduleFunctionWrapper");
9
+ const browse_1 = __importDefault(require("./browse"));
16
10
  (0, globals_1.describe)('browse command', () => {
17
11
  (0, globals_1.beforeEach)(() => {
18
12
  globals_1.jest.spyOn(console, 'log').mockImplementation(() => { });
19
13
  globals_1.jest.spyOn(console, 'error').mockImplementation(() => { });
20
- globals_1.jest.spyOn(moduleFunctionWrapper_js_1.moduleFunctionWrapper, 'open').mockImplementation(() => { });
14
+ globals_1.jest.spyOn(moduleFunctionWrapper_1.moduleFunctionWrapper, 'open').mockImplementation(() => { });
21
15
  });
22
16
  (0, globals_1.afterEach)(() => {
23
17
  globals_1.jest.restoreAllMocks();
24
18
  globals_1.jest.resetModules();
25
19
  });
26
- (0, globals_1.it)('should show usage when no additional params are provided', async () => {
27
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: [] });
28
- (0, globals_1.expect)(console.log).toHaveBeenCalledWith(commandsText);
29
- });
30
20
  (0, globals_1.it)('should open the browser when manual is provided as the first param', async () => {
31
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['manual'] });
32
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://manual.payments.service.gov.uk/', globals_1.expect.any(Function));
21
+ const argv = { _: ['browse'], $0: 'pay', location: 'manual' };
22
+ await (0, browse_1.default)(argv);
23
+ (0, globals_1.expect)(moduleFunctionWrapper_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://manual.payments.service.gov.uk/', globals_1.expect.any(Function));
33
24
  (0, globals_1.expect)(console.log).toHaveBeenCalledWith('Opening the team manual');
34
25
  (0, globals_1.expect)(console.error).not.toHaveBeenCalled();
35
26
  });
36
27
  (0, globals_1.it)('should open the browser when concourse is provided as the first param', async () => {
37
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['concourse'] });
38
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://pay-cd.deploy.payments.service.gov.uk/', globals_1.expect.any(Function));
28
+ const argv = { _: ['browse'], $0: 'pay', location: 'concourse' };
29
+ await (0, browse_1.default)(argv);
30
+ (0, globals_1.expect)(moduleFunctionWrapper_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://pay-cd.deploy.payments.service.gov.uk/', globals_1.expect.any(Function));
39
31
  (0, globals_1.expect)(console.log).toHaveBeenCalledWith('Opening the concourse page');
40
32
  (0, globals_1.expect)(console.error).not.toHaveBeenCalled();
41
33
  });
42
34
  (0, globals_1.it)('should open the browser when repo is provided as the first param', async () => {
43
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['repo'] });
44
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://github.com/alphagov/pay-infra', globals_1.expect.any(Function));
35
+ const argv = { _: ['browse'], $0: 'pay', location: 'repo' };
36
+ await (0, browse_1.default)(argv);
37
+ (0, globals_1.expect)(moduleFunctionWrapper_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://github.com/alphagov/pay-infra', globals_1.expect.any(Function));
45
38
  (0, globals_1.expect)(console.log).toHaveBeenCalledWith('Opening the pay-infra github repository');
46
39
  (0, globals_1.expect)(console.error).not.toHaveBeenCalled();
47
40
  });
48
41
  (0, globals_1.it)('should open the browser when status is provided as the first param', async () => {
49
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['status'] });
50
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://payments.statuspage.io/', globals_1.expect.any(Function));
42
+ const argv = { _: ['browse'], $0: 'pay', location: 'status' };
43
+ await (0, browse_1.default)(argv);
44
+ (0, globals_1.expect)(moduleFunctionWrapper_1.moduleFunctionWrapper.open).toHaveBeenCalledWith('https://payments.statuspage.io/', globals_1.expect.any(Function));
51
45
  (0, globals_1.expect)(console.log).toHaveBeenCalledWith('Opening the status page');
52
46
  (0, globals_1.expect)(console.error).not.toHaveBeenCalled();
53
47
  });
54
- (0, globals_1.it)('should show the help page when requested', async () => {
55
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['help'] });
56
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).not.toHaveBeenCalled();
57
- (0, globals_1.expect)(console.log).toHaveBeenCalledWith(`Commands:
58
- pay browse concourse # browses the concourse page
59
- pay browse help [COMMAND] # Describe subcommands or one specific subcommand
60
- pay browse manual # browses the pay team manual
61
- pay browse repo # browses the pay-infra github repo
62
- pay browse status # browses the pay status page`);
63
- });
64
- (0, globals_1.it)('should details about a command', async () => {
65
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['help', 'manual'] });
66
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).not.toHaveBeenCalled();
67
- (0, globals_1.expect)(console.log).toHaveBeenCalledWith('Usage:');
68
- (0, globals_1.expect)(console.log).toHaveBeenCalledWith('browses the team manual');
69
- });
70
- (0, globals_1.it)('should handle an unknown command', async () => {
71
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['abcdef'] });
72
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).not.toHaveBeenCalled();
73
- (0, globals_1.expect)(console.error).toHaveBeenCalledWith('Could not find command "abcdef".');
74
- (0, globals_1.expect)(console.log).toHaveBeenCalledWith('The available options are: "concourse", "manual", "repo", "status".');
75
- });
76
- (0, globals_1.it)('should handle an unknown command within help', async () => {
77
- await (0, browse_js_1.default)({ commandName: 'browse', arguments: ['help', 'abcdef'] });
78
- (0, globals_1.expect)(moduleFunctionWrapper_js_1.moduleFunctionWrapper.open).not.toHaveBeenCalled();
79
- (0, globals_1.expect)(console.error).toHaveBeenCalledWith('Could not find command "abcdef".');
80
- });
81
48
  });
@@ -1,6 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- async function demoHandler(options) {
3
+ exports.handler = exports.builder = exports.desc = exports.command = void 0;
4
+ const standardContent_1 = require("../core/standardContent");
5
+ exports.command = 'demo';
6
+ exports.desc = false; // Hide command from generated help
7
+ exports.builder = {};
8
+ exports.handler = demoHandler;
9
+ async function demoHandler(argv) {
10
+ await (0, standardContent_1.showHeader)();
4
11
  console.log('This is where you would put your implementation.');
5
12
  await new Promise((resolve) => {
6
13
  setTimeout(resolve, 10);
@@ -8,4 +15,3 @@ async function demoHandler(options) {
8
15
  console.log('It can be asynchronous.');
9
16
  console.error('You can also write to stderr.');
10
17
  }
11
- exports.default = demoHandler;
@@ -23,25 +23,25 @@ var __importStar = (this && this.__importStar) || function (mod) {
23
23
  return result;
24
24
  };
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.proxyHandlerOptionsToLegacyCli = exports.proxyArrayOfArgumentsToLegacyCli = void 0;
26
+ exports.proxyArrayOfArgumentsToLegacyCli = exports.handler = exports.builder = exports.desc = exports.command = void 0;
27
27
  const payCliExec_1 = __importStar(require("../util/payCliExec"));
28
28
  const path = __importStar(require("node:path"));
29
29
  const constants_1 = require("../core/constants");
30
- const standardContent_1 = require("../core/standardContent");
31
30
  const pathToLegacyRubyCli = path.join(constants_1.rootDir, 'resources', 'legacy-ruby-cli');
32
- async function legacyHandler(options) {
33
- const argsToPassOn = [];
34
- if (options.commandName !== 'legacy') {
35
- argsToPassOn.unshift(options.commandName);
36
- }
37
- options.arguments.forEach((arg) => {
38
- argsToPassOn.push(arg);
39
- });
31
+ exports.command = 'legacy';
32
+ exports.desc = 'Pass through to legacy ruby cli';
33
+ const commandDesc = '$0 legacy -- {ruby version command and options}';
34
+ const longDesc = 'Use the legacy ruby version of the pay cli, passing through commands, options etc. The legacy command itself should be followed by `--` then the command from the ruby version followed by it\'s parameters and options. e.g. use `pay legacy -- help` to run help on the legacy version.';
35
+ const builder = (yargs) => {
36
+ return yargs.usage(`${commandDesc}\n\n${longDesc}`);
37
+ };
38
+ exports.builder = builder;
39
+ exports.handler = legacyHandler;
40
+ async function legacyHandler(argv) {
41
+ const argsToPassOn = argv._.slice(1);
40
42
  await proxyArrayOfArgumentsToLegacyCli(argsToPassOn);
41
43
  }
42
- exports.default = legacyHandler;
43
44
  async function proxyArrayOfArgumentsToLegacyCli(argsToPassOn) {
44
- await (0, standardContent_1.showHeader)();
45
45
  const rbenvCommand = process.env.PAY_CLI_RBENV_COMMAND ?? 'rbenv';
46
46
  const shellCommand = process.env.PAY_CLI_SHELL_COMMAND ?? 'zsh';
47
47
  const whichRbenvResult = await (0, payCliExec_1.execAndReturnIO)(`which ${rbenvCommand}`);
@@ -67,7 +67,3 @@ async function proxyArrayOfArgumentsToLegacyCli(argsToPassOn) {
67
67
  });
68
68
  }
69
69
  exports.proxyArrayOfArgumentsToLegacyCli = proxyArrayOfArgumentsToLegacyCli;
70
- async function proxyHandlerOptionsToLegacyCli(options) {
71
- await proxyArrayOfArgumentsToLegacyCli([options.commandName].concat(options.arguments));
72
- }
73
- exports.proxyHandlerOptionsToLegacyCli = proxyHandlerOptionsToLegacyCli;
@@ -0,0 +1,232 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const node_crypto_1 = __importDefault(require("node:crypto"));
7
+ const fetch_wrapper_1 = require("./fetch_wrapper");
8
+ const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
9
+ let SERVICES_CONFIG;
10
+ const appClient = {
11
+ async createPaymentLink(apiKey) {
12
+ const paymentLinkData = {
13
+ pay_api_token: apiKey,
14
+ name: 'exampleName',
15
+ price: 100,
16
+ gateway_account_id: '1',
17
+ return_url: 'https://test.test/some_reference',
18
+ service_name: 'aServiceName',
19
+ type: 'ADHOC',
20
+ service_name_path: 'aServiceNamePath',
21
+ product_name_path: node_crypto_1.default.randomBytes(16).toString('hex'),
22
+ reference_enabled: false
23
+ };
24
+ const url = urlFor('products', '/v1/api/products/');
25
+ const result = await (0, fetch_wrapper_1.postRequest)(url, paymentLinkData);
26
+ if (!result.success) {
27
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
28
+ return;
29
+ }
30
+ const body = result.successfulResult?.body;
31
+ if (body === undefined || typeof body === 'string') {
32
+ console.error('The response to a request payment links did not have a body, or the body was not JSON!');
33
+ return;
34
+ }
35
+ if (!Object.hasOwn(body, '_links')) {
36
+ console.error('The response to create a payment link did not include an _links property');
37
+ return;
38
+ }
39
+ const typedBody = body;
40
+ return typedBody._links;
41
+ },
42
+ async createService() {
43
+ const createServiceData = {
44
+ en: 'My service',
45
+ cy: 'Welsh name for My service'
46
+ };
47
+ const url = urlFor('adminusers', '/v1/api/services');
48
+ const result = await (0, fetch_wrapper_1.postRequest)(url, createServiceData);
49
+ if (!result.success) {
50
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
51
+ return;
52
+ }
53
+ const body = result.successfulResult?.body;
54
+ if (body === undefined || typeof body === 'string') {
55
+ console.error('The response to a create a service did not have a body, or the body was not JSON!');
56
+ return;
57
+ }
58
+ if (!Object.hasOwn(body, 'external_id')) {
59
+ console.error('The response to create a service did not include an external_id property');
60
+ return;
61
+ }
62
+ const typedBody = body;
63
+ return typedBody.external_id;
64
+ },
65
+ async createAccountInServiceWithEmailCollectionMode(serviceExternalID, emailCollectionMode) {
66
+ const account = await appClient.createAccount(serviceExternalID);
67
+ if (account === undefined) {
68
+ console.error('Failed to create account');
69
+ return;
70
+ }
71
+ if (!await appClient.setEmailCollectionModeOnAccount(account.gateway_account_id, emailCollectionMode)) {
72
+ console.error('Failed to set email collection mode on gateway account');
73
+ return;
74
+ }
75
+ if (!await appClient.addGatewayAccountToService(account.gateway_account_id, serviceExternalID)) {
76
+ console.error('Failed to add the gateway account to the service');
77
+ return;
78
+ }
79
+ return account;
80
+ },
81
+ async createAccount(serviceID) {
82
+ const createAccountData = {
83
+ payment_provider: 'sandbox',
84
+ service_name: 'My service',
85
+ type: 'test',
86
+ service_id: serviceID
87
+ };
88
+ const url = urlFor('connector', '/v1/api/accounts');
89
+ const result = await (0, fetch_wrapper_1.postRequest)(url, createAccountData);
90
+ if (!result.success) {
91
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
92
+ return;
93
+ }
94
+ const body = result.successfulResult?.body;
95
+ if (body === undefined || typeof body === 'string') {
96
+ console.error('The response to a create an account did not have a body, or the body was not JSON!');
97
+ return;
98
+ }
99
+ const typedBody = body;
100
+ return typedBody;
101
+ },
102
+ async setEmailCollectionModeOnAccount(accountID, emailCollectionMode) {
103
+ const patchEmailCollectionModeData = {
104
+ op: 'replace',
105
+ path: 'email_collection_mode',
106
+ value: emailCollectionMode
107
+ };
108
+ const url = urlFor('connector', `/v1/api/accounts/${accountID}`);
109
+ const result = await (0, fetch_wrapper_1.patchRequest)(url, patchEmailCollectionModeData);
110
+ if (!result.success) {
111
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
112
+ return false;
113
+ }
114
+ return true;
115
+ },
116
+ async addGatewayAccountToService(accountID, serviceID) {
117
+ const patchAddGatewayAccountToServiceData = {
118
+ op: 'add',
119
+ path: 'gateway_account_ids',
120
+ value: [accountID]
121
+ };
122
+ const url = urlFor('adminusers', `/v1/api/services/${serviceID}`);
123
+ const result = await (0, fetch_wrapper_1.patchRequest)(url, patchAddGatewayAccountToServiceData);
124
+ if (!result.success) {
125
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
126
+ return false;
127
+ }
128
+ return true;
129
+ },
130
+ async createToken(gatewayAccountID) {
131
+ const createTokenData = {
132
+ account_id: gatewayAccountID,
133
+ description: 'my token',
134
+ created_by: 'system generated',
135
+ token_type: 'CARD'
136
+ };
137
+ const url = urlFor('publicauth', '/v1/frontend/auth');
138
+ const result = await (0, fetch_wrapper_1.postRequest)(url, createTokenData);
139
+ if (!result.success) {
140
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
141
+ return;
142
+ }
143
+ const body = result.successfulResult?.body;
144
+ if (body === undefined || typeof body === 'string') {
145
+ console.error('The response to a create a token did not have a body, or the body was not JSON!');
146
+ return;
147
+ }
148
+ const typedBody = body;
149
+ return typedBody.token;
150
+ },
151
+ async createPayment(apiToken) {
152
+ const createPaymentData = {
153
+ amount: 1000,
154
+ description: 'my payment',
155
+ reference: 'my payment reference',
156
+ return_url: new URL('https://www.payments.service.gov.uk')
157
+ };
158
+ const url = urlFor('publicapi', '/v1/payments');
159
+ const result = await (0, fetch_wrapper_1.postRequest)(url, createPaymentData, apiToken);
160
+ if (!result.success) {
161
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
162
+ return;
163
+ }
164
+ const body = result.successfulResult?.body;
165
+ if (body === undefined || typeof body === 'string') {
166
+ console.error('The response to a create a payment did not have a body, or the body was not JSON!');
167
+ return;
168
+ }
169
+ return body;
170
+ },
171
+ async createUser(gatewayAccountIDs, roleName) {
172
+ const createUserData = {
173
+ gateway_account_ids: gatewayAccountIDs,
174
+ email: `${node_crypto_1.default.randomBytes(16).toString('hex')}@example.com`,
175
+ password: `${node_crypto_1.default.randomBytes(10).toString('hex')}`,
176
+ telephone_number: '01134960000',
177
+ role_name: roleName
178
+ };
179
+ const url = urlFor('adminusers', '/v1/api/users');
180
+ const result = await (0, fetch_wrapper_1.postRequest)(url, createUserData);
181
+ if (!result.success) {
182
+ console.error((0, fetch_wrapper_1.formatErrorMessageForFailedRequest)(result.unsuccessfulResult));
183
+ return;
184
+ }
185
+ const body = result.successfulResult?.body;
186
+ if (body === undefined || typeof body === 'string') {
187
+ console.error('The response to a create a user did not have a body, or the body was not JSON!');
188
+ return;
189
+ }
190
+ const typedAugmentedBody = {
191
+ ...createUserData,
192
+ ...body
193
+ };
194
+ return typedAugmentedBody;
195
+ },
196
+ async isHealthy(serviceName) {
197
+ const url = urlFor(serviceName, '/healthcheck');
198
+ const response = await (0, fetch_wrapper_1.getRequest)(url);
199
+ return response.success;
200
+ },
201
+ async isUnhealthy(serviceName) {
202
+ return !await this.isHealthy(serviceName);
203
+ },
204
+ async isProxyHealthy(serviceName) {
205
+ const proxyUrl = this.externalUrlFor(serviceName, '/healthcheck', true);
206
+ const response = await (0, fetch_wrapper_1.getRequest)(proxyUrl);
207
+ return response.success;
208
+ },
209
+ externalUrlFor(serviceName, resource, proxy) {
210
+ if (SERVICES_CONFIG === undefined) {
211
+ SERVICES_CONFIG = (0, pay_local_cluster_js_1.loadServicesConfig)();
212
+ }
213
+ if (!(serviceName in SERVICES_CONFIG)) {
214
+ throw new Error(`Tried to look up service config for ${serviceName} but it isn't defined in the service_config.yaml file`);
215
+ }
216
+ const proxyPort = SERVICES_CONFIG[serviceName].proxy_port;
217
+ if (proxy && proxyPort !== undefined) {
218
+ return `https://127.0.0.1:${proxyPort}${resource}`;
219
+ }
220
+ return `http://127.0.0.1:${SERVICES_CONFIG[serviceName].port}${resource}`;
221
+ }
222
+ };
223
+ function urlFor(serviceName, resource) {
224
+ if (SERVICES_CONFIG === undefined) {
225
+ SERVICES_CONFIG = (0, pay_local_cluster_js_1.loadServicesConfig)();
226
+ }
227
+ if (!(serviceName in SERVICES_CONFIG)) {
228
+ throw new Error(`Tried to look up service config for ${serviceName} but it isn't defined in the service_config.yaml file`);
229
+ }
230
+ return appClient.externalUrlFor(serviceName, resource, false);
231
+ }
232
+ exports.default = appClient;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatErrorMessageForFailedRequest = exports.patchRequest = exports.postRequest = exports.getRequest = void 0;
4
+ async function getRequest(url, authToken) {
5
+ return await makeRequest(url, { headers: defaultHeaders(authToken) });
6
+ }
7
+ exports.getRequest = getRequest;
8
+ async function postRequest(url, body, authToken) {
9
+ return await makeRequest(url, {
10
+ method: 'POST',
11
+ body: JSON.stringify(body),
12
+ headers: defaultHeaders(authToken)
13
+ });
14
+ }
15
+ exports.postRequest = postRequest;
16
+ async function patchRequest(url, body, authToken) {
17
+ return await makeRequest(url, {
18
+ method: 'PATCH',
19
+ body: JSON.stringify(body),
20
+ headers: defaultHeaders(authToken)
21
+ });
22
+ }
23
+ exports.patchRequest = patchRequest;
24
+ function formatErrorMessageForFailedRequest(unsuccessfulResult) {
25
+ if (unsuccessfulResult === undefined) {
26
+ return 'The result was successful';
27
+ }
28
+ let errorMessage = '';
29
+ if (unsuccessfulResult.error !== null && unsuccessfulResult.error !== undefined) {
30
+ errorMessage = unsuccessfulResult.error.message;
31
+ }
32
+ if (unsuccessfulResult.response === undefined) {
33
+ return `No response was received from the server, the following error was thrown:\n${errorMessage}`;
34
+ }
35
+ else {
36
+ if (unsuccessfulResult.error === undefined) {
37
+ return 'The server returned a non-ok HTTP response, no other error was thrown\n' +
38
+ `Response Code: ${unsuccessfulResult.response?.status}\n` +
39
+ `Response Text: ${unsuccessfulResult.response?.statusText}`;
40
+ }
41
+ else {
42
+ return 'A response was recevied from the server, but an error was also thrown.\n' +
43
+ `Error: ${errorMessage}` +
44
+ `Response Code: ${unsuccessfulResult?.response?.status}\n` +
45
+ `Response Text: ${unsuccessfulResult?.response?.statusText}`;
46
+ }
47
+ }
48
+ }
49
+ exports.formatErrorMessageForFailedRequest = formatErrorMessageForFailedRequest;
50
+ /**
51
+ * The error handling around requests is absymal, so we'll catch all possible errors and return a result with a
52
+ * concrete type which is easier for clients to understand and deal with, containing the complexity to only this
53
+ * function
54
+ */
55
+ async function makeRequest(url, requestOptions) {
56
+ let response;
57
+ try {
58
+ response = await fetch(url, requestOptions);
59
+ if (!response.ok) {
60
+ return {
61
+ success: false,
62
+ unsuccessfulResult: {
63
+ response
64
+ }
65
+ };
66
+ }
67
+ }
68
+ catch (error) {
69
+ return {
70
+ success: false,
71
+ unsuccessfulResult: {
72
+ error
73
+ }
74
+ };
75
+ }
76
+ try {
77
+ const rawBody = await response.text();
78
+ const jsonResponse = response.headers.get('Content-Type') === 'application/json';
79
+ return {
80
+ success: true,
81
+ successfulResult: {
82
+ response,
83
+ body: jsonResponse ? await JSON.parse(rawBody) : rawBody
84
+ }
85
+ };
86
+ }
87
+ catch (error) {
88
+ return {
89
+ success: false,
90
+ unsuccessfulResult: {
91
+ response,
92
+ error
93
+ }
94
+ };
95
+ }
96
+ }
97
+ function defaultHeaders(authToken) {
98
+ const headers = new Headers({
99
+ 'Content-Type': 'application/json',
100
+ Accept: 'application/json'
101
+ });
102
+ if (authToken !== undefined) {
103
+ headers.set('Authorization', `Bearer ${authToken}`);
104
+ }
105
+ return headers;
106
+ }