@pega/dx-component-builder-sdk 0.1.23 → 0.1.25
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 +3 -2
- package/src/auth.js +573 -0
- package/src/cli.js +8 -2
- package/src/constants.js +32 -1
- package/src/tasks/authenticate/helper.js +91 -8
- package/src/tasks/authenticate/index.js +137 -61
- package/src/tasks/create/index.js +6 -1
- package/src/tasks/create/templates/SDK-React/template/DETAILS/demo.stories.jsx.mustache +509 -0
- package/src/tasks/create/templates/SDK-React/template/DETAILS/mock.stories.js.mustache +34 -0
- package/src/tasks/create/templates/SDK-React/template/DETAILS-region/demo.stories.jsx.mustache +1107 -0
- package/src/tasks/create/templates/SDK-React/template/DETAILS-region/mock.stories.js.mustache +34 -0
- package/src/tasks/create/templates/SDK-React/template/FORM/demo.stories.jsx.mustache +200 -0
- package/src/tasks/create/templates/SDK-React/template/FORM-region/demo.stories.jsx.mustache +183 -0
- package/src/tasks/create/templates/SDK-React/template/FORM-region/mock.stories.js.mustache +132 -0
- package/src/tasks/index.js +1 -0
- package/src/tasks/override/index.js +4 -2
- package/src/tasks/override-all/index.js +218 -0
- package/src/tasks/publish/helper.js +6 -0
- package/src/tasks/publish/index.js +8 -1
- package/src/tasks/publish-all/helper.js +7 -0
- package/src/tasks/publish-all/index.js +8 -1
- package/src/util.js +0 -5
|
@@ -1,24 +1,98 @@
|
|
|
1
1
|
/* eslint-disable import/prefer-default-export */
|
|
2
2
|
import { getPegaServerConfig } from '../../util.js';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
import { AUTHENTICATE_SCHEMA } from '../../constants.js';
|
|
5
|
+
|
|
6
|
+
export const getAuthQuestions = async (dxcbConfig) => {
|
|
7
|
+
const defaultPegaConfig = dxcbConfig;
|
|
8
|
+
const aMustAsk = dxcbConfig['questions_askAlways'] ? dxcbConfig['questions_askAlways'].split(',') : [];
|
|
9
|
+
const aNeverAsk = dxcbConfig['questions_askNever'] ? dxcbConfig['questions_askNever'].split(',') : [];
|
|
10
|
+
|
|
11
|
+
const initAnswers = (answers) => {
|
|
12
|
+
// Setup default answers
|
|
13
|
+
answers.serverType = defaultPegaConfig.serverType || "infinity";
|
|
14
|
+
answers.server = defaultPegaConfig.server || undefined;
|
|
15
|
+
answers.isolationId = defaultPegaConfig.isolationId || undefined;
|
|
16
|
+
answers.clientId = defaultPegaConfig.clientId || undefined;
|
|
17
|
+
answers.grantType = defaultPegaConfig.grantType || "authCode";
|
|
18
|
+
answers.clientSecret = defaultPegaConfig.clientSecret || undefined;
|
|
19
|
+
answers.user = defaultPegaConfig.user || undefined;
|
|
20
|
+
answers.password = defaultPegaConfig.password || undefined;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const fnStandardWhen = (prop, answers) => {
|
|
24
|
+
if (aNeverAsk.includes(prop)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return aMustAsk.includes(prop) || !answers[prop];
|
|
28
|
+
};
|
|
6
29
|
|
|
7
30
|
return [
|
|
31
|
+
{
|
|
32
|
+
name: 'serverType',
|
|
33
|
+
type: 'rawlist',
|
|
34
|
+
message: 'Enter Pega server type',
|
|
35
|
+
default: answers => {
|
|
36
|
+
return defaultPegaConfig.serverType;
|
|
37
|
+
},
|
|
38
|
+
choices: AUTHENTICATE_SCHEMA.serverType,
|
|
39
|
+
validate: value => {
|
|
40
|
+
if (value.trim()) {
|
|
41
|
+
return true;
|
|
42
|
+
}
|
|
43
|
+
return 'Pega server type cannot be empty';
|
|
44
|
+
},
|
|
45
|
+
when: answers => {
|
|
46
|
+
initAnswers(answers);
|
|
47
|
+
return fnStandardWhen('serverType', answers);
|
|
48
|
+
}
|
|
49
|
+
},
|
|
8
50
|
{
|
|
9
51
|
name: 'server',
|
|
10
52
|
message: 'Enter pega server url',
|
|
11
|
-
default: defaultPegaConfig.server
|
|
53
|
+
default: defaultPegaConfig.server,
|
|
54
|
+
when: answers =>{
|
|
55
|
+
return fnStandardWhen('server', answers);
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'isolationId',
|
|
60
|
+
message: 'Enter isolation id',
|
|
61
|
+
default: defaultPegaConfig.isolationId,
|
|
62
|
+
when: answers => {
|
|
63
|
+
return answers.serverType === "launchpad" && fnStandardWhen('isolationId', answers);
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'grantType',
|
|
68
|
+
type: 'rawlist',
|
|
69
|
+
message: 'Enter OAuth 2.0 grant type',
|
|
70
|
+
default: defaultPegaConfig.grantType,
|
|
71
|
+
choices: answers => {
|
|
72
|
+
return AUTHENTICATE_SCHEMA.grantType.filter(gt => !(answers.serverType === "launchpad" && gt.value === "passwordCreds"));
|
|
73
|
+
},
|
|
74
|
+
validate: value => {
|
|
75
|
+
if (value.trim()) {
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return 'Grant type cannot be empty';
|
|
79
|
+
},
|
|
80
|
+
when: answers => {
|
|
81
|
+
return fnStandardWhen('grantType', answers);
|
|
82
|
+
}
|
|
12
83
|
},
|
|
13
84
|
{
|
|
14
85
|
name: 'user',
|
|
15
86
|
message: 'Enter user id',
|
|
16
87
|
default: defaultPegaConfig.user,
|
|
17
|
-
validate: value => {
|
|
18
|
-
if (value.trim()) {
|
|
88
|
+
validate: (value, answers) => {
|
|
89
|
+
if (value.trim() || answers.grantType === "authCode") {
|
|
19
90
|
return true;
|
|
20
91
|
}
|
|
21
92
|
return 'Username cannot be empty';
|
|
93
|
+
},
|
|
94
|
+
when: answers => {
|
|
95
|
+
return (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('user', answers);
|
|
22
96
|
}
|
|
23
97
|
},
|
|
24
98
|
{
|
|
@@ -26,11 +100,14 @@ export const getAuthQuestions = async () => {
|
|
|
26
100
|
type: 'password',
|
|
27
101
|
message: 'Enter password',
|
|
28
102
|
default: defaultPegaConfig.password,
|
|
29
|
-
validate: value => {
|
|
30
|
-
if (value.trim()) {
|
|
103
|
+
validate: (value, answers) => {
|
|
104
|
+
if (value.trim() || answers.grantType === "authCode") {
|
|
31
105
|
return true;
|
|
32
106
|
}
|
|
33
107
|
return 'Password cannot be empty';
|
|
108
|
+
},
|
|
109
|
+
when: answers => {
|
|
110
|
+
return (answers.user && (answers.serverType === "infinity" && answers.grantType === "passwordCreds") && fnStandardWhen('password', answers));
|
|
34
111
|
}
|
|
35
112
|
},
|
|
36
113
|
{
|
|
@@ -42,6 +119,9 @@ export const getAuthQuestions = async () => {
|
|
|
42
119
|
return true;
|
|
43
120
|
}
|
|
44
121
|
return 'clientId cannot be empty';
|
|
122
|
+
},
|
|
123
|
+
when: answers => {
|
|
124
|
+
return fnStandardWhen('clientId', answers);
|
|
45
125
|
}
|
|
46
126
|
},
|
|
47
127
|
{
|
|
@@ -49,11 +129,14 @@ export const getAuthQuestions = async () => {
|
|
|
49
129
|
type: 'password',
|
|
50
130
|
message: 'Enter clientSecret',
|
|
51
131
|
default: defaultPegaConfig.clientSecret,
|
|
52
|
-
validate: value => {
|
|
132
|
+
validate: (value, answers) => {
|
|
53
133
|
if (value.trim()) {
|
|
54
134
|
return true;
|
|
55
135
|
}
|
|
56
136
|
return 'clientSecret cannot be empty';
|
|
137
|
+
},
|
|
138
|
+
when: answers => {
|
|
139
|
+
return (answers.grantType !== "authCode" && fnStandardWhen('clientSecret', answers));
|
|
57
140
|
}
|
|
58
141
|
}
|
|
59
142
|
];
|
|
@@ -1,90 +1,166 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import fs from 'fs';
|
|
3
|
-
import https from 'https';
|
|
2
|
+
import fs from 'node:fs';
|
|
4
3
|
|
|
5
4
|
import chalk from 'chalk';
|
|
6
5
|
import inquirer from 'inquirer';
|
|
7
|
-
import fetch from 'node-fetch';
|
|
8
6
|
|
|
9
|
-
import { checkPathAccess,
|
|
10
|
-
import { TOKEN_PATH,
|
|
7
|
+
import { checkPathAccess, showVersion } from '../../util.js';
|
|
8
|
+
import { TOKEN_PATH, TOKEN_URL_V1, AUTHORIZE_URL_V1, LP_TOKEN_URL, LP_AUTHORIZE_URL, SDK_CONFIG_JSON_FILENAME,
|
|
9
|
+
SERVER_CONFIG, DXCB_CONFIG, DXCB_PUBLISH_ACCESS, SERVER_TYPE, SERVER_REST_URL, LP_SERVER_REST_URL } from '../../constants.js';
|
|
11
10
|
|
|
12
11
|
import { getAuthQuestions } from './helper.js';
|
|
13
|
-
|
|
12
|
+
import PegaAuth from '../../auth.js';
|
|
14
13
|
|
|
15
14
|
const pegaConfigJsonPath = path.join(path.resolve(), SDK_CONFIG_JSON_FILENAME);
|
|
15
|
+
let server = null;
|
|
16
16
|
|
|
17
17
|
const generateAccessToken = async config => {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
18
|
+
|
|
19
|
+
let authSuccess = false;
|
|
20
|
+
const { serverType, isolationId, grantType, clientId, clientSecret, user, password } = config;
|
|
21
|
+
// Try to gracefully deal with missing trailing slashes for server (and later conditionally for redirectUri)
|
|
22
|
+
const server = config.server.endsWith('/') ? config.server : `${config.server}/`;
|
|
23
|
+
|
|
24
|
+
return new Promise((resolve, reject) => {
|
|
25
|
+
const sTokenUri = `${server}${serverType === 'infinity' ? TOKEN_URL_V1 : LP_TOKEN_URL}`;
|
|
26
|
+
const sAuthorizeUri = `${server}${serverType === 'infinity' ? AUTHORIZE_URL_V1 : LP_AUTHORIZE_URL}`;
|
|
27
|
+
// console.log(`grantType: ${config.grantType}`);
|
|
28
|
+
|
|
29
|
+
const authCodeConfig = grantType === 'authCode' ? {
|
|
30
|
+
authorizeUri: sAuthorizeUri,
|
|
31
|
+
redirectUri: config.redirectUri.endsWith('/') ? config.redirectUri : `${config.redirectUri}/`,
|
|
32
|
+
cert: config.cert,
|
|
33
|
+
key: config.key,
|
|
34
|
+
winTitle: 'DX Component Dev',
|
|
35
|
+
winBodyHtml: `Authentication is complete. This browser window may be closed.`
|
|
36
|
+
} : {};
|
|
37
|
+
|
|
38
|
+
// Build auth config structure
|
|
39
|
+
const authConfig = {
|
|
40
|
+
serverType: serverType,
|
|
41
|
+
grantType: grantType,
|
|
42
|
+
tokenUri: sTokenUri,
|
|
43
|
+
clientId: clientId,
|
|
44
|
+
clientSecret: clientSecret,
|
|
45
|
+
ignoreInvalidCerts: true,
|
|
46
|
+
...authCodeConfig
|
|
47
|
+
};
|
|
48
|
+
if (serverType === 'infinity') {
|
|
49
|
+
authConfig.authService = 'pega';
|
|
50
|
+
if (grantType !== 'clientCreds' && user && password) {
|
|
51
|
+
authConfig.userIdentifier = user;
|
|
52
|
+
authConfig.password = Buffer.from(password).toString('base64');
|
|
53
53
|
}
|
|
54
|
-
}
|
|
55
|
-
|
|
54
|
+
}
|
|
55
|
+
if (serverType === 'launchpad') {
|
|
56
|
+
authConfig.isolationId = isolationId;
|
|
57
|
+
// authConfig.noPKCE = true;
|
|
58
|
+
}
|
|
59
|
+
const auth = new PegaAuth(authConfig);
|
|
60
|
+
// console.log(`...about to invoke auth.login\n${JSON.stringify(authConfig)}`);
|
|
61
|
+
|
|
62
|
+
auth.login()
|
|
63
|
+
.then((token) => {
|
|
64
|
+
if (token?.token_type) {
|
|
65
|
+
fs.writeFile(TOKEN_PATH, JSON.stringify(token), err => {
|
|
66
|
+
if (err) {
|
|
67
|
+
console.error(err);
|
|
68
|
+
return reject(authSuccess);
|
|
69
|
+
}
|
|
70
|
+
console.log(`${chalk.bold.green('Authenticated successfully !!')}`);
|
|
71
|
+
authSuccess = true;
|
|
72
|
+
return resolve(authSuccess);
|
|
73
|
+
});
|
|
74
|
+
} else {
|
|
75
|
+
console.log(`${chalk.bold.red('Authentication failed:' + JSON.stringify(token.errors ? token.errors : token))}`);
|
|
76
|
+
return reject(authSuccess);
|
|
77
|
+
}
|
|
78
|
+
})
|
|
79
|
+
.catch((e) => {
|
|
80
|
+
console.log(`${chalk.bold.red(e)}`);
|
|
81
|
+
return reject(authSuccess);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
56
84
|
};
|
|
57
85
|
|
|
58
86
|
export default async options => {
|
|
87
|
+
|
|
88
|
+
let authOK = false;
|
|
89
|
+
|
|
59
90
|
showVersion();
|
|
60
91
|
|
|
61
92
|
await checkPathAccess(pegaConfigJsonPath);
|
|
62
93
|
|
|
63
|
-
let
|
|
64
|
-
data =
|
|
94
|
+
let cfgData = fs.readFileSync(pegaConfigJsonPath, { encoding: 'utf8' });
|
|
95
|
+
let data = null;
|
|
96
|
+
if (cfgData) {
|
|
97
|
+
try {
|
|
98
|
+
data = JSON.parse(cfgData);
|
|
99
|
+
} catch (e) {
|
|
100
|
+
const msg = `Invalid JSON within ${SDK_CONFIG_JSON_FILENAME}`;
|
|
101
|
+
console.log(`${chalk.red(msg)}`);
|
|
102
|
+
process.exit(1);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
65
105
|
|
|
66
106
|
if (!data[SERVER_CONFIG] || !data[SERVER_CONFIG][SERVER_REST_URL]) {
|
|
67
107
|
console.error(
|
|
68
|
-
`${chalk.red.bold('ERROR')}
|
|
108
|
+
`${chalk.red.bold('ERROR')} ${SERVER_CONFIG}.${SERVER_REST_URL} property not found within ${SDK_CONFIG_JSON_FILENAME}`
|
|
69
109
|
);
|
|
70
110
|
process.exit(1);
|
|
71
111
|
}
|
|
72
112
|
|
|
73
|
-
|
|
74
|
-
const serverConfig =
|
|
75
|
-
|
|
113
|
+
// Note: serverConfig below is actually dxcbConfig.
|
|
114
|
+
const serverConfig = data[DXCB_CONFIG][DXCB_PUBLISH_ACCESS];
|
|
115
|
+
serverConfig.serverType = data[SERVER_CONFIG][SERVER_TYPE] || "infinity";
|
|
116
|
+
serverConfig.server = data[SERVER_CONFIG][serverConfig.serverType === "infinity" ? SERVER_REST_URL : LP_SERVER_REST_URL];
|
|
117
|
+
const isPwdNonEmpty = serverConfig['password'] ? true : false;
|
|
76
118
|
|
|
77
|
-
const questions = await getAuthQuestions(
|
|
119
|
+
const questions = await getAuthQuestions(serverConfig);
|
|
78
120
|
const answers = await inquirer.prompt(questions);
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
121
|
+
const aProps = ['serverType','server','isolationId','clientId','grantType','clientSecret','user','password'];
|
|
122
|
+
const isLaunchPad = answers.serverType === "launchpad";
|
|
123
|
+
let bWriteUpdate = false;
|
|
124
|
+
for (let i = 0; i < aProps.length; i += 1) {
|
|
125
|
+
const prop = aProps[i];
|
|
126
|
+
if (serverConfig[prop] !== answers[prop]) {
|
|
127
|
+
// console.log(`property ${prop} changed from ${serverConfig[prop]} to ${answers[prop]}`);
|
|
128
|
+
serverConfig[prop] = answers[prop];
|
|
129
|
+
if (prop !== 'password' || isPwdNonEmpty) {
|
|
130
|
+
bWriteUpdate = true;
|
|
131
|
+
}
|
|
132
|
+
if (prop === 'server') {
|
|
133
|
+
data[SERVER_CONFIG][isLaunchPad ? LP_SERVER_REST_URL : SERVER_REST_URL] = answers.server;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
authOK = await generateAccessToken(serverConfig);
|
|
140
|
+
} catch (e) {
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
delete serverConfig.serverType;
|
|
144
|
+
delete serverConfig.server;
|
|
145
|
+
|
|
146
|
+
if (authOK & bWriteUpdate) {
|
|
147
|
+
// Don't write password value (unless it already had a value)
|
|
148
|
+
if (!isPwdNonEmpty) {
|
|
149
|
+
serverConfig['password'] = '';
|
|
150
|
+
}
|
|
151
|
+
console.log(`${chalk.green('Writing updated config...')}`);
|
|
152
|
+
let updCfg = null;
|
|
153
|
+
try {
|
|
154
|
+
updCfg = JSON.stringify(data, null, 2);
|
|
155
|
+
// console.log(`updated config: ${updCfg}`);
|
|
156
|
+
fs.writeFileSync(pegaConfigJsonPath, updCfg, err => {
|
|
157
|
+
if (err) throw err;
|
|
158
|
+
});
|
|
159
|
+
} catch (e) {
|
|
160
|
+
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
process.exit(1);
|
|
165
|
+
|
|
90
166
|
};
|
|
@@ -45,7 +45,12 @@ const copyComponentTemplate = async options => {
|
|
|
45
45
|
}
|
|
46
46
|
else {
|
|
47
47
|
return copy(options.templateDirectoryConstellation, options.targetDirectoryConstellation, {
|
|
48
|
-
clobber: false
|
|
48
|
+
clobber: false,
|
|
49
|
+
filter: (fileName) => {
|
|
50
|
+
// filter out the file config.json or config.json.mustache
|
|
51
|
+
if (fileName.indexOf("config.json") >= 0) return false;
|
|
52
|
+
else return true;
|
|
53
|
+
}
|
|
49
54
|
});
|
|
50
55
|
}
|
|
51
56
|
|