@govuk-pay/cli 0.0.31 → 0.0.32
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 +1 -2
- package/resources/pay-local/templates/docker-compose.hbs +1 -1
- package/src/commands/local/app_client/app_client.js +232 -0
- package/src/commands/local/app_client/fetch_wrapper.js +106 -0
- package/src/commands/local/config/pay_local_cluster.js +8 -4
- package/src/commands/local/subcommands/account.js +51 -0
- package/src/commands/local/subcommands/browse.js +39 -0
- package/src/commands/local/subcommands/db.js +82 -0
- package/src/commands/local/subcommands/payment.js +68 -0
- package/src/commands/local/subcommands/paymentlink.js +41 -0
- package/src/commands/local/subcommands/token.js +66 -0
- package/src/commands/local/subcommands/up.js +2 -2
- package/src/commands/local/subcommands/url.js +44 -0
- package/src/commands/local/subcommands/user.js +91 -0
- package/src/commands/local.js +56 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@govuk-pay/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.32",
|
|
4
4
|
"description": "GOV.UK Pay Command Line Interface",
|
|
5
5
|
"bin": {
|
|
6
6
|
"pay": "bin/cli.js",
|
|
@@ -22,7 +22,6 @@
|
|
|
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
25
|
"yaml": "^2.5.1"
|
|
27
26
|
},
|
|
28
27
|
"files": [
|
|
@@ -178,7 +178,7 @@ services:
|
|
|
178
178
|
{{#ifBoth localBuild entrypointOverrideLocal}}
|
|
179
179
|
entrypoint: {{{../entrypointOverrideLocal}}}
|
|
180
180
|
{{else}}
|
|
181
|
-
entrypoint: "npx nodemon --inspect=0.0.0.0:{{../debugPort}}
|
|
181
|
+
entrypoint: "npx nodemon --inspect=0.0.0.0:{{../debugPort}}"
|
|
182
182
|
{{/ifBoth}}
|
|
183
183
|
ports:
|
|
184
184
|
- "{{port}}:{{port}}"
|
|
@@ -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
|
+
}
|
|
@@ -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.loadClusterConfig = exports.PayLocalCluster = void 0;
|
|
6
|
+
exports.loadServicesConfig = exports.loadClusterConfig = exports.PayLocalCluster = void 0;
|
|
7
7
|
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
8
|
const node_path_1 = __importDefault(require("node:path"));
|
|
9
9
|
const yaml_1 = __importDefault(require("yaml"));
|
|
@@ -89,9 +89,7 @@ var PayServiceType;
|
|
|
89
89
|
PayServiceType["Node"] = "node";
|
|
90
90
|
})(PayServiceType || (PayServiceType = {}));
|
|
91
91
|
function loadClusterConfig(options, workspace, defaultServiceConfigsPath, environmentOverridesPath) {
|
|
92
|
-
const
|
|
93
|
-
const serviceConfigFileContents = node_fs_1.default.readFileSync(servicesConfigPath, 'utf8');
|
|
94
|
-
const servicesConfig = yaml_1.default.parse(serviceConfigFileContents);
|
|
92
|
+
const servicesConfig = loadServicesConfig();
|
|
95
93
|
const payServices = [];
|
|
96
94
|
for (const [, serviceConfig] of Object.entries(servicesConfig)) {
|
|
97
95
|
if (includeAppInCluster(options.cluster, options, serviceConfig)) {
|
|
@@ -125,6 +123,12 @@ function loadClusterConfig(options, workspace, defaultServiceConfigsPath, enviro
|
|
|
125
123
|
return new PayLocalCluster(clusterConfig);
|
|
126
124
|
}
|
|
127
125
|
exports.loadClusterConfig = loadClusterConfig;
|
|
126
|
+
function loadServicesConfig() {
|
|
127
|
+
const servicesConfigPath = node_path_1.default.join(__dirname, '..', '..', '..', '..', 'resources', 'pay-local', 'config', 'service_config.yaml');
|
|
128
|
+
const serviceConfigFileContents = node_fs_1.default.readFileSync(servicesConfigPath, 'utf8');
|
|
129
|
+
return yaml_1.default.parse(serviceConfigFileContents);
|
|
130
|
+
}
|
|
131
|
+
exports.loadServicesConfig = loadServicesConfig;
|
|
128
132
|
function includeAppInCluster(cluster, options, serviceConfig) {
|
|
129
133
|
if (cluster === 'all' || cluster === 'nuke' || serviceConfig.clusters.includes(cluster)) {
|
|
130
134
|
if (options.apps.length === 0 || options.apps.includes(serviceConfig.name)) {
|
|
@@ -0,0 +1,51 @@
|
|
|
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 app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
7
|
+
async function AccountHandler(options) {
|
|
8
|
+
const args = parseArguments(options);
|
|
9
|
+
if (await app_client_js_1.default.isUnhealthy('adminusers')) {
|
|
10
|
+
console.error('The adminusers service is unhealthy, so an account cannot be created');
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
if (await app_client_js_1.default.isUnhealthy('connector')) {
|
|
14
|
+
console.error('The connector service is unhealthy, so an account cannot be created');
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
let serviceExternalID;
|
|
18
|
+
if (args.serviceID === undefined) {
|
|
19
|
+
serviceExternalID = await app_client_js_1.default.createService();
|
|
20
|
+
if (serviceExternalID === undefined) {
|
|
21
|
+
console.error('Service creation failed');
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
serviceExternalID = args.serviceID;
|
|
27
|
+
}
|
|
28
|
+
if (serviceExternalID === undefined) {
|
|
29
|
+
throw new Error('Service external ID is undefined, this should be impossible');
|
|
30
|
+
}
|
|
31
|
+
const account = await app_client_js_1.default.createAccountInServiceWithEmailCollectionMode(serviceExternalID, 'MANDATORY');
|
|
32
|
+
if (account === undefined) {
|
|
33
|
+
console.error('Failed to create a fully set up account');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
console.log(account);
|
|
37
|
+
}
|
|
38
|
+
exports.default = AccountHandler;
|
|
39
|
+
function parseArguments(options) {
|
|
40
|
+
if (options.length === 0) {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
if (options.length > 1) {
|
|
44
|
+
help();
|
|
45
|
+
throw new Error('Too many arguments');
|
|
46
|
+
}
|
|
47
|
+
return { serviceID: options[0] };
|
|
48
|
+
}
|
|
49
|
+
function help() {
|
|
50
|
+
console.log('Usage: pay local account [service_id]>');
|
|
51
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
+
const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
8
|
+
const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
|
|
9
|
+
async function BrowseHandler(options) {
|
|
10
|
+
const args = parseArguments(options);
|
|
11
|
+
const servicesConfig = (0, pay_local_cluster_js_1.loadServicesConfig)();
|
|
12
|
+
if (!(args.service in servicesConfig)) {
|
|
13
|
+
console.error(`The service specified (${args.service}) was not defined in the service_config.yaml file`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const serviceConfig = servicesConfig[args.service];
|
|
17
|
+
const url = app_client_js_1.default.externalUrlFor(args.service, '/', args.proxy);
|
|
18
|
+
(0, node_child_process_1.spawn)('open', [url]);
|
|
19
|
+
if (await app_client_js_1.default.isHealthy(serviceConfig.name)) {
|
|
20
|
+
console.log(`📋 “${url}” opened`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.error(`❌ “${url}” opened, however the app did not respond successfully to ${url}/healthcheck`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = BrowseHandler;
|
|
27
|
+
function help() {
|
|
28
|
+
console.log('Usage: pay local browse <service>');
|
|
29
|
+
}
|
|
30
|
+
function parseArguments(options) {
|
|
31
|
+
if (options.length !== 1) {
|
|
32
|
+
help();
|
|
33
|
+
throw new Error('No service specified');
|
|
34
|
+
}
|
|
35
|
+
return {
|
|
36
|
+
service: options[0],
|
|
37
|
+
proxy: true
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const node_child_process_1 = require("node:child_process");
|
|
4
|
+
const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
|
|
5
|
+
async function DBHandler(options) {
|
|
6
|
+
const args = parseArguments(options);
|
|
7
|
+
const servicesConfig = (0, pay_local_cluster_js_1.loadServicesConfig)();
|
|
8
|
+
if (!(args.service in servicesConfig)) {
|
|
9
|
+
console.error(`The service specified (${args.service}) was not defined in the service_config.yaml file`);
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
const serviceConfig = servicesConfig[args.service];
|
|
13
|
+
if (!serviceConfig.db) {
|
|
14
|
+
console.error(`The service specified (${serviceConfig.name}) does not have a database`);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (args.docker) {
|
|
18
|
+
launchPsqlInDocker(serviceConfig);
|
|
19
|
+
}
|
|
20
|
+
else if (!psqlAvailable()) {
|
|
21
|
+
console.warn('PSQL installation not found locally.');
|
|
22
|
+
launchPsqlInDocker(serviceConfig);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
launchPsql(serviceConfig);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.default = DBHandler;
|
|
29
|
+
function psqlAvailable() {
|
|
30
|
+
const psqlCheck = (0, node_child_process_1.spawnSync)('command', ['-v', 'psql'], { shell: true });
|
|
31
|
+
if (psqlCheck.status === 0) {
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
function launchPsqlInDocker(serviceConfig) {
|
|
37
|
+
console.log('Running psql in running app db container.');
|
|
38
|
+
console.log('Note: This means you wont have a psql history, and one will not survive restarts of pay local');
|
|
39
|
+
(0, node_child_process_1.spawn)('docker', [
|
|
40
|
+
'exec',
|
|
41
|
+
'-e', 'PGPASSWORD=mysecretpassword', // pragma: allowlist secret
|
|
42
|
+
'-e', 'PGSSLMODE=disable',
|
|
43
|
+
'-ti',
|
|
44
|
+
`${serviceConfig.name}_db`,
|
|
45
|
+
'psql',
|
|
46
|
+
'--host', `${serviceConfig.name}_db`,
|
|
47
|
+
'--user', serviceConfig.name,
|
|
48
|
+
'--dbname', serviceConfig.name
|
|
49
|
+
], { stdio: 'inherit', shell: true });
|
|
50
|
+
}
|
|
51
|
+
function launchPsql(serviceConfig) {
|
|
52
|
+
if (serviceConfig.db_port === undefined) {
|
|
53
|
+
throw new Error(`Service config for ${serviceConfig.name} is missing db_port specification`);
|
|
54
|
+
}
|
|
55
|
+
(0, node_child_process_1.spawn)('psql', [
|
|
56
|
+
'--host', '127.0.0.1',
|
|
57
|
+
'--port', `${serviceConfig.db_port}`,
|
|
58
|
+
'--user', serviceConfig.name,
|
|
59
|
+
'--dbname', serviceConfig.name
|
|
60
|
+
], {
|
|
61
|
+
stdio: 'inherit',
|
|
62
|
+
shell: true,
|
|
63
|
+
env: {
|
|
64
|
+
...process.env,
|
|
65
|
+
PGPASSWORD: 'mysecretpassword', // pragma: allowlist secret
|
|
66
|
+
PGSSLMODE: 'disable'
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function help() {
|
|
71
|
+
console.log('Usage: pay local db <service> [--docker]');
|
|
72
|
+
}
|
|
73
|
+
function parseArguments(options) {
|
|
74
|
+
if (options.length !== 1) {
|
|
75
|
+
help();
|
|
76
|
+
throw new Error('No service specified');
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
service: options[0],
|
|
80
|
+
docker: false
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
+
const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
8
|
+
async function PaymentHandler(options) {
|
|
9
|
+
const args = parseArguments(options);
|
|
10
|
+
if (await app_client_js_1.default.isUnhealthy('connector')) {
|
|
11
|
+
console.error('The connector service is unhealthy, so a payment cannot be created');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (await app_client_js_1.default.isUnhealthy('publicapi')) {
|
|
15
|
+
console.error('The publicapi service is unhealthy, so a payment cannot be created');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
let apiKey;
|
|
19
|
+
if (args.api_key === undefined) {
|
|
20
|
+
console.warn('👔 Creating gateway account and service');
|
|
21
|
+
console.warn();
|
|
22
|
+
if (await app_client_js_1.default.isUnhealthy('adminusers')) {
|
|
23
|
+
console.error('The adminusers service is unhealthy, so a gateway account cannot be created to enable a payment to be created');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const serviceExternalID = await app_client_js_1.default.createService();
|
|
27
|
+
if (serviceExternalID === undefined) {
|
|
28
|
+
console.error('Unable to create a service');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const account = await app_client_js_1.default.createAccountInServiceWithEmailCollectionMode(serviceExternalID, args.email_collection_mode === undefined ? 'MANDATORY' : args.email_collection_mode);
|
|
32
|
+
if (account === undefined) {
|
|
33
|
+
console.error('Failed to create a fully set up account');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const createTokenResult = await app_client_js_1.default.createToken(account.gateway_account_id);
|
|
37
|
+
if (createTokenResult === undefined) {
|
|
38
|
+
console.error('Failed to create an api token');
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
apiKey = createTokenResult;
|
|
42
|
+
console.warn(`🆔 Gateway account ID: ${account.gateway_account_id}`);
|
|
43
|
+
console.warn(`💁 Service ID: ${serviceExternalID}`);
|
|
44
|
+
console.warn();
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
apiKey = args.api_key;
|
|
48
|
+
}
|
|
49
|
+
const createPaymentResult = await app_client_js_1.default.createPayment(apiKey);
|
|
50
|
+
if (createPaymentResult === undefined) {
|
|
51
|
+
console.error('Failed to create a payment');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.warn(`💷 Payment ID: ${createPaymentResult.payment_id}`);
|
|
55
|
+
console.warn(`🎫 API token: ${apiKey}`);
|
|
56
|
+
console.warn();
|
|
57
|
+
const nextUrl = createPaymentResult._links.next_url?.href;
|
|
58
|
+
if (nextUrl === undefined) {
|
|
59
|
+
console.error('The response from creating the payment did not include a next_url link');
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
console.log(`Opening next_url (${nextUrl} in your browser`);
|
|
63
|
+
(0, node_child_process_1.spawn)('open', [nextUrl]);
|
|
64
|
+
}
|
|
65
|
+
exports.default = PaymentHandler;
|
|
66
|
+
function parseArguments(_options) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
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_child_process_1 = __importDefault(require("node:child_process"));
|
|
7
|
+
const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
8
|
+
async function PaymentLinkHandler(options) {
|
|
9
|
+
const args = parseArguments(options);
|
|
10
|
+
if (await app_client_js_1.default.isUnhealthy('products')) {
|
|
11
|
+
console.error('The products service is unhealthy, so a payment link cannot be created');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
else if (await app_client_js_1.default.isUnhealthy('products-ui')) {
|
|
15
|
+
console.error('The products-ui service is unhealthy, so a payment link cannot be created');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const paymentLinks = await app_client_js_1.default.createPaymentLink(args.apiKey);
|
|
19
|
+
if (paymentLinks === undefined) {
|
|
20
|
+
console.error('Payment link creation failed');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
paymentLinks.forEach((link) => { console.log(`${link.method} ${link.rel}: ${link.href}`); });
|
|
24
|
+
const payLink = paymentLinks.find((link) => link.rel === 'pay');
|
|
25
|
+
if (payLink === undefined) {
|
|
26
|
+
console.error('The response to create a payment link did not include a link with the rel of "pay"');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
node_child_process_1.default.spawn('open', [payLink.href]);
|
|
30
|
+
}
|
|
31
|
+
exports.default = PaymentLinkHandler;
|
|
32
|
+
function parseArguments(options) {
|
|
33
|
+
if (options.length !== 1) {
|
|
34
|
+
help();
|
|
35
|
+
throw new Error('No key specified');
|
|
36
|
+
}
|
|
37
|
+
return { apiKey: options[0].trimEnd() };
|
|
38
|
+
}
|
|
39
|
+
function help() {
|
|
40
|
+
console.log('Usage: pay local paymentlink <api_key>');
|
|
41
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
+
const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
8
|
+
async function TokenHandler(options) {
|
|
9
|
+
const args = parseArguments(options);
|
|
10
|
+
if (await app_client_js_1.default.isUnhealthy('publicauth')) {
|
|
11
|
+
console.error('The publicauth service is unhealthy, so an API token cannot be created');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
let gatewayAccountID;
|
|
15
|
+
if (args.gatewayAccountID === undefined) {
|
|
16
|
+
console.log('No gateway_account_id provided, creating service and gateway account');
|
|
17
|
+
if (await app_client_js_1.default.isUnhealthy('adminusers')) {
|
|
18
|
+
console.error('The adminusers service is unhealthy, so an API token cannot be created');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
if (await app_client_js_1.default.isUnhealthy('connector')) {
|
|
22
|
+
console.error('The connector service is unhealthy, so an API token cannot be created');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const serviceExternalID = await app_client_js_1.default.createService();
|
|
26
|
+
if (serviceExternalID === undefined) {
|
|
27
|
+
console.error('Service creation failed');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const account = await app_client_js_1.default.createAccountInServiceWithEmailCollectionMode(serviceExternalID, 'MANDATORY');
|
|
31
|
+
if (account === undefined) {
|
|
32
|
+
console.error('Failed to create a fully set up account');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
gatewayAccountID = account.gateway_account_id;
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
gatewayAccountID = args.gatewayAccountID;
|
|
39
|
+
}
|
|
40
|
+
const token = await app_client_js_1.default.createToken(gatewayAccountID);
|
|
41
|
+
if (token === undefined) {
|
|
42
|
+
console.error('Failed to create an API token');
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
copyToClipboard(token);
|
|
46
|
+
console.log(`📋 API token “${token}” copied to clipboard`);
|
|
47
|
+
}
|
|
48
|
+
exports.default = TokenHandler;
|
|
49
|
+
function parseArguments(options) {
|
|
50
|
+
if (options.length === 0) {
|
|
51
|
+
return {};
|
|
52
|
+
}
|
|
53
|
+
if (options.length > 1) {
|
|
54
|
+
help();
|
|
55
|
+
throw new Error('Too many arguments');
|
|
56
|
+
}
|
|
57
|
+
return { gatewayAccountID: options[0] };
|
|
58
|
+
}
|
|
59
|
+
function copyToClipboard(token) {
|
|
60
|
+
const proc = (0, node_child_process_1.spawn)('pbcopy');
|
|
61
|
+
proc.stdin.write(token);
|
|
62
|
+
proc.stdin.end();
|
|
63
|
+
}
|
|
64
|
+
function help() {
|
|
65
|
+
console.log('Usage: pay local token [gateway_account_id]>');
|
|
66
|
+
}
|
|
@@ -43,9 +43,9 @@ async function UpHandler(options, onlyWriteConfig = false) {
|
|
|
43
43
|
exports.default = UpHandler;
|
|
44
44
|
function parseArguments(_options) {
|
|
45
45
|
return {
|
|
46
|
-
cluster: '
|
|
46
|
+
cluster: 'all',
|
|
47
47
|
apps: [],
|
|
48
|
-
local: ['cardid', 'frontend'],
|
|
48
|
+
local: [], // ['cardid', 'frontend'],
|
|
49
49
|
proxy: true,
|
|
50
50
|
with_egress_proxy: false,
|
|
51
51
|
rebuild: true,
|
|
@@ -0,0 +1,44 @@
|
|
|
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_child_process_1 = require("node:child_process");
|
|
7
|
+
const app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
8
|
+
const pay_local_cluster_js_1 = require("../config/pay_local_cluster.js");
|
|
9
|
+
async function URLHandler(options) {
|
|
10
|
+
const args = parseArguments(options);
|
|
11
|
+
const servicesConfig = (0, pay_local_cluster_js_1.loadServicesConfig)();
|
|
12
|
+
if (!(args.service in servicesConfig)) {
|
|
13
|
+
console.error(`The service specified (${args.service}) was not defined in the service_config.yaml file`);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const serviceConfig = servicesConfig[args.service];
|
|
17
|
+
const url = app_client_js_1.default.externalUrlFor(args.service, '/', args.proxy);
|
|
18
|
+
copyToClipboard(url);
|
|
19
|
+
if (await app_client_js_1.default.isHealthy(serviceConfig.name)) {
|
|
20
|
+
console.log(`📋 “${url}” copied to clipboard`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
console.error(`❌ “${url}” copied to clipboard, however the app did not respond successfully to ${url}/healthcheck`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
exports.default = URLHandler;
|
|
27
|
+
function copyToClipboard(url) {
|
|
28
|
+
const proc = (0, node_child_process_1.spawn)('pbcopy');
|
|
29
|
+
proc.stdin.write(url);
|
|
30
|
+
proc.stdin.end();
|
|
31
|
+
}
|
|
32
|
+
function help() {
|
|
33
|
+
console.log('Usage: pay local url <service>');
|
|
34
|
+
}
|
|
35
|
+
function parseArguments(options) {
|
|
36
|
+
if (options.length !== 1) {
|
|
37
|
+
help();
|
|
38
|
+
throw new Error('No service specified');
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
service: options[0],
|
|
42
|
+
proxy: false
|
|
43
|
+
};
|
|
44
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
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 app_client_js_1 = __importDefault(require("../app_client/app_client.js"));
|
|
7
|
+
const totp_generator_1 = require("totp-generator");
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
async function UserHandler(options) {
|
|
10
|
+
const args = parseArguments(options);
|
|
11
|
+
if (await app_client_js_1.default.isUnhealthy('adminusers')) {
|
|
12
|
+
console.error('The adminusers service is unhealthy, so a user cannot be created');
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
if (await app_client_js_1.default.isUnhealthy('connector')) {
|
|
16
|
+
console.error('The connector service is unhealthy, so a user cannot be created');
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
console.warn('Creating card gateway account and API token');
|
|
20
|
+
const serviceExternalID = await app_client_js_1.default.createService();
|
|
21
|
+
if (serviceExternalID === undefined) {
|
|
22
|
+
console.error('Service creation failed');
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const account = await app_client_js_1.default.createAccountInServiceWithEmailCollectionMode(serviceExternalID, 'MANDATORY');
|
|
26
|
+
if (account === undefined) {
|
|
27
|
+
console.error('Failed to create a fully set up account');
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const apiToken = await app_client_js_1.default.createToken(account.gateway_account_id);
|
|
31
|
+
if (apiToken === undefined) {
|
|
32
|
+
console.error('Failed to create an API token');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (args.createPayments !== undefined && args.createPayments) {
|
|
36
|
+
console.warn('💸 Creating 10 payments in card sandbox gateway account (each . is a success, each ! is a failure)');
|
|
37
|
+
let createPaymentResult;
|
|
38
|
+
for (let i = 0; i < 10; i++) {
|
|
39
|
+
createPaymentResult = await app_client_js_1.default.createPayment(apiToken);
|
|
40
|
+
if (createPaymentResult === undefined) {
|
|
41
|
+
process.stderr.write('!');
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
process.stderr.write('.');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
console.warn('🤓 Creating admin user for service');
|
|
49
|
+
const user = await app_client_js_1.default.createUser([account.gateway_account_id], 'admin');
|
|
50
|
+
if (user === undefined) {
|
|
51
|
+
console.error('Failed to create an admin user');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
console.warn('😎 Creating view-only user for service');
|
|
55
|
+
const viewOnlyUser = await app_client_js_1.default.createUser([account.gateway_account_id], 'view-only');
|
|
56
|
+
if (viewOnlyUser === undefined) {
|
|
57
|
+
console.error('Failed to create a view-only user, continuing anyway since the admin user was successfully created');
|
|
58
|
+
}
|
|
59
|
+
const { otp } = totp_generator_1.TOTP.generate(user.otp_key);
|
|
60
|
+
console.log(`📧 Email: ${user.email}`);
|
|
61
|
+
console.log(`🛂 Password: ${user.password}`);
|
|
62
|
+
console.log(`🔑 OTP key: ${user.otp_key}`);
|
|
63
|
+
console.log(`📱 OTP token: ${otp}`);
|
|
64
|
+
console.log(`💁 Service ID: ${serviceExternalID}`);
|
|
65
|
+
console.log(`💳 Card gateway account ID: ${account.external_id}`);
|
|
66
|
+
console.log(`🎫 Card API token: ${apiToken}`);
|
|
67
|
+
console.log();
|
|
68
|
+
let selfserviceUrl;
|
|
69
|
+
if (await app_client_js_1.default.isProxyHealthy('selfservice')) {
|
|
70
|
+
selfserviceUrl = app_client_js_1.default.externalUrlFor('selfservice', '/', true);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
selfserviceUrl = app_client_js_1.default.externalUrlFor('selfservice', '/', false);
|
|
74
|
+
}
|
|
75
|
+
copyToClipboard(user.email);
|
|
76
|
+
console.log(`📋 “${user.email}” copied to clipboard`);
|
|
77
|
+
console.log(`🌎 Opening selfservice (${selfserviceUrl}) browser`);
|
|
78
|
+
console.log();
|
|
79
|
+
(0, node_child_process_1.spawn)('open', [selfserviceUrl]);
|
|
80
|
+
}
|
|
81
|
+
exports.default = UserHandler;
|
|
82
|
+
function copyToClipboard(email) {
|
|
83
|
+
const proc = (0, node_child_process_1.spawn)('pbcopy');
|
|
84
|
+
proc.stdin.write(email);
|
|
85
|
+
proc.stdin.end();
|
|
86
|
+
}
|
|
87
|
+
function parseArguments(_options) {
|
|
88
|
+
return {
|
|
89
|
+
createPayments: false
|
|
90
|
+
};
|
|
91
|
+
}
|
package/src/commands/local.js
CHANGED
|
@@ -4,22 +4,19 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
const standardContent_js_1 = require("../core/standardContent.js");
|
|
7
|
-
const legacy_1 = __importDefault(require("../commands/legacy"));
|
|
8
7
|
const otp_js_1 = __importDefault(require("./local/subcommands/otp.js"));
|
|
9
8
|
const up_js_1 = __importDefault(require("./local/subcommands/up.js"));
|
|
10
9
|
const down_js_1 = __importDefault(require("./local/subcommands/down.js"));
|
|
11
10
|
const nuke_js_1 = __importDefault(require("./local/subcommands/nuke.js"));
|
|
12
11
|
const restart_js_1 = __importDefault(require("./local/subcommands/restart.js"));
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
'user'
|
|
22
|
-
];
|
|
12
|
+
const paymentlink_js_1 = __importDefault(require("./local/subcommands/paymentlink.js"));
|
|
13
|
+
const url_js_1 = __importDefault(require("./local/subcommands/url.js"));
|
|
14
|
+
const browse_js_1 = __importDefault(require("./local/subcommands/browse.js"));
|
|
15
|
+
const db_js_1 = __importDefault(require("./local/subcommands/db.js"));
|
|
16
|
+
const account_js_1 = __importDefault(require("./local/subcommands/account.js"));
|
|
17
|
+
const token_js_1 = __importDefault(require("./local/subcommands/token.js"));
|
|
18
|
+
const payment_js_1 = __importDefault(require("./local/subcommands/payment.js"));
|
|
19
|
+
const user_js_1 = __importDefault(require("./local/subcommands/user.js"));
|
|
23
20
|
var LocalCommand;
|
|
24
21
|
(function (LocalCommand) {
|
|
25
22
|
LocalCommand["OTP"] = "otp";
|
|
@@ -28,17 +25,18 @@ var LocalCommand;
|
|
|
28
25
|
LocalCommand["Down"] = "down";
|
|
29
26
|
LocalCommand["Restart"] = "restart";
|
|
30
27
|
LocalCommand["Nuke"] = "nuke";
|
|
28
|
+
LocalCommand["PaymentLink"] = "paymentlink";
|
|
29
|
+
LocalCommand["Browse"] = "browse";
|
|
30
|
+
LocalCommand["Url"] = "url";
|
|
31
|
+
LocalCommand["DB"] = "db";
|
|
32
|
+
LocalCommand["Token"] = "token";
|
|
33
|
+
LocalCommand["Payment"] = "payment";
|
|
34
|
+
LocalCommand["Account"] = "account";
|
|
35
|
+
LocalCommand["User"] = "user";
|
|
31
36
|
LocalCommand["Help"] = "help";
|
|
32
37
|
LocalCommand["Unknown"] = "Unknown";
|
|
33
38
|
})(LocalCommand || (LocalCommand = {}));
|
|
34
39
|
async function localHandler(options) {
|
|
35
|
-
// Not everything is implemented yet. Lets hand off to the legacy handler for unimplemented
|
|
36
|
-
// subcommands
|
|
37
|
-
if (options.arguments.length > 0 && SUBCOMMANDS_NOT_YET_IMPLEMENTED.includes(options.arguments[0])) {
|
|
38
|
-
options.commandName = 'local';
|
|
39
|
-
await (0, legacy_1.default)(options);
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
40
|
await (0, standardContent_js_1.showHeader)();
|
|
43
41
|
const { subcommand, subcommandOptions } = parseArguments(options);
|
|
44
42
|
switch (subcommand) {
|
|
@@ -46,6 +44,38 @@ async function localHandler(options) {
|
|
|
46
44
|
await (0, otp_js_1.default)(subcommandOptions);
|
|
47
45
|
break;
|
|
48
46
|
}
|
|
47
|
+
case LocalCommand.PaymentLink: {
|
|
48
|
+
await (0, paymentlink_js_1.default)(subcommandOptions);
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
case LocalCommand.Browse: {
|
|
52
|
+
await (0, browse_js_1.default)(subcommandOptions);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case LocalCommand.Account: {
|
|
56
|
+
await (0, account_js_1.default)(subcommandOptions);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case LocalCommand.Url: {
|
|
60
|
+
await (0, url_js_1.default)(subcommandOptions);
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
case LocalCommand.DB: {
|
|
64
|
+
await (0, db_js_1.default)(subcommandOptions);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
case LocalCommand.Token: {
|
|
68
|
+
await (0, token_js_1.default)(subcommandOptions);
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case LocalCommand.Payment: {
|
|
72
|
+
await (0, payment_js_1.default)(subcommandOptions);
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
case LocalCommand.User: {
|
|
76
|
+
await (0, user_js_1.default)(subcommandOptions);
|
|
77
|
+
break;
|
|
78
|
+
}
|
|
49
79
|
case LocalCommand.Up: {
|
|
50
80
|
await (0, up_js_1.default)(subcommandOptions);
|
|
51
81
|
break;
|
|
@@ -84,7 +114,15 @@ function parseArguments(options) {
|
|
|
84
114
|
const subcommand = subcommandOptions.shift();
|
|
85
115
|
switch (subcommand) {
|
|
86
116
|
case LocalCommand.OTP: return { subcommand, subcommandOptions };
|
|
117
|
+
case LocalCommand.PaymentLink: return { subcommand, subcommandOptions };
|
|
118
|
+
case LocalCommand.Url: return { subcommand, subcommandOptions };
|
|
119
|
+
case LocalCommand.Browse: return { subcommand, subcommandOptions };
|
|
120
|
+
case LocalCommand.Account: return { subcommand, subcommandOptions };
|
|
87
121
|
case LocalCommand.Up: return { subcommand, subcommandOptions };
|
|
122
|
+
case LocalCommand.DB: return { subcommand, subcommandOptions };
|
|
123
|
+
case LocalCommand.Token: return { subcommand, subcommandOptions };
|
|
124
|
+
case LocalCommand.Payment: return { subcommand, subcommandOptions };
|
|
125
|
+
case LocalCommand.User: return { subcommand, subcommandOptions };
|
|
88
126
|
case LocalCommand.Launch: return { subcommand, subcommandOptions };
|
|
89
127
|
case LocalCommand.Down: return { subcommand, subcommandOptions };
|
|
90
128
|
case LocalCommand.Restart: return { subcommand, subcommandOptions };
|