@pacaf/wizard-ux 3.0.5 → 3.0.7
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 +2 -2
- package/server/steps/03-app-registration.mjs +9 -6
- package/server/steps/04-auth-setup.mjs +27 -24
- package/server/steps/05-publisher.mjs +4 -4
- package/server/steps/07-scaffold.mjs +5 -5
- package/server/steps/08-connectors.mjs +12 -9
- package/server/steps/09-verify-deploy.mjs +13 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pacaf/wizard-ux",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.7",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Browser-based setup wizard for Power Apps Code Apps (parallel to @pacaf/wizard CLI).",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"react-dom": "^19.0.0",
|
|
39
39
|
"react-resizable-panels": "^2.1.7",
|
|
40
40
|
"react-router-dom": "^7.1.0",
|
|
41
|
-
"@pacaf/wizard": "3.1.
|
|
41
|
+
"@pacaf/wizard": "3.1.1"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/react": "^19.0.0",
|
|
@@ -7,8 +7,11 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
7
7
|
import { setSecret, hasUsableSecret } from '../lib/dataverse-bridge.mjs';
|
|
8
8
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
// PACKAGE_DIR locates sibling @pacaf/wizard lib files (must stay __dirname-relative).
|
|
11
|
+
// PROJECT_DIR is the user's working directory (where .env, .env.local, etc. live).
|
|
12
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
13
|
+
const PROJECT_DIR = process.cwd();
|
|
14
|
+
const VALIDATE = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'validate.mjs')).href);
|
|
12
15
|
|
|
13
16
|
function hasCommand(name) {
|
|
14
17
|
try {
|
|
@@ -21,7 +24,7 @@ function hasCommand(name) {
|
|
|
21
24
|
|
|
22
25
|
function runSafe(file, args) {
|
|
23
26
|
try {
|
|
24
|
-
return execFileSync(file, args, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], cwd:
|
|
27
|
+
return execFileSync(file, args, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], cwd: PROJECT_DIR }).trim();
|
|
25
28
|
} catch {
|
|
26
29
|
return null;
|
|
27
30
|
}
|
|
@@ -29,7 +32,7 @@ function runSafe(file, args) {
|
|
|
29
32
|
|
|
30
33
|
function runSafeWithTimeout(file, args, timeoutMs = 2000) {
|
|
31
34
|
try {
|
|
32
|
-
return execFileSync(file, args, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], cwd:
|
|
35
|
+
return execFileSync(file, args, { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'], cwd: PROJECT_DIR, timeout: timeoutMs }).trim();
|
|
33
36
|
} catch {
|
|
34
37
|
return null;
|
|
35
38
|
}
|
|
@@ -428,8 +431,8 @@ export default {
|
|
|
428
431
|
|
|
429
432
|
// Persist encrypted secret to .env.local so it survives server restarts
|
|
430
433
|
try {
|
|
431
|
-
const CRYPTO = await import(pathToFileURL(resolve(
|
|
432
|
-
const envLocalPath = join(
|
|
434
|
+
const CRYPTO = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'crypto.mjs')).href);
|
|
435
|
+
const envLocalPath = join(PROJECT_DIR, '.env.local');
|
|
433
436
|
let envContent = existsSync(envLocalPath) ? readFileSync(envLocalPath, 'utf-8') : '';
|
|
434
437
|
const encrypted = CRYPTO.encrypt(clientSecret);
|
|
435
438
|
if (envContent.match(/^PP_CLIENT_SECRET=.*$/m)) {
|
|
@@ -7,10 +7,13 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
7
7
|
import { getSecret, hasUsableSecret, recoverSecret, setSecret } from '../lib/dataverse-bridge.mjs';
|
|
8
8
|
|
|
9
9
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
10
|
+
// PACKAGE_DIR locates sibling @pacaf/wizard lib files (must stay __dirname-relative).
|
|
11
|
+
// PROJECT_DIR is the user's working directory (profile names, env files, git hooks, cwd).
|
|
12
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
13
|
+
const PROJECT_DIR = process.cwd();
|
|
14
|
+
const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
|
|
15
|
+
const CRYPTO = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'crypto.mjs')).href);
|
|
16
|
+
const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
|
|
14
17
|
|
|
15
18
|
function hasCommand(name) {
|
|
16
19
|
try {
|
|
@@ -41,7 +44,7 @@ function formatPacAuthCreateError(profileName, url, output = '') {
|
|
|
41
44
|
}
|
|
42
45
|
|
|
43
46
|
function createPacProfile(log, pac, targetKey, url, appId, secret, tenantId) {
|
|
44
|
-
const profileName = PAC_TARGET.buildPacProfileName({ rootDir:
|
|
47
|
+
const profileName = PAC_TARGET.buildPacProfileName({ rootDir: PROJECT_DIR, targetKey, profileType: 'spn', url });
|
|
45
48
|
const result = SHELL.runSafeCapture(pac, [
|
|
46
49
|
'auth', 'create', '--name', profileName, '--environment', url,
|
|
47
50
|
'--applicationId', appId, '--clientSecret', secret, '--tenant', tenantId,
|
|
@@ -70,10 +73,10 @@ function createProfiles(log, pac, credentialValues, state) {
|
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
function installPreCommitHook(log) {
|
|
73
|
-
const hookDir = join(
|
|
76
|
+
const hookDir = join(PROJECT_DIR, '.git', 'hooks');
|
|
74
77
|
const hookPath = join(hookDir, 'pre-commit');
|
|
75
|
-
const hookSource = join(
|
|
76
|
-
if (!existsSync(join(
|
|
78
|
+
const hookSource = join(PROJECT_DIR, 'scripts', 'pre-commit-hook.sh');
|
|
79
|
+
if (!existsSync(join(PROJECT_DIR, '.git')) || !existsSync(hookSource)) return;
|
|
77
80
|
if (existsSync(hookPath)) {
|
|
78
81
|
const existing = readFileSync(hookPath, 'utf-8');
|
|
79
82
|
if (!existing.includes('papps-secret-guard')) return;
|
|
@@ -91,7 +94,7 @@ function installPreCommitHook(log) {
|
|
|
91
94
|
function runLivePac(log, pac, args, opts = {}) {
|
|
92
95
|
return new Promise((resolvePromise) => {
|
|
93
96
|
log.info(`$ ${SHELL.formatCommandForLog(pac, args)}`);
|
|
94
|
-
const child = SHELL.spawnSafe(pac, args, { cwd:
|
|
97
|
+
const child = SHELL.spawnSafe(pac, args, { cwd: PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
95
98
|
let settled = false;
|
|
96
99
|
const timeout = opts.timeoutMs
|
|
97
100
|
? setTimeout(() => {
|
|
@@ -233,7 +236,7 @@ export default {
|
|
|
233
236
|
// ── User credentials flow ──
|
|
234
237
|
if (authProfileType === 'user') {
|
|
235
238
|
const method = answers.USER_SIGN_IN_METHOD === 'browser' ? 'browser' : 'deviceCode';
|
|
236
|
-
const userProfileName = PAC_TARGET.buildPacProfileName({ rootDir:
|
|
239
|
+
const userProfileName = PAC_TARGET.buildPacProfileName({ rootDir: PROJECT_DIR, targetKey, profileType: 'user', url: devUrl });
|
|
237
240
|
|
|
238
241
|
log.info('Creating user auth profile via interactive sign-in...');
|
|
239
242
|
const userArgs = ['auth', 'create', '--name', userProfileName, '--environment', devUrl];
|
|
@@ -266,7 +269,7 @@ export default {
|
|
|
266
269
|
prodUrl ? `PP_ENV_PROD=op://${vault}/${itemName}/env-prod` : '',
|
|
267
270
|
'',
|
|
268
271
|
].filter((line) => line !== '').join('\n');
|
|
269
|
-
writeFileSync(join(
|
|
272
|
+
writeFileSync(join(PROJECT_DIR, '.env'), `${envContent}\n`, 'utf-8');
|
|
270
273
|
log.ok('Wrote .env with 1Password references');
|
|
271
274
|
} else {
|
|
272
275
|
const envContent = [
|
|
@@ -278,7 +281,7 @@ export default {
|
|
|
278
281
|
prodUrl ? `PP_ENV_PROD=${prodUrl}` : '',
|
|
279
282
|
'',
|
|
280
283
|
].filter((line) => line !== '').join('\n');
|
|
281
|
-
writeFileSync(join(
|
|
284
|
+
writeFileSync(join(PROJECT_DIR, '.env'), `${envContent}\n`, 'utf-8');
|
|
282
285
|
log.ok('Wrote .env with environment URLs');
|
|
283
286
|
}
|
|
284
287
|
|
|
@@ -287,12 +290,12 @@ export default {
|
|
|
287
290
|
// Verify the user profile
|
|
288
291
|
const verification = PAC_TARGET.selectAndVerifyPacProfile({
|
|
289
292
|
pac,
|
|
290
|
-
rootDir:
|
|
293
|
+
rootDir: PROJECT_DIR,
|
|
291
294
|
wizardState: { WIZARD_TARGET_ENV: targetKey, PP_ENV_DEV: devUrl, PP_ENV_TEST: testUrl, PP_ENV_PROD: prodUrl },
|
|
292
295
|
targetKey,
|
|
293
296
|
profileType: 'user',
|
|
294
297
|
credentialValues: null,
|
|
295
|
-
powerConfigPath: join(
|
|
298
|
+
powerConfigPath: join(PROJECT_DIR, 'power.config.json'),
|
|
296
299
|
requireCredentialMatch: false,
|
|
297
300
|
requirePowerConfig: false,
|
|
298
301
|
requirePowerConfigTarget: false,
|
|
@@ -335,10 +338,10 @@ export default {
|
|
|
335
338
|
prodUrl ? `PP_ENV_PROD=op://${vault}/${itemName}/env-prod` : '',
|
|
336
339
|
'',
|
|
337
340
|
].filter((line) => line !== '').join('\n');
|
|
338
|
-
writeFileSync(join(
|
|
341
|
+
writeFileSync(join(PROJECT_DIR, '.env'), `${envContent}\n`, 'utf-8');
|
|
339
342
|
log.ok('Wrote .env with 1Password references');
|
|
340
343
|
} else {
|
|
341
|
-
const gitignorePath = join(
|
|
344
|
+
const gitignorePath = join(PROJECT_DIR, '.gitignore');
|
|
342
345
|
if (existsSync(gitignorePath)) {
|
|
343
346
|
const gitignore = readFileSync(gitignorePath, 'utf-8');
|
|
344
347
|
if (!gitignore.includes('.env.local')) appendFileSync(gitignorePath, '\n.env.local\n');
|
|
@@ -357,15 +360,15 @@ export default {
|
|
|
357
360
|
prodUrl ? `PP_ENV_PROD=${prodUrl}` : '',
|
|
358
361
|
'',
|
|
359
362
|
].filter((line) => line !== '').join('\n');
|
|
360
|
-
writeFileSync(join(
|
|
363
|
+
writeFileSync(join(PROJECT_DIR, '.env.local'), `${envLocalContent}\n`, 'utf-8');
|
|
361
364
|
if (platform() !== 'win32') {
|
|
362
|
-
try { chmodSync(join(
|
|
365
|
+
try { chmodSync(join(PROJECT_DIR, '.env.local'), 0o600); } catch { /* best effort */ }
|
|
363
366
|
}
|
|
364
367
|
log.ok('Wrote .env.local');
|
|
365
368
|
}
|
|
366
369
|
|
|
367
370
|
const opBin = hasCommand('op') ? 'op' : null;
|
|
368
|
-
const credentialValues = PAC_TARGET.resolveCredentialValues({ rootDir:
|
|
371
|
+
const credentialValues = PAC_TARGET.resolveCredentialValues({ rootDir: PROJECT_DIR, opBin, source: authMode });
|
|
369
372
|
createProfiles(log, pac, credentialValues, state);
|
|
370
373
|
installPreCommitHook(log);
|
|
371
374
|
|
|
@@ -381,7 +384,7 @@ export default {
|
|
|
381
384
|
prodUrl ? `PP_ENV_PROD=${prodUrl}` : '',
|
|
382
385
|
'',
|
|
383
386
|
].filter((line) => line !== '').join('\n');
|
|
384
|
-
writeFileSync(join(
|
|
387
|
+
writeFileSync(join(PROJECT_DIR, '.env.template'), `${envTemplate}\n`, 'utf-8');
|
|
385
388
|
log.ok('Wrote .env.template');
|
|
386
389
|
|
|
387
390
|
const wizardState = {
|
|
@@ -392,12 +395,12 @@ export default {
|
|
|
392
395
|
};
|
|
393
396
|
const verification = PAC_TARGET.selectAndVerifyPacProfile({
|
|
394
397
|
pac,
|
|
395
|
-
rootDir:
|
|
398
|
+
rootDir: PROJECT_DIR,
|
|
396
399
|
wizardState,
|
|
397
400
|
targetKey,
|
|
398
401
|
profileType: 'spn',
|
|
399
402
|
credentialValues,
|
|
400
|
-
powerConfigPath: join(
|
|
403
|
+
powerConfigPath: join(PROJECT_DIR, 'power.config.json'),
|
|
401
404
|
requireCredentialMatch: true,
|
|
402
405
|
requirePowerConfig: false,
|
|
403
406
|
requirePowerConfigTarget: false,
|
|
@@ -406,7 +409,7 @@ export default {
|
|
|
406
409
|
log.info(verification.whoInfo.raw.split('\n').map((line) => ` ${line}`).join('\n'));
|
|
407
410
|
|
|
408
411
|
if (answers.CREATE_USER_PROFILE === true) {
|
|
409
|
-
const userProfileName = PAC_TARGET.buildPacProfileName({ rootDir:
|
|
412
|
+
const userProfileName = PAC_TARGET.buildPacProfileName({ rootDir: PROJECT_DIR, targetKey, profileType: 'user', url: devUrl });
|
|
410
413
|
const method = answers.USER_SIGN_IN_METHOD === 'browser' ? 'browser' : 'deviceCode';
|
|
411
414
|
log.warn('PAC code commands require a user auth profile. Starting user sign-in now.');
|
|
412
415
|
const userArgs = ['auth', 'create', '--name', userProfileName, '--environment', devUrl];
|
|
@@ -414,7 +417,7 @@ export default {
|
|
|
414
417
|
const userOk = await runLivePac(log, pac, userArgs, { timeoutMs: method === 'browser' ? 180000 : 0 });
|
|
415
418
|
if (userOk) {
|
|
416
419
|
log.ok(`User profile ${userProfileName} created`);
|
|
417
|
-
const spnProfileName = PAC_TARGET.buildPacProfileName({ rootDir:
|
|
420
|
+
const spnProfileName = PAC_TARGET.buildPacProfileName({ rootDir: PROJECT_DIR, targetKey, profileType: 'spn', url: devUrl });
|
|
418
421
|
SHELL.runSafeCapture(pac, ['auth', 'select', '--name', spnProfileName]);
|
|
419
422
|
log.ok('Switched back to SPN profile for the next setup steps');
|
|
420
423
|
} else {
|
|
@@ -6,10 +6,10 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
6
6
|
import { dvGet, dvPost, hasUsableSecret, setSecret, clearSecret } from '../lib/dataverse-bridge.mjs';
|
|
7
7
|
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
const
|
|
10
|
-
const VALIDATE = await import(pathToFileURL(resolve(
|
|
11
|
-
const SHELL = await import(pathToFileURL(resolve(
|
|
12
|
-
const PAC_TARGET = await import(pathToFileURL(resolve(
|
|
9
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
10
|
+
const VALIDATE = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'validate.mjs')).href);
|
|
11
|
+
const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
|
|
12
|
+
const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
|
|
13
13
|
|
|
14
14
|
const CREATE_NEW = '__create_new__';
|
|
15
15
|
const PASTE_URL = '__paste_url__';
|
|
@@ -5,10 +5,10 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const
|
|
9
|
-
const SCAFFOLD = await import(pathToFileURL(resolve(
|
|
10
|
-
const SHELL = await import(pathToFileURL(resolve(
|
|
11
|
-
const PAC_TARGET = await import(pathToFileURL(resolve(
|
|
8
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
9
|
+
const SCAFFOLD = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'scaffold-foundations.mjs')).href);
|
|
10
|
+
const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
|
|
11
|
+
const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
|
|
12
12
|
|
|
13
13
|
function makeFoundationLogger(log) {
|
|
14
14
|
return {
|
|
@@ -256,7 +256,7 @@ export default {
|
|
|
256
256
|
log.ok('Folder structure created');
|
|
257
257
|
|
|
258
258
|
SCAFFOLD.writeStarterFiles(projectDir, appName, foundationLogger);
|
|
259
|
-
SCAFFOLD.copyFoundationFiles(
|
|
259
|
+
SCAFFOLD.copyFoundationFiles(PACKAGE_DIR, projectDir, foundationLogger);
|
|
260
260
|
|
|
261
261
|
const pac = SHELL.pacPath();
|
|
262
262
|
if (pac) {
|
|
@@ -6,11 +6,14 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
6
6
|
import { dvGet, dvPost, hasUsableSecret, setSecret } from '../lib/dataverse-bridge.mjs';
|
|
7
7
|
|
|
8
8
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const
|
|
12
|
-
const
|
|
13
|
-
const
|
|
9
|
+
// PACKAGE_DIR locates sibling @pacaf/wizard lib files (must stay __dirname-relative).
|
|
10
|
+
// PROJECT_DIR is the user's working directory (profile names, command cwd).
|
|
11
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
12
|
+
const PROJECT_DIR = process.cwd();
|
|
13
|
+
const VALIDATE = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'validate.mjs')).href);
|
|
14
|
+
const CONNECTIONS = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'connection-discovery.mjs')).href);
|
|
15
|
+
const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
|
|
16
|
+
const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
|
|
14
17
|
|
|
15
18
|
const CREATE_MANUAL = '__manual__';
|
|
16
19
|
const SKIP_CONNECTION = '__skip__';
|
|
@@ -103,7 +106,7 @@ function connectionOptions(connections, savedConnectionId = '') {
|
|
|
103
106
|
|
|
104
107
|
function resolveCredentialValues(state) {
|
|
105
108
|
return PAC_TARGET.resolveCredentialValues({
|
|
106
|
-
rootDir:
|
|
109
|
+
rootDir: PROJECT_DIR,
|
|
107
110
|
opBin: process.env.OP_BIN || (hasCommand('op') ? 'op' : null),
|
|
108
111
|
source: state.AUTH_MODE || 'auto',
|
|
109
112
|
});
|
|
@@ -112,7 +115,7 @@ function resolveCredentialValues(state) {
|
|
|
112
115
|
function verifyUserProfile(pac, projectDir, state, credentialValues) {
|
|
113
116
|
return PAC_TARGET.selectAndVerifyPacProfile({
|
|
114
117
|
pac,
|
|
115
|
-
rootDir:
|
|
118
|
+
rootDir: PROJECT_DIR,
|
|
116
119
|
wizardState: {
|
|
117
120
|
WIZARD_TARGET_ENV: state.WIZARD_TARGET_ENV || 'dev',
|
|
118
121
|
PP_ENV_DEV: state.PP_ENV_DEV || '',
|
|
@@ -132,7 +135,7 @@ function verifyUserProfile(pac, projectDir, state, credentialValues) {
|
|
|
132
135
|
function runFileCapture(log, file, args, opts = {}) {
|
|
133
136
|
return new Promise((resolvePromise) => {
|
|
134
137
|
log.info(`$ ${SHELL.formatCommandForLog(file, args)}`);
|
|
135
|
-
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd ||
|
|
138
|
+
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd || PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
136
139
|
let stdout = '';
|
|
137
140
|
let stderr = '';
|
|
138
141
|
child.stdout.setEncoding('utf-8');
|
|
@@ -396,7 +399,7 @@ export default {
|
|
|
396
399
|
const pac = SHELL.pacPath();
|
|
397
400
|
if (!pac) throw new Error('PAC CLI was not found. Install PAC CLI before registering data sources.');
|
|
398
401
|
|
|
399
|
-
const projectDir = resolve(String(state.PROJECT_DIR ||
|
|
402
|
+
const projectDir = resolve(String(state.PROJECT_DIR || PROJECT_DIR));
|
|
400
403
|
if (!existsSync(join(projectDir, 'power.config.json'))) {
|
|
401
404
|
throw new Error(`power.config.json was not found in ${projectDir}. Complete Step 7 before registering data sources.`);
|
|
402
405
|
}
|
|
@@ -5,9 +5,12 @@ import { dirname, join, resolve } from 'node:path';
|
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
6
6
|
|
|
7
7
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const
|
|
8
|
+
// PACKAGE_DIR locates sibling @pacaf/wizard lib files (must stay __dirname-relative).
|
|
9
|
+
// PROJECT_DIR is the user's working directory (profile names, command cwd).
|
|
10
|
+
const PACKAGE_DIR = resolve(__dirname, '..', '..', '..');
|
|
11
|
+
const PROJECT_DIR = process.cwd();
|
|
12
|
+
const SHELL = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'shell.mjs')).href);
|
|
13
|
+
const PAC_TARGET = await import(pathToFileURL(resolve(PACKAGE_DIR, 'wizard', 'lib', 'pac-target.mjs')).href);
|
|
11
14
|
|
|
12
15
|
function hasCommand(name) {
|
|
13
16
|
try {
|
|
@@ -22,8 +25,8 @@ function runCommand(log, command, opts = {}) {
|
|
|
22
25
|
return new Promise((resolvePromise) => {
|
|
23
26
|
log.info(`$ ${command}`);
|
|
24
27
|
const child = process.platform === 'win32'
|
|
25
|
-
? spawn(process.env.COMSPEC || 'cmd.exe', ['/d', '/s', '/c', command], { cwd: opts.cwd ||
|
|
26
|
-
: spawn('sh', ['-c', command], { cwd: opts.cwd ||
|
|
28
|
+
? spawn(process.env.COMSPEC || 'cmd.exe', ['/d', '/s', '/c', command], { cwd: opts.cwd || PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] })
|
|
29
|
+
: spawn('sh', ['-c', command], { cwd: opts.cwd || PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
27
30
|
child.stdout.setEncoding('utf-8');
|
|
28
31
|
child.stderr.setEncoding('utf-8');
|
|
29
32
|
child.stdout.on('data', (chunk) => log.info(String(chunk).trimEnd()));
|
|
@@ -39,7 +42,7 @@ function runCommand(log, command, opts = {}) {
|
|
|
39
42
|
function runFile(log, file, args, opts = {}) {
|
|
40
43
|
return new Promise((resolvePromise) => {
|
|
41
44
|
log.info(`$ ${SHELL.formatCommandForLog(file, args)}`);
|
|
42
|
-
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd ||
|
|
45
|
+
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd || PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
43
46
|
child.stdout.setEncoding('utf-8');
|
|
44
47
|
child.stderr.setEncoding('utf-8');
|
|
45
48
|
child.stdout.on('data', (chunk) => log.info(String(chunk).trimEnd()));
|
|
@@ -55,7 +58,7 @@ function runFile(log, file, args, opts = {}) {
|
|
|
55
58
|
function runFileCapture(log, file, args, opts = {}) {
|
|
56
59
|
return new Promise((resolvePromise) => {
|
|
57
60
|
log.info(`$ ${SHELL.formatCommandForLog(file, args)}`);
|
|
58
|
-
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd ||
|
|
61
|
+
const child = SHELL.spawnSafe(file, args, { cwd: opts.cwd || PROJECT_DIR, stdio: ['ignore', 'pipe', 'pipe'] });
|
|
59
62
|
let stdout = '';
|
|
60
63
|
let stderr = '';
|
|
61
64
|
child.stdout.setEncoding('utf-8');
|
|
@@ -81,7 +84,7 @@ const PAC_HTTP_ERROR_RE = /HTTP error status:\s*[45]\d\d/i;
|
|
|
81
84
|
|
|
82
85
|
function resolveCredentialValues(state) {
|
|
83
86
|
return PAC_TARGET.resolveCredentialValues({
|
|
84
|
-
rootDir:
|
|
87
|
+
rootDir: PROJECT_DIR,
|
|
85
88
|
opBin: process.env.OP_BIN || (hasCommand('op') ? 'op' : null),
|
|
86
89
|
source: state.AUTH_MODE || 'auto',
|
|
87
90
|
});
|
|
@@ -90,7 +93,7 @@ function resolveCredentialValues(state) {
|
|
|
90
93
|
function verifyUserProfile(pac, projectDir, state, credentialValues) {
|
|
91
94
|
return PAC_TARGET.selectAndVerifyPacProfile({
|
|
92
95
|
pac,
|
|
93
|
-
rootDir:
|
|
96
|
+
rootDir: PROJECT_DIR,
|
|
94
97
|
wizardState: {
|
|
95
98
|
WIZARD_TARGET_ENV: state.WIZARD_TARGET_ENV || 'dev',
|
|
96
99
|
PP_ENV_DEV: state.PP_ENV_DEV || '',
|
|
@@ -153,7 +156,7 @@ export default {
|
|
|
153
156
|
},
|
|
154
157
|
|
|
155
158
|
async apply(answers, state, log) {
|
|
156
|
-
const projectDir = resolve(String(state.PROJECT_DIR ||
|
|
159
|
+
const projectDir = resolve(String(state.PROJECT_DIR || PROJECT_DIR));
|
|
157
160
|
if (!existsSync(join(projectDir, 'package.json'))) throw new Error(`No package.json found in ${projectDir}. Run Step 7 first.`);
|
|
158
161
|
|
|
159
162
|
log.info('Building project...');
|