@bluealba/platform-cli 0.3.0 → 0.3.1
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/dist/index.js +220 -208
- package/package.json +1 -1
- package/templates/customization-ui-module-template/Dockerfile +4 -4
- package/templates/customization-ui-module-template/Dockerfile.development +1 -1
- package/templates/customization-ui-module-template/package.json +3 -3
- package/templates/customization-ui-module-template/tsconfig.json +1 -1
- package/templates/customization-ui-module-template/webpack.config.js +2 -2
- package/templates/platform-init-template/{local → {{platformName}}-local}/.env.example +1 -1
- package/templates/platform-init-template/{{platformName}}-local/docker-compose.yml +3 -0
- package/templates/platform-init-template/{local → {{platformName}}-local}/package.json +3 -3
- package/templates/platform-init-template/{local → {{platformName}}-local}/scripts/build.sh +1 -1
- package/templates/platform-init-template/{local → {{platformName}}-local}/scripts/install.sh +1 -1
- package/templates/platform-init-template/{local/core-docker-compose.yml → {{platformName}}-local/{{platformName}}-core-docker-compose.yml} +5 -5
- package/templates/react-ui-module-template/Dockerfile +3 -3
- package/templates/react-ui-module-template/Dockerfile.development +1 -1
- package/templates/react-ui-module-template/package.json +1 -1
- package/templates/platform-init-template/local/docker-compose.yml +0 -3
- /package/templates/customization-ui-module-template/src/{platform-customization-ui.tsx → {{platformName}}-customization-ui.tsx} +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/.changeset/config.json +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/.nvmrc +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/.syncpackrc +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/package.json +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/packages-versions.json +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/scripts/preinstall.mjs +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/services/.gitkeep +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/turbo.json +0 -0
- /package/templates/platform-init-template/{core → {{platformName}}-core}/ui/.gitkeep +0 -0
- /package/templates/platform-init-template/{local → {{platformName}}-local}/environment/pae-nestjs-gateway-service.env +0 -0
- /package/templates/platform-init-template/{local → {{platformName}}-local}/nginx.conf +0 -0
- /package/templates/platform-init-template/{local → {{platformName}}-local}/platform-docker-compose.yml +0 -0
- /package/templates/platform-init-template/{local → {{platformName}}-local}/ssl/cert.pem +0 -0
- /package/templates/platform-init-template/{local → {{platformName}}-local}/ssl/key.pem +0 -0
package/dist/index.js
CHANGED
|
@@ -6,7 +6,7 @@ import { render } from "ink";
|
|
|
6
6
|
// src/app.tsx
|
|
7
7
|
import { createRequire } from "module";
|
|
8
8
|
import { useState as useState3, useCallback as useCallback2 } from "react";
|
|
9
|
-
import { Box as
|
|
9
|
+
import { Box as Box5, Text as Text7, useApp, useInput } from "ink";
|
|
10
10
|
|
|
11
11
|
// src/components/prompt.tsx
|
|
12
12
|
import { Box, Text } from "ink";
|
|
@@ -54,53 +54,71 @@ var CommandPalette = React.memo(function CommandPalette2({ commands, selectedInd
|
|
|
54
54
|
});
|
|
55
55
|
|
|
56
56
|
// src/components/scrollback-history.tsx
|
|
57
|
-
import { Static, Text as
|
|
57
|
+
import { Static, Text as Text5 } from "ink";
|
|
58
58
|
|
|
59
59
|
// src/components/welcome-banner.tsx
|
|
60
|
+
import React3 from "react";
|
|
61
|
+
import { Box as Box4, Text as Text4 } from "ink";
|
|
62
|
+
|
|
63
|
+
// src/components/working-directory.tsx
|
|
60
64
|
import React2 from "react";
|
|
65
|
+
import os from "os";
|
|
61
66
|
import { Box as Box3, Text as Text3 } from "ink";
|
|
62
67
|
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
68
|
+
var WorkingDirectory = React2.memo(function WorkingDirectory2() {
|
|
69
|
+
const cwd7 = process.cwd();
|
|
70
|
+
const home = os.homedir();
|
|
71
|
+
const displayPath = cwd7.startsWith(home) ? "~" + cwd7.slice(home.length) : cwd7;
|
|
72
|
+
return /* @__PURE__ */ jsxs3(Box3, { paddingLeft: 2, children: [
|
|
73
|
+
/* @__PURE__ */ jsx3(Text3, { bold: true, dimColor: true, children: "Working Dir: " }),
|
|
74
|
+
/* @__PURE__ */ jsx3(Text3, { dimColor: true, children: displayPath })
|
|
75
|
+
] });
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// src/components/welcome-banner.tsx
|
|
79
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
63
80
|
var ASCII_ART = [
|
|
64
81
|
"|---. .---|",
|
|
65
82
|
"| \\/ |",
|
|
66
83
|
"| /\\ |",
|
|
67
84
|
"|---' '---|"
|
|
68
85
|
];
|
|
69
|
-
var WelcomeBanner =
|
|
70
|
-
return /* @__PURE__ */
|
|
71
|
-
/* @__PURE__ */
|
|
86
|
+
var WelcomeBanner = React3.memo(function WelcomeBanner2({ version: version2 }) {
|
|
87
|
+
return /* @__PURE__ */ jsxs4(Box4, { borderStyle: "round", flexDirection: "column", paddingX: 1, paddingY: 1, children: [
|
|
88
|
+
/* @__PURE__ */ jsxs4(Text4, { bold: true, color: "cyan", children: [
|
|
72
89
|
"Blue Alba Platform CLI v",
|
|
73
90
|
version2
|
|
74
91
|
] }),
|
|
75
|
-
/* @__PURE__ */
|
|
76
|
-
/* @__PURE__ */
|
|
77
|
-
/* @__PURE__ */
|
|
78
|
-
/* @__PURE__ */
|
|
79
|
-
/* @__PURE__ */
|
|
92
|
+
/* @__PURE__ */ jsxs4(Box4, { marginTop: 1, children: [
|
|
93
|
+
/* @__PURE__ */ jsx4(Box4, { flexDirection: "column", marginRight: 2, children: ASCII_ART.map((line, i) => /* @__PURE__ */ jsx4(Text4, { color: "yellow", children: line }, i)) }),
|
|
94
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", justifyContent: "center", marginRight: 2, children: [
|
|
95
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, children: "Welcome to the" }),
|
|
96
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, children: "Blue Alba Platform!" })
|
|
80
97
|
] }),
|
|
81
|
-
/* @__PURE__ */
|
|
82
|
-
/* @__PURE__ */
|
|
83
|
-
/* @__PURE__ */
|
|
84
|
-
/* @__PURE__ */
|
|
98
|
+
/* @__PURE__ */ jsx4(Box4, { flexDirection: "column", children: ASCII_ART.map((_, i) => /* @__PURE__ */ jsx4(Text4, { dimColor: true, children: "\u2502" }, i)) }),
|
|
99
|
+
/* @__PURE__ */ jsxs4(Box4, { flexDirection: "column", marginLeft: 2, children: [
|
|
100
|
+
/* @__PURE__ */ jsx4(Text4, { bold: true, color: "cyan", children: "Tips for getting started" }),
|
|
101
|
+
/* @__PURE__ */ jsxs4(Text4, { children: [
|
|
85
102
|
"Run ",
|
|
86
|
-
/* @__PURE__ */
|
|
103
|
+
/* @__PURE__ */ jsx4(Text4, { color: "green", children: "/init" }),
|
|
87
104
|
" to start building a platform"
|
|
88
105
|
] })
|
|
89
106
|
] })
|
|
90
|
-
] })
|
|
107
|
+
] }),
|
|
108
|
+
/* @__PURE__ */ jsx4(Box4, { marginTop: 1, children: /* @__PURE__ */ jsx4(WorkingDirectory, {}) })
|
|
91
109
|
] });
|
|
92
110
|
});
|
|
93
111
|
|
|
94
112
|
// src/components/scrollback-history.tsx
|
|
95
|
-
import { jsx as
|
|
113
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
96
114
|
function ScrollbackHistory({ items, version: version2 }) {
|
|
97
|
-
return /* @__PURE__ */
|
|
115
|
+
return /* @__PURE__ */ jsx5(Static, { items, children: (item) => item.kind === "banner" ? /* @__PURE__ */ jsx5(WelcomeBanner, { version: version2 }, item.id) : /* @__PURE__ */ jsx5(Text5, { children: item.line }, item.id) });
|
|
98
116
|
}
|
|
99
117
|
|
|
100
118
|
// src/components/spinner.tsx
|
|
101
119
|
import { useState, useEffect } from "react";
|
|
102
|
-
import { Text as
|
|
103
|
-
import { jsx as
|
|
120
|
+
import { Text as Text6 } from "ink";
|
|
121
|
+
import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
104
122
|
var FRAMES = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
105
123
|
var INTERVAL_MS = 80;
|
|
106
124
|
function Spinner({ label }) {
|
|
@@ -111,12 +129,12 @@ function Spinner({ label }) {
|
|
|
111
129
|
}, INTERVAL_MS);
|
|
112
130
|
return () => clearInterval(id);
|
|
113
131
|
}, []);
|
|
114
|
-
return /* @__PURE__ */
|
|
115
|
-
/* @__PURE__ */
|
|
132
|
+
return /* @__PURE__ */ jsxs5(Text6, { children: [
|
|
133
|
+
/* @__PURE__ */ jsxs5(Text6, { color: "cyan", children: [
|
|
116
134
|
FRAMES[frame],
|
|
117
135
|
" "
|
|
118
136
|
] }),
|
|
119
|
-
label && /* @__PURE__ */
|
|
137
|
+
label && /* @__PURE__ */ jsx6(Text6, { dimColor: true, children: label })
|
|
120
138
|
] });
|
|
121
139
|
}
|
|
122
140
|
|
|
@@ -269,7 +287,7 @@ var reactUiModuleTemplateDir = join5(
|
|
|
269
287
|
"react-ui-module-template"
|
|
270
288
|
);
|
|
271
289
|
async function scaffoldUiModule(uiDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger) {
|
|
272
|
-
logger.log(`Creating UI module "${applicationName}-ui"...`);
|
|
290
|
+
logger.log(`Creating UI module "${platformName}-${applicationName}-ui"...`);
|
|
273
291
|
await applyTemplate(
|
|
274
292
|
{
|
|
275
293
|
templateDir: reactUiModuleTemplateDir,
|
|
@@ -290,8 +308,8 @@ var nestjsServiceModuleTemplateDir = join6(
|
|
|
290
308
|
"templates",
|
|
291
309
|
"nestjs-service-module-template"
|
|
292
310
|
);
|
|
293
|
-
async function scaffoldNestjsService(serviceDir, organizationName, applicationName, applicationDisplayName, serviceBaseDir, logger) {
|
|
294
|
-
const serviceName = `${applicationName}-service`;
|
|
311
|
+
async function scaffoldNestjsService(serviceDir, organizationName, platformName, applicationName, applicationDisplayName, serviceBaseDir, logger) {
|
|
312
|
+
const serviceName = `${platformName}-${applicationName}-service`;
|
|
295
313
|
const serviceDisplayName = `${applicationDisplayName} Service`;
|
|
296
314
|
logger.log(`Creating NestJS service "${serviceName}"...`);
|
|
297
315
|
await applyTemplate(
|
|
@@ -322,33 +340,33 @@ async function addModuleEntry(bootstrapServiceDir, applicationName, entry, logge
|
|
|
322
340
|
}
|
|
323
341
|
|
|
324
342
|
// src/commands/create-application/module-entry-builders.ts
|
|
325
|
-
function buildServiceModuleEntry(organizationName, applicationName, applicationDisplayName) {
|
|
343
|
+
function buildServiceModuleEntry(organizationName, platformName, applicationName, applicationDisplayName) {
|
|
326
344
|
return {
|
|
327
|
-
name: `@${organizationName}/${applicationName}-service`,
|
|
345
|
+
name: `@${organizationName}/${platformName}-${applicationName}-service`,
|
|
328
346
|
displayName: `${applicationDisplayName} Service`,
|
|
329
347
|
type: "service",
|
|
330
|
-
baseUrl: `/${applicationName}-service`,
|
|
348
|
+
baseUrl: `/${platformName}-${applicationName}-service`,
|
|
331
349
|
service: {
|
|
332
|
-
host: `${applicationName}-service`,
|
|
350
|
+
host: `${platformName}-${applicationName}-service`,
|
|
333
351
|
port: 80
|
|
334
352
|
},
|
|
335
353
|
dependsOn: []
|
|
336
354
|
};
|
|
337
355
|
}
|
|
338
|
-
function buildUiModuleEntry(organizationName, applicationName, applicationDisplayName) {
|
|
356
|
+
function buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName) {
|
|
339
357
|
return {
|
|
340
|
-
name: `@${organizationName}/${applicationName}-ui`,
|
|
358
|
+
name: `@${organizationName}/${platformName}-${applicationName}-ui`,
|
|
341
359
|
displayName: applicationDisplayName,
|
|
342
360
|
type: "app",
|
|
343
|
-
baseUrl: `/${applicationName}-ui`,
|
|
361
|
+
baseUrl: `/${platformName}-${applicationName}-ui`,
|
|
344
362
|
service: {
|
|
345
|
-
host: `${applicationName}-ui`,
|
|
363
|
+
host: `${platformName}-${applicationName}-ui`,
|
|
346
364
|
port: 80
|
|
347
365
|
},
|
|
348
366
|
ui: {
|
|
349
367
|
route: `/${applicationName}`,
|
|
350
368
|
mountAtSelector: "#pae-shell-ui-content",
|
|
351
|
-
bundleFile: `${organizationName}-${applicationName}-ui.js`,
|
|
369
|
+
bundleFile: `${organizationName}-${platformName}-${applicationName}-ui.js`,
|
|
352
370
|
customProps: {}
|
|
353
371
|
},
|
|
354
372
|
dependsOn: [`@bluealba/pae-shell-ui`]
|
|
@@ -357,14 +375,14 @@ function buildUiModuleEntry(organizationName, applicationName, applicationDispla
|
|
|
357
375
|
|
|
358
376
|
// src/commands/create-application/create-docker-compose.ts
|
|
359
377
|
import { writeFile as writeFile3 } from "fs/promises";
|
|
360
|
-
function buildBootstrapBlock(applicationName) {
|
|
361
|
-
return ` ${applicationName}-bootstrap-service:
|
|
378
|
+
function buildBootstrapBlock(platformName, applicationName) {
|
|
379
|
+
return ` ${platformName}-${applicationName}-bootstrap-service:
|
|
362
380
|
build:
|
|
363
|
-
context: ../${applicationName}/services/${applicationName}-bootstrap-service
|
|
381
|
+
context: ../${platformName}-${applicationName}/services/${platformName}-${applicationName}-bootstrap-service
|
|
364
382
|
dockerfile: Dockerfile.development
|
|
365
383
|
environment:
|
|
366
384
|
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
367
|
-
- SERVICE_ACCESS_NAME=${applicationName}-bootstrap
|
|
385
|
+
- SERVICE_ACCESS_NAME=${platformName}-${applicationName}-bootstrap
|
|
368
386
|
- WAIT_TIME=5000
|
|
369
387
|
- SYNC_STRATEGY=\${PAE_BOOTSTRAP_SYNC_STRATEGY}
|
|
370
388
|
- GATEWAY_SERVICE_URL=\${PAE_GATEWAY_URL}
|
|
@@ -376,10 +394,10 @@ function buildBootstrapBlock(applicationName) {
|
|
|
376
394
|
condition: service_healthy
|
|
377
395
|
`;
|
|
378
396
|
}
|
|
379
|
-
function buildUiBlock(applicationName, uiPort) {
|
|
380
|
-
return ` ${applicationName}-ui:
|
|
397
|
+
function buildUiBlock(platformName, applicationName, uiPort) {
|
|
398
|
+
return ` ${platformName}-${applicationName}-ui:
|
|
381
399
|
build:
|
|
382
|
-
context: ../${applicationName}/ui/${applicationName}-ui
|
|
400
|
+
context: ../${platformName}-${applicationName}/ui/${platformName}-${applicationName}-ui
|
|
383
401
|
dockerfile: Dockerfile.development
|
|
384
402
|
ports:
|
|
385
403
|
- ${uiPort}:80
|
|
@@ -387,10 +405,10 @@ function buildUiBlock(applicationName, uiPort) {
|
|
|
387
405
|
- \${PWD}/../:/app/out
|
|
388
406
|
`;
|
|
389
407
|
}
|
|
390
|
-
function buildBackendBlock(applicationName, servicePort) {
|
|
391
|
-
return ` ${applicationName}-service:
|
|
408
|
+
function buildBackendBlock(platformName, applicationName, servicePort) {
|
|
409
|
+
return ` ${platformName}-${applicationName}-service:
|
|
392
410
|
build:
|
|
393
|
-
context: ../${applicationName}/services/${applicationName}-service
|
|
411
|
+
context: ../${platformName}-${applicationName}/services/${platformName}-${applicationName}-service
|
|
394
412
|
dockerfile: Dockerfile.development
|
|
395
413
|
args:
|
|
396
414
|
- BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
|
|
@@ -402,13 +420,13 @@ function buildBackendBlock(applicationName, servicePort) {
|
|
|
402
420
|
- \${PWD}/../:/app/out
|
|
403
421
|
`;
|
|
404
422
|
}
|
|
405
|
-
async function createDockerCompose(dockerComposePath, applicationName, hasUserInterface, hasBackendService, uiPort, servicePort, logger) {
|
|
406
|
-
const blocks = ["services:\n", buildBootstrapBlock(applicationName)];
|
|
423
|
+
async function createDockerCompose(dockerComposePath, platformName, applicationName, hasUserInterface, hasBackendService, uiPort, servicePort, logger) {
|
|
424
|
+
const blocks = ["services:\n", buildBootstrapBlock(platformName, applicationName)];
|
|
407
425
|
if (hasUserInterface) {
|
|
408
|
-
blocks.push(buildUiBlock(applicationName, uiPort));
|
|
426
|
+
blocks.push(buildUiBlock(platformName, applicationName, uiPort));
|
|
409
427
|
}
|
|
410
428
|
if (hasBackendService) {
|
|
411
|
-
blocks.push(buildBackendBlock(applicationName, servicePort));
|
|
429
|
+
blocks.push(buildBackendBlock(platformName, applicationName, servicePort));
|
|
412
430
|
}
|
|
413
431
|
const content = blocks.join("\n");
|
|
414
432
|
try {
|
|
@@ -422,10 +440,10 @@ async function createDockerCompose(dockerComposePath, applicationName, hasUserIn
|
|
|
422
440
|
|
|
423
441
|
// src/commands/create-application/update-root-docker-compose.ts
|
|
424
442
|
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
425
|
-
async function updateRootDockerCompose(rootDockerComposePath, applicationName, logger) {
|
|
443
|
+
async function updateRootDockerCompose(rootDockerComposePath, platformName, applicationName, logger) {
|
|
426
444
|
try {
|
|
427
445
|
const existing = await readFile3(rootDockerComposePath, "utf-8");
|
|
428
|
-
const includeLine = ` - path: ./${applicationName}-docker-compose.yml
|
|
446
|
+
const includeLine = ` - path: ./${platformName}-${applicationName}-docker-compose.yml
|
|
429
447
|
`;
|
|
430
448
|
await writeFile4(rootDockerComposePath, existing + includeLine, "utf-8");
|
|
431
449
|
logger.log(`Updated root docker-compose: ${rootDockerComposePath}`);
|
|
@@ -465,13 +483,34 @@ function formatError(err) {
|
|
|
465
483
|
}
|
|
466
484
|
|
|
467
485
|
// src/utils/platform-check.ts
|
|
468
|
-
import { access } from "fs/promises";
|
|
486
|
+
import { access, readdir as readdir3, readFile as readFile5 } from "fs/promises";
|
|
469
487
|
import { join as join9 } from "path";
|
|
470
488
|
import { cwd } from "process";
|
|
489
|
+
async function findCoreDirName(dir) {
|
|
490
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
491
|
+
const coreEntry = entries.find((e) => e.isDirectory() && e.name.endsWith("-core"));
|
|
492
|
+
return coreEntry?.name ?? null;
|
|
493
|
+
}
|
|
494
|
+
async function readPlatformManifest(dir) {
|
|
495
|
+
const baseDir = dir ?? cwd();
|
|
496
|
+
const coreDirName = await findCoreDirName(baseDir);
|
|
497
|
+
if (!coreDirName) {
|
|
498
|
+
throw new Error("No *-core directory found \u2014 platform not initialized in this directory.");
|
|
499
|
+
}
|
|
500
|
+
const platformName = coreDirName.replace(/-core$/, "");
|
|
501
|
+
const pkgJson = JSON.parse(await readFile5(join9(baseDir, coreDirName, "package.json"), "utf-8"));
|
|
502
|
+
const scopeMatch = pkgJson.name.match(/^@([^/]+)\//);
|
|
503
|
+
if (!scopeMatch) {
|
|
504
|
+
throw new Error(`Could not parse organization from package name: "${pkgJson.name}"`);
|
|
505
|
+
}
|
|
506
|
+
return { platformName, organizationName: scopeMatch[1] };
|
|
507
|
+
}
|
|
471
508
|
async function isPlatformInitialized() {
|
|
472
509
|
try {
|
|
473
|
-
await
|
|
474
|
-
|
|
510
|
+
const coreDirName = await findCoreDirName(cwd());
|
|
511
|
+
if (!coreDirName) return false;
|
|
512
|
+
const platformName = coreDirName.replace(/-core$/, "");
|
|
513
|
+
await access(join9(cwd(), `${platformName}-local`));
|
|
475
514
|
return true;
|
|
476
515
|
} catch {
|
|
477
516
|
return false;
|
|
@@ -499,10 +538,10 @@ async function createApplication(params, logger) {
|
|
|
499
538
|
return;
|
|
500
539
|
}
|
|
501
540
|
const rootDir = cwd2();
|
|
502
|
-
const applicationDir = join10(rootDir, applicationName);
|
|
503
|
-
const bootstrapServiceDir = join10(applicationDir, "services", `${applicationName}-bootstrap-service`);
|
|
504
|
-
const localDir = join10(rootDir,
|
|
505
|
-
logger.log(`Creating application monorepo "${applicationName}"...`);
|
|
541
|
+
const applicationDir = join10(rootDir, `${platformName}-${applicationName}`);
|
|
542
|
+
const bootstrapServiceDir = join10(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
|
|
543
|
+
const localDir = join10(rootDir, `${platformName}-local`);
|
|
544
|
+
logger.log(`Creating application monorepo "${platformName}-${applicationName}"...`);
|
|
506
545
|
try {
|
|
507
546
|
await scaffoldApplicationMonorepo(applicationDir, organizationName, platformName, applicationName, logger);
|
|
508
547
|
} catch (err) {
|
|
@@ -511,10 +550,10 @@ async function createApplication(params, logger) {
|
|
|
511
550
|
}
|
|
512
551
|
await mkdir2(join10(applicationDir, "services"), { recursive: true });
|
|
513
552
|
await mkdir2(join10(applicationDir, "ui"), { recursive: true });
|
|
514
|
-
logger.log(`Creating bootstrap service "${applicationName}-bootstrap-service"...`);
|
|
515
|
-
const bootstrapServiceDir_var = `${applicationName}/services`;
|
|
553
|
+
logger.log(`Creating bootstrap service "${platformName}-${applicationName}-bootstrap-service"...`);
|
|
554
|
+
const bootstrapServiceDir_var = `${platformName}-${applicationName}/services`;
|
|
516
555
|
try {
|
|
517
|
-
await scaffoldBootstrap(bootstrapServiceDir, organizationName, applicationName
|
|
556
|
+
await scaffoldBootstrap(bootstrapServiceDir, organizationName, `${platformName}-${applicationName}`, bootstrapServiceDir_var, logger);
|
|
518
557
|
} catch (err) {
|
|
519
558
|
logger.log(`Error: Could not scaffold bootstrap service \u2014 ${formatError(err)}`);
|
|
520
559
|
return;
|
|
@@ -530,7 +569,7 @@ async function createApplication(params, logger) {
|
|
|
530
569
|
await addModuleEntry(
|
|
531
570
|
bootstrapServiceDir,
|
|
532
571
|
applicationName,
|
|
533
|
-
buildUiModuleEntry(organizationName, applicationName, applicationDisplayName),
|
|
572
|
+
buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName),
|
|
534
573
|
logger
|
|
535
574
|
);
|
|
536
575
|
}
|
|
@@ -538,13 +577,13 @@ async function createApplication(params, logger) {
|
|
|
538
577
|
await addModuleEntry(
|
|
539
578
|
bootstrapServiceDir,
|
|
540
579
|
applicationName,
|
|
541
|
-
buildServiceModuleEntry(organizationName, applicationName, applicationDisplayName),
|
|
580
|
+
buildServiceModuleEntry(organizationName, platformName, applicationName, applicationDisplayName),
|
|
542
581
|
logger
|
|
543
582
|
);
|
|
544
583
|
}
|
|
545
584
|
if (hasUserInterface) {
|
|
546
|
-
const uiDir = join10(applicationDir, "ui", `${applicationName}-ui`);
|
|
547
|
-
const uiBaseDir = `${applicationName}/ui`;
|
|
585
|
+
const uiDir = join10(applicationDir, "ui", `${platformName}-${applicationName}-ui`);
|
|
586
|
+
const uiBaseDir = `${platformName}-${applicationName}/ui`;
|
|
548
587
|
try {
|
|
549
588
|
await scaffoldUiModule(uiDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger);
|
|
550
589
|
} catch (err) {
|
|
@@ -553,21 +592,22 @@ async function createApplication(params, logger) {
|
|
|
553
592
|
}
|
|
554
593
|
}
|
|
555
594
|
if (hasBackendService) {
|
|
556
|
-
const serviceDir = join10(applicationDir, "services", `${applicationName}-service`);
|
|
557
|
-
const serviceBaseDir = `${applicationName}/services`;
|
|
595
|
+
const serviceDir = join10(applicationDir, "services", `${platformName}-${applicationName}-service`);
|
|
596
|
+
const serviceBaseDir = `${platformName}-${applicationName}/services`;
|
|
558
597
|
try {
|
|
559
|
-
await scaffoldNestjsService(serviceDir, organizationName, applicationName, applicationDisplayName, serviceBaseDir, logger);
|
|
598
|
+
await scaffoldNestjsService(serviceDir, organizationName, platformName, applicationName, applicationDisplayName, serviceBaseDir, logger);
|
|
560
599
|
} catch (err) {
|
|
561
600
|
logger.log(`Error: Could not scaffold NestJS service \u2014 ${formatError(err)}`);
|
|
562
601
|
return;
|
|
563
602
|
}
|
|
564
603
|
}
|
|
565
|
-
const dockerComposePath = join10(localDir, `${applicationName}-docker-compose.yml`);
|
|
604
|
+
const dockerComposePath = join10(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
|
|
566
605
|
const basePort = await getNextAvailablePort(localDir);
|
|
567
606
|
const uiPort = hasUserInterface ? basePort : 0;
|
|
568
607
|
const servicePort = hasBackendService ? hasUserInterface ? basePort + 1 : basePort : 0;
|
|
569
608
|
await createDockerCompose(
|
|
570
609
|
dockerComposePath,
|
|
610
|
+
platformName,
|
|
571
611
|
applicationName,
|
|
572
612
|
hasUserInterface,
|
|
573
613
|
hasBackendService,
|
|
@@ -576,8 +616,8 @@ async function createApplication(params, logger) {
|
|
|
576
616
|
logger
|
|
577
617
|
);
|
|
578
618
|
const rootDockerComposePath = join10(localDir, "docker-compose.yml");
|
|
579
|
-
await updateRootDockerCompose(rootDockerComposePath, applicationName, logger);
|
|
580
|
-
logger.log(`Done! Application "${applicationName}" created at ${applicationDir}`);
|
|
619
|
+
await updateRootDockerCompose(rootDockerComposePath, platformName, applicationName, logger);
|
|
620
|
+
logger.log(`Done! Application "${platformName}-${applicationName}" created at ${applicationDir}`);
|
|
581
621
|
}
|
|
582
622
|
|
|
583
623
|
// src/commands/init/init.command.ts
|
|
@@ -630,31 +670,31 @@ async function scaffoldCustomizationUi(outputDir, variables, logger) {
|
|
|
630
670
|
|
|
631
671
|
// src/commands/init/register-customization-module.ts
|
|
632
672
|
import { join as join14 } from "path";
|
|
633
|
-
import { readFile as
|
|
634
|
-
async function registerCustomizationModule(bootstrapServiceDir, organizationName, logger) {
|
|
673
|
+
import { readFile as readFile6, writeFile as writeFile5 } from "fs/promises";
|
|
674
|
+
async function registerCustomizationModule(bootstrapServiceDir, organizationName, platformName, logger) {
|
|
635
675
|
const modulesJsonPath = join14(bootstrapServiceDir, "src", "data", "platform", "modules.json");
|
|
636
676
|
const entry = {
|
|
637
|
-
name: `@${organizationName}
|
|
677
|
+
name: `@${organizationName}/${platformName}-customization-ui`,
|
|
638
678
|
displayName: "Platform Customization UI",
|
|
639
679
|
type: "app",
|
|
640
|
-
baseUrl:
|
|
641
|
-
service: { host:
|
|
680
|
+
baseUrl: `/${platformName}-customization-ui`,
|
|
681
|
+
service: { host: `${platformName}-customization-ui`, port: 80 },
|
|
642
682
|
ui: {
|
|
643
683
|
route: "/",
|
|
644
|
-
bundleFile:
|
|
684
|
+
bundleFile: `${platformName}-customization-ui.js`,
|
|
645
685
|
isPlatformCustomization: true,
|
|
646
686
|
customProps: {}
|
|
647
687
|
},
|
|
648
688
|
dependsOn: []
|
|
649
689
|
};
|
|
650
|
-
const existing = JSON.parse(await
|
|
690
|
+
const existing = JSON.parse(await readFile6(modulesJsonPath, "utf-8"));
|
|
651
691
|
existing.push(entry);
|
|
652
692
|
await writeFile5(modulesJsonPath, JSON.stringify(existing, null, 2) + "\n", "utf-8");
|
|
653
693
|
logger.log(`Registered customization module in ${modulesJsonPath}`);
|
|
654
694
|
}
|
|
655
695
|
|
|
656
696
|
// src/commands/init/generate-local-env.ts
|
|
657
|
-
import { readFile as
|
|
697
|
+
import { readFile as readFile7, writeFile as writeFile6 } from "fs/promises";
|
|
658
698
|
import { join as join15 } from "path";
|
|
659
699
|
|
|
660
700
|
// src/utils/random.ts
|
|
@@ -664,11 +704,11 @@ function generateRandomSecret() {
|
|
|
664
704
|
}
|
|
665
705
|
|
|
666
706
|
// src/commands/init/generate-local-env.ts
|
|
667
|
-
async function generateLocalEnv(outputDir, logger) {
|
|
668
|
-
const examplePath = join15(outputDir,
|
|
669
|
-
const envPath = join15(outputDir,
|
|
670
|
-
logger.log(
|
|
671
|
-
const content = await
|
|
707
|
+
async function generateLocalEnv(outputDir, platformName, logger) {
|
|
708
|
+
const examplePath = join15(outputDir, `${platformName}-local`, ".env.example");
|
|
709
|
+
const envPath = join15(outputDir, `${platformName}-local`, ".env");
|
|
710
|
+
logger.log(`Generating ${platformName}-local/.env with random secrets...`);
|
|
711
|
+
const content = await readFile7(examplePath, "utf-8");
|
|
672
712
|
const result = content.replace(/^(PAE_AUTH_JWT_SECRET|PAE_GATEWAY_SERVICE_ACCESS_SECRET|PAE_DB_PASSWORD)=$/gm, (_, key) => {
|
|
673
713
|
return `${key}=${generateRandomSecret()}`;
|
|
674
714
|
});
|
|
@@ -695,8 +735,8 @@ async function init(params, logger) {
|
|
|
695
735
|
platformName,
|
|
696
736
|
platformTitle,
|
|
697
737
|
platformDisplayName,
|
|
698
|
-
bootstrapName:
|
|
699
|
-
bootstrapServiceDir:
|
|
738
|
+
bootstrapName: platformName,
|
|
739
|
+
bootstrapServiceDir: `${platformName}-core/services`
|
|
700
740
|
};
|
|
701
741
|
try {
|
|
702
742
|
await scaffoldPlatform(outputDir, variables, logger);
|
|
@@ -705,14 +745,14 @@ async function init(params, logger) {
|
|
|
705
745
|
return;
|
|
706
746
|
}
|
|
707
747
|
try {
|
|
708
|
-
await generateLocalEnv(outputDir, logger);
|
|
748
|
+
await generateLocalEnv(outputDir, platformName, logger);
|
|
709
749
|
} catch (err) {
|
|
710
|
-
logger.log(`Error: Could not generate local/.env \u2014 ${formatError(err)}`);
|
|
750
|
+
logger.log(`Error: Could not generate ${platformName}-local/.env \u2014 ${formatError(err)}`);
|
|
711
751
|
return;
|
|
712
752
|
}
|
|
713
753
|
try {
|
|
714
754
|
await scaffoldPlatformBootstrap(
|
|
715
|
-
join16(outputDir,
|
|
755
|
+
join16(outputDir, `${platformName}-core`, "services", `${platformName}-bootstrap-service`),
|
|
716
756
|
variables,
|
|
717
757
|
logger
|
|
718
758
|
);
|
|
@@ -722,7 +762,7 @@ async function init(params, logger) {
|
|
|
722
762
|
}
|
|
723
763
|
try {
|
|
724
764
|
await scaffoldCustomizationUi(
|
|
725
|
-
join16(outputDir,
|
|
765
|
+
join16(outputDir, `${platformName}-core`, "ui", `${platformName}-customization-ui`),
|
|
726
766
|
variables,
|
|
727
767
|
logger
|
|
728
768
|
);
|
|
@@ -732,8 +772,9 @@ async function init(params, logger) {
|
|
|
732
772
|
}
|
|
733
773
|
try {
|
|
734
774
|
await registerCustomizationModule(
|
|
735
|
-
join16(outputDir,
|
|
775
|
+
join16(outputDir, `${platformName}-core`, "services", `${platformName}-bootstrap-service`),
|
|
736
776
|
organizationName,
|
|
777
|
+
platformName,
|
|
737
778
|
logger
|
|
738
779
|
);
|
|
739
780
|
} catch (err) {
|
|
@@ -749,11 +790,11 @@ import { cwd as cwd4 } from "process";
|
|
|
749
790
|
import { fetch as undiciFetch, Agent } from "undici";
|
|
750
791
|
|
|
751
792
|
// src/utils/env-reader.ts
|
|
752
|
-
import { readFile as
|
|
793
|
+
import { readFile as readFile8 } from "fs/promises";
|
|
753
794
|
async function readEnvFile(filePath) {
|
|
754
795
|
let content;
|
|
755
796
|
try {
|
|
756
|
-
content = await
|
|
797
|
+
content = await readFile8(filePath, "utf-8");
|
|
757
798
|
} catch (error) {
|
|
758
799
|
if (error.code === "ENOENT") {
|
|
759
800
|
throw new Error(`.env file not found at ${filePath}`);
|
|
@@ -827,7 +868,8 @@ async function configureIdp(params, logger) {
|
|
|
827
868
|
logger.log("Error: Cannot configure an IDP \u2014 no platform initialized in this directory.");
|
|
828
869
|
return;
|
|
829
870
|
}
|
|
830
|
-
const
|
|
871
|
+
const { platformName } = await readPlatformManifest();
|
|
872
|
+
const envPath = join17(cwd4(), `${platformName}-local`, ".env");
|
|
831
873
|
let env;
|
|
832
874
|
try {
|
|
833
875
|
env = await readEnvFile(envPath);
|
|
@@ -838,11 +880,11 @@ async function configureIdp(params, logger) {
|
|
|
838
880
|
const gatewayUrl = env.get("PAE_GATEWAY_HOST_URL");
|
|
839
881
|
const accessSecret = env.get("PAE_GATEWAY_SERVICE_ACCESS_SECRET");
|
|
840
882
|
if (!gatewayUrl) {
|
|
841
|
-
logger.log(
|
|
883
|
+
logger.log(`Error: PAE_GATEWAY_HOST_URL is not set in ${platformName}-local/.env`);
|
|
842
884
|
return;
|
|
843
885
|
}
|
|
844
886
|
if (!accessSecret) {
|
|
845
|
-
logger.log(
|
|
887
|
+
logger.log(`Error: PAE_GATEWAY_SERVICE_ACCESS_SECRET is not set in ${platformName}-local/.env`);
|
|
846
888
|
return;
|
|
847
889
|
}
|
|
848
890
|
const provider = idpProviderRegistry.get(params.providerType);
|
|
@@ -881,7 +923,7 @@ async function configureIdp(params, logger) {
|
|
|
881
923
|
// src/commands/create-service-module/create-service-module.command.ts
|
|
882
924
|
import { join as join19 } from "path";
|
|
883
925
|
import { cwd as cwd5 } from "process";
|
|
884
|
-
import { access as access2
|
|
926
|
+
import { access as access2 } from "fs/promises";
|
|
885
927
|
|
|
886
928
|
// src/commands/create-service-module/scaffold-service-module.ts
|
|
887
929
|
import { fileURLToPath as fileURLToPath9 } from "url";
|
|
@@ -921,12 +963,12 @@ function buildCustomServiceModuleEntry(organizationName, serviceName, serviceDis
|
|
|
921
963
|
}
|
|
922
964
|
|
|
923
965
|
// src/commands/create-service-module/append-docker-compose.ts
|
|
924
|
-
import { readFile as
|
|
925
|
-
async function appendServiceToDockerCompose(dockerComposePath, serviceName, applicationName, port, logger) {
|
|
966
|
+
import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
967
|
+
async function appendServiceToDockerCompose(dockerComposePath, serviceName, platformName, applicationName, port, logger) {
|
|
926
968
|
const block = `
|
|
927
969
|
${serviceName}:
|
|
928
970
|
build:
|
|
929
|
-
context: ../${applicationName}/services/${serviceName}
|
|
971
|
+
context: ../${platformName}-${applicationName}/services/${serviceName}
|
|
930
972
|
dockerfile: Dockerfile.development
|
|
931
973
|
args:
|
|
932
974
|
- BA_NPM_AUTH_TOKEN=$BA_NPM_AUTH_TOKEN
|
|
@@ -938,7 +980,7 @@ async function appendServiceToDockerCompose(dockerComposePath, serviceName, appl
|
|
|
938
980
|
- \${PWD}/../:/app/out
|
|
939
981
|
`;
|
|
940
982
|
try {
|
|
941
|
-
const existing = await
|
|
983
|
+
const existing = await readFile9(dockerComposePath, "utf-8");
|
|
942
984
|
await writeFile7(dockerComposePath, existing + block, "utf-8");
|
|
943
985
|
logger.log(`Updated docker-compose: ${dockerComposePath}`);
|
|
944
986
|
} catch (err) {
|
|
@@ -960,36 +1002,32 @@ async function createServiceModule(params, logger) {
|
|
|
960
1002
|
return;
|
|
961
1003
|
}
|
|
962
1004
|
const rootDir = cwd5();
|
|
963
|
-
|
|
1005
|
+
let organizationName;
|
|
1006
|
+
let platformName;
|
|
1007
|
+
try {
|
|
1008
|
+
const manifest = await readPlatformManifest(rootDir);
|
|
1009
|
+
organizationName = manifest.organizationName;
|
|
1010
|
+
platformName = manifest.platformName;
|
|
1011
|
+
} catch (err) {
|
|
1012
|
+
logger.log(`Error: Could not read .platform.json \u2014 ${formatError(err)}`);
|
|
1013
|
+
return;
|
|
1014
|
+
}
|
|
1015
|
+
const applicationDir = join19(rootDir, `${platformName}-${applicationName}`);
|
|
964
1016
|
try {
|
|
965
1017
|
await access2(applicationDir);
|
|
966
1018
|
} catch {
|
|
967
|
-
logger.log(`Error: The specified application "${applicationName}" does not exist in the platform.`);
|
|
1019
|
+
logger.log(`Error: The specified application "${platformName}-${applicationName}" does not exist in the platform.`);
|
|
968
1020
|
return;
|
|
969
1021
|
}
|
|
970
|
-
const fullServiceName = `${serviceName}-service`;
|
|
1022
|
+
const fullServiceName = `${platformName}-${serviceName}-service`;
|
|
971
1023
|
const serviceDir = join19(applicationDir, "services", fullServiceName);
|
|
972
1024
|
try {
|
|
973
1025
|
await access2(serviceDir);
|
|
974
|
-
logger.log(`Error: A service named "${fullServiceName}" already exists in application "${applicationName}".`);
|
|
1026
|
+
logger.log(`Error: A service named "${fullServiceName}" already exists in application "${platformName}-${applicationName}".`);
|
|
975
1027
|
return;
|
|
976
1028
|
} catch {
|
|
977
1029
|
}
|
|
978
|
-
|
|
979
|
-
try {
|
|
980
|
-
const corePackageJson = JSON.parse(
|
|
981
|
-
await readFile9(join19(rootDir, "core", "package.json"), "utf-8")
|
|
982
|
-
);
|
|
983
|
-
const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
|
|
984
|
-
organizationName = scopeMatch?.[1];
|
|
985
|
-
if (!organizationName) {
|
|
986
|
-
throw new Error(`Could not parse organization from package name: "${corePackageJson.name}"`);
|
|
987
|
-
}
|
|
988
|
-
} catch (err) {
|
|
989
|
-
logger.log(`Error: Could not read core/package.json \u2014 ${formatError(err)}`);
|
|
990
|
-
return;
|
|
991
|
-
}
|
|
992
|
-
const serviceBaseDir = `${applicationName}/services`;
|
|
1030
|
+
const serviceBaseDir = `${platformName}-${applicationName}/services`;
|
|
993
1031
|
try {
|
|
994
1032
|
await scaffoldServiceModule(
|
|
995
1033
|
serviceDir,
|
|
@@ -1003,28 +1041,28 @@ async function createServiceModule(params, logger) {
|
|
|
1003
1041
|
logger.log(`Error: Could not scaffold NestJS service \u2014 ${formatError(err)}`);
|
|
1004
1042
|
return;
|
|
1005
1043
|
}
|
|
1006
|
-
const bootstrapServiceDir = join19(applicationDir, "services", `${applicationName}-bootstrap-service`);
|
|
1044
|
+
const bootstrapServiceDir = join19(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
|
|
1007
1045
|
const moduleEntry = buildCustomServiceModuleEntry(organizationName, fullServiceName, serviceDisplayName);
|
|
1008
1046
|
await addModuleEntry(bootstrapServiceDir, applicationName, moduleEntry, logger);
|
|
1009
|
-
const localDir = join19(rootDir,
|
|
1010
|
-
const dockerComposePath = join19(localDir, `${applicationName}-docker-compose.yml`);
|
|
1047
|
+
const localDir = join19(rootDir, `${platformName}-local`);
|
|
1048
|
+
const dockerComposePath = join19(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
|
|
1011
1049
|
const port = await getNextAvailablePort(localDir);
|
|
1012
|
-
await appendServiceToDockerCompose(dockerComposePath, fullServiceName, applicationName, port, logger);
|
|
1013
|
-
logger.log(`Done! Service module "${fullServiceName}" added to application "${applicationName}".`);
|
|
1050
|
+
await appendServiceToDockerCompose(dockerComposePath, fullServiceName, platformName, applicationName, port, logger);
|
|
1051
|
+
logger.log(`Done! Service module "${fullServiceName}" added to application "${platformName}-${applicationName}".`);
|
|
1014
1052
|
}
|
|
1015
1053
|
|
|
1016
1054
|
// src/commands/create-ui-module/create-ui-module.command.ts
|
|
1017
1055
|
import { join as join20 } from "path";
|
|
1018
1056
|
import { cwd as cwd6 } from "process";
|
|
1019
|
-
import { access as access3, readdir as
|
|
1057
|
+
import { access as access3, readdir as readdir4 } from "fs/promises";
|
|
1020
1058
|
|
|
1021
1059
|
// src/commands/create-ui-module/append-ui-docker-compose.ts
|
|
1022
1060
|
import { readFile as readFile10, writeFile as writeFile8 } from "fs/promises";
|
|
1023
|
-
async function appendUiToDockerCompose(dockerComposePath, applicationName, port, logger) {
|
|
1061
|
+
async function appendUiToDockerCompose(dockerComposePath, platformName, applicationName, port, logger) {
|
|
1024
1062
|
const block = `
|
|
1025
|
-
${applicationName}-ui:
|
|
1063
|
+
${platformName}-${applicationName}-ui:
|
|
1026
1064
|
build:
|
|
1027
|
-
context: ../${applicationName}/ui/${applicationName}-ui
|
|
1065
|
+
context: ../${platformName}-${applicationName}/ui/${platformName}-${applicationName}-ui
|
|
1028
1066
|
dockerfile: Dockerfile.development
|
|
1029
1067
|
ports:
|
|
1030
1068
|
- ${port}:80
|
|
@@ -1054,56 +1092,49 @@ async function createUiModule(params, logger) {
|
|
|
1054
1092
|
return;
|
|
1055
1093
|
}
|
|
1056
1094
|
const rootDir = cwd6();
|
|
1057
|
-
|
|
1095
|
+
let organizationName;
|
|
1096
|
+
let platformName;
|
|
1097
|
+
try {
|
|
1098
|
+
const manifest = await readPlatformManifest(rootDir);
|
|
1099
|
+
organizationName = manifest.organizationName;
|
|
1100
|
+
platformName = manifest.platformName;
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
logger.log(`Error: Could not read .platform.json \u2014 ${formatError(err)}`);
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
const applicationDir = join20(rootDir, `${platformName}-${applicationName}`);
|
|
1058
1106
|
try {
|
|
1059
1107
|
await access3(applicationDir);
|
|
1060
1108
|
} catch {
|
|
1061
|
-
logger.log(`Error: The specified application "${applicationName}" does not exist in the platform.`);
|
|
1109
|
+
logger.log(`Error: The specified application "${platformName}-${applicationName}" does not exist in the platform.`);
|
|
1062
1110
|
return;
|
|
1063
1111
|
}
|
|
1064
1112
|
const uiDir = join20(applicationDir, "ui");
|
|
1065
1113
|
try {
|
|
1066
|
-
const uiEntries = await
|
|
1114
|
+
const uiEntries = await readdir4(uiDir);
|
|
1067
1115
|
const existingUiModules = uiEntries.filter((e) => e !== ".gitkeep");
|
|
1068
1116
|
if (existingUiModules.length > 0) {
|
|
1069
|
-
logger.log(`Error: Currently we support only one UI module per application. Application "${applicationName}" already has a UI module.`);
|
|
1117
|
+
logger.log(`Error: Currently we support only one UI module per application. Application "${platformName}-${applicationName}" already has a UI module.`);
|
|
1070
1118
|
return;
|
|
1071
1119
|
}
|
|
1072
1120
|
} catch {
|
|
1073
1121
|
}
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
try {
|
|
1077
|
-
const corePackageJson = JSON.parse(
|
|
1078
|
-
await readFile11(join20(rootDir, "core", "package.json"), "utf-8")
|
|
1079
|
-
);
|
|
1080
|
-
const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
|
|
1081
|
-
organizationName = scopeMatch?.[1];
|
|
1082
|
-
const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
|
|
1083
|
-
platformName = rawName;
|
|
1084
|
-
if (!organizationName || !platformName) {
|
|
1085
|
-
throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
|
|
1086
|
-
}
|
|
1087
|
-
} catch (err) {
|
|
1088
|
-
logger.log(`Error: Could not read core/package.json \u2014 ${formatError(err)}`);
|
|
1089
|
-
return;
|
|
1090
|
-
}
|
|
1091
|
-
const uiOutputDir = join20(uiDir, `${applicationName}-ui`);
|
|
1092
|
-
const uiBaseDir = `${applicationName}/ui`;
|
|
1122
|
+
const uiOutputDir = join20(uiDir, `${platformName}-${applicationName}-ui`);
|
|
1123
|
+
const uiBaseDir = `${platformName}-${applicationName}/ui`;
|
|
1093
1124
|
try {
|
|
1094
1125
|
await scaffoldUiModule(uiOutputDir, organizationName, platformName, applicationName, applicationDisplayName, uiBaseDir, logger);
|
|
1095
1126
|
} catch (err) {
|
|
1096
1127
|
logger.log(`Error: Could not scaffold UI module \u2014 ${formatError(err)}`);
|
|
1097
1128
|
return;
|
|
1098
1129
|
}
|
|
1099
|
-
const bootstrapServiceDir = join20(applicationDir, "services", `${applicationName}-bootstrap-service`);
|
|
1100
|
-
const moduleEntry = buildUiModuleEntry(organizationName, applicationName, applicationDisplayName);
|
|
1130
|
+
const bootstrapServiceDir = join20(applicationDir, "services", `${platformName}-${applicationName}-bootstrap-service`);
|
|
1131
|
+
const moduleEntry = buildUiModuleEntry(organizationName, platformName, applicationName, applicationDisplayName);
|
|
1101
1132
|
await addModuleEntry(bootstrapServiceDir, applicationName, moduleEntry, logger);
|
|
1102
|
-
const localDir = join20(rootDir,
|
|
1103
|
-
const dockerComposePath = join20(localDir, `${applicationName}-docker-compose.yml`);
|
|
1133
|
+
const localDir = join20(rootDir, `${platformName}-local`);
|
|
1134
|
+
const dockerComposePath = join20(localDir, `${platformName}-${applicationName}-docker-compose.yml`);
|
|
1104
1135
|
const port = await getNextAvailablePort(localDir);
|
|
1105
|
-
await appendUiToDockerCompose(dockerComposePath, applicationName, port, logger);
|
|
1106
|
-
logger.log(`Done! UI module "${applicationName}-ui" added to application "${applicationName}".`);
|
|
1136
|
+
await appendUiToDockerCompose(dockerComposePath, platformName, applicationName, port, logger);
|
|
1137
|
+
logger.log(`Done! UI module "${platformName}-${applicationName}-ui" added to application "${platformName}-${applicationName}".`);
|
|
1107
1138
|
}
|
|
1108
1139
|
|
|
1109
1140
|
// src/commands/registry.ts
|
|
@@ -1145,11 +1176,6 @@ var APP_STATE = {
|
|
|
1145
1176
|
// src/hooks/use-command-runner.ts
|
|
1146
1177
|
import { useState as useState2, useCallback, useRef } from "react";
|
|
1147
1178
|
|
|
1148
|
-
// src/controllers/ui/create-application.ui-controller.ts
|
|
1149
|
-
import { readFile as readFile12 } from "fs/promises";
|
|
1150
|
-
import { join as join21 } from "path";
|
|
1151
|
-
import { cwd as cwd7 } from "process";
|
|
1152
|
-
|
|
1153
1179
|
// src/services/create-application.service.ts
|
|
1154
1180
|
async function createApplicationService(params, logger) {
|
|
1155
1181
|
await createApplication(params, logger);
|
|
@@ -1164,19 +1190,12 @@ async function createApplicationUiController(ctx) {
|
|
|
1164
1190
|
let organizationName;
|
|
1165
1191
|
let platformName;
|
|
1166
1192
|
try {
|
|
1167
|
-
const
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
|
|
1171
|
-
organizationName = scopeMatch?.[1];
|
|
1172
|
-
const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
|
|
1173
|
-
platformName = rawName;
|
|
1174
|
-
if (!organizationName || !platformName) {
|
|
1175
|
-
throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
|
|
1176
|
-
}
|
|
1193
|
+
const manifest = await readPlatformManifest();
|
|
1194
|
+
organizationName = manifest.organizationName;
|
|
1195
|
+
platformName = manifest.platformName;
|
|
1177
1196
|
} catch (err) {
|
|
1178
1197
|
const message = err instanceof Error ? err.message : String(err);
|
|
1179
|
-
ctx.log(`Error: Could not read
|
|
1198
|
+
ctx.log(`Error: Could not read .platform.json \u2014 ${message}`);
|
|
1180
1199
|
return;
|
|
1181
1200
|
}
|
|
1182
1201
|
const applicationName = await ctx.prompt("Application name:");
|
|
@@ -1247,7 +1266,7 @@ async function configureIdpUiController(ctx) {
|
|
|
1247
1266
|
return;
|
|
1248
1267
|
}
|
|
1249
1268
|
const provider = providers[index];
|
|
1250
|
-
const name =
|
|
1269
|
+
const name = provider.type;
|
|
1251
1270
|
const issuer = await ctx.prompt("Issuer URL:");
|
|
1252
1271
|
const clientId = await ctx.prompt("Client ID:");
|
|
1253
1272
|
const clientSecret = await ctx.prompt("Client Secret:");
|
|
@@ -1404,7 +1423,7 @@ function useCommandRunner({ appendStaticItem, setState }) {
|
|
|
1404
1423
|
}
|
|
1405
1424
|
|
|
1406
1425
|
// src/app.tsx
|
|
1407
|
-
import { jsx as
|
|
1426
|
+
import { jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1408
1427
|
var require2 = createRequire(import.meta.url);
|
|
1409
1428
|
var { version } = require2("../package.json");
|
|
1410
1429
|
function App() {
|
|
@@ -1491,17 +1510,17 @@ function App() {
|
|
|
1491
1510
|
function renderActiveArea() {
|
|
1492
1511
|
switch (state) {
|
|
1493
1512
|
case APP_STATE.EXECUTING:
|
|
1494
|
-
return /* @__PURE__ */
|
|
1495
|
-
/* @__PURE__ */
|
|
1496
|
-
/* @__PURE__ */
|
|
1513
|
+
return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "row", gap: 1, children: [
|
|
1514
|
+
/* @__PURE__ */ jsx7(Spinner, { label: "Running\u2026" }),
|
|
1515
|
+
/* @__PURE__ */ jsx7(Text7, { dimColor: true, children: "(esc to cancel)" })
|
|
1497
1516
|
] });
|
|
1498
1517
|
case APP_STATE.PROMPTING:
|
|
1499
|
-
return /* @__PURE__ */
|
|
1500
|
-
/* @__PURE__ */
|
|
1501
|
-
/* @__PURE__ */
|
|
1518
|
+
return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
|
|
1519
|
+
/* @__PURE__ */ jsx7(Text7, { color: "cyan", children: promptMessage }),
|
|
1520
|
+
/* @__PURE__ */ jsx7(Prompt, { value: promptValue, onChange: setPromptValue, onSubmit: handlePromptSubmit })
|
|
1502
1521
|
] });
|
|
1503
1522
|
default:
|
|
1504
|
-
return /* @__PURE__ */
|
|
1523
|
+
return /* @__PURE__ */ jsx7(
|
|
1505
1524
|
Prompt,
|
|
1506
1525
|
{
|
|
1507
1526
|
value: inputValue,
|
|
@@ -1514,17 +1533,14 @@ function App() {
|
|
|
1514
1533
|
);
|
|
1515
1534
|
}
|
|
1516
1535
|
}
|
|
1517
|
-
return /* @__PURE__ */
|
|
1518
|
-
/* @__PURE__ */
|
|
1536
|
+
return /* @__PURE__ */ jsxs6(Box5, { flexDirection: "column", children: [
|
|
1537
|
+
/* @__PURE__ */ jsx7(ScrollbackHistory, { items: staticItems, version }),
|
|
1519
1538
|
renderActiveArea(),
|
|
1520
|
-
state === APP_STATE.PALETTE && /* @__PURE__ */
|
|
1539
|
+
state === APP_STATE.PALETTE && /* @__PURE__ */ jsx7(CommandPalette, { commands: filteredCommands, selectedIndex })
|
|
1521
1540
|
] });
|
|
1522
1541
|
}
|
|
1523
1542
|
|
|
1524
1543
|
// src/controllers/cli/create-application.cli-controller.ts
|
|
1525
|
-
import { readFile as readFile13 } from "fs/promises";
|
|
1526
|
-
import { join as join22 } from "path";
|
|
1527
|
-
import { cwd as cwd8 } from "process";
|
|
1528
1544
|
async function createApplicationCliController(args2) {
|
|
1529
1545
|
if (!await isPlatformInitialized()) {
|
|
1530
1546
|
console.error("Error: Cannot create an application \u2014 no platform initialized in this directory.");
|
|
@@ -1548,19 +1564,12 @@ async function createApplicationCliController(args2) {
|
|
|
1548
1564
|
let organizationName;
|
|
1549
1565
|
let platformName;
|
|
1550
1566
|
try {
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
const scopeMatch = corePackageJson.name.match(/^@([^/]+)\//);
|
|
1555
|
-
organizationName = scopeMatch?.[1];
|
|
1556
|
-
const rawName = corePackageJson.name.replace(/^@[^/]+\//, "").replace(/-core$/, "");
|
|
1557
|
-
platformName = rawName;
|
|
1558
|
-
if (!organizationName || !platformName) {
|
|
1559
|
-
throw new Error(`Could not parse organization/platform from package name: "${corePackageJson.name}"`);
|
|
1560
|
-
}
|
|
1567
|
+
const manifest = await readPlatformManifest();
|
|
1568
|
+
organizationName = manifest.organizationName;
|
|
1569
|
+
platformName = manifest.platformName;
|
|
1561
1570
|
} catch (err) {
|
|
1562
1571
|
const message = err instanceof Error ? err.message : String(err);
|
|
1563
|
-
console.error(`Error: Could not read
|
|
1572
|
+
console.error(`Error: Could not read .platform.json \u2014 ${message}`);
|
|
1564
1573
|
process.exit(1);
|
|
1565
1574
|
}
|
|
1566
1575
|
await createApplicationService(
|
|
@@ -1601,9 +1610,9 @@ async function configureIdpCliController(args2) {
|
|
|
1601
1610
|
console.error("Error: Cannot configure an IDP \u2014 no platform initialized in this directory.");
|
|
1602
1611
|
process.exit(1);
|
|
1603
1612
|
}
|
|
1604
|
-
const { providerType,
|
|
1605
|
-
if (!providerType || !
|
|
1606
|
-
logger.log("Error: Missing required arguments: providerType,
|
|
1613
|
+
const { providerType, issuer, clientId, clientSecret } = args2;
|
|
1614
|
+
if (!providerType || !issuer || !clientId || !clientSecret) {
|
|
1615
|
+
logger.log("Error: Missing required arguments: providerType, issuer, clientId, clientSecret");
|
|
1607
1616
|
process.exit(1);
|
|
1608
1617
|
}
|
|
1609
1618
|
const provider = idpProviderRegistry.get(providerType);
|
|
@@ -1620,19 +1629,22 @@ async function configureIdpCliController(args2) {
|
|
|
1620
1629
|
}
|
|
1621
1630
|
extras[field.key] = value;
|
|
1622
1631
|
}
|
|
1632
|
+
const name = providerType;
|
|
1623
1633
|
await configureIdpService({ providerType, name, issuer, clientId, clientSecret, extras }, logger);
|
|
1624
1634
|
}
|
|
1625
1635
|
|
|
1626
1636
|
// src/utils/run-npm-script.ts
|
|
1627
1637
|
import { spawn } from "child_process";
|
|
1628
1638
|
import { access as access4 } from "fs/promises";
|
|
1629
|
-
import { join as
|
|
1639
|
+
import { join as join21 } from "path";
|
|
1630
1640
|
async function runNpmScript(scriptName, logger, signal) {
|
|
1631
|
-
|
|
1641
|
+
let localDir;
|
|
1632
1642
|
try {
|
|
1643
|
+
const { platformName } = await readPlatformManifest();
|
|
1644
|
+
localDir = join21(process.cwd(), `${platformName}-local`);
|
|
1633
1645
|
await access4(localDir);
|
|
1634
1646
|
} catch {
|
|
1635
|
-
logger.log(`Error:
|
|
1647
|
+
logger.log(`Error: No initialized platform found in this directory. Run "platform init" first.`);
|
|
1636
1648
|
return;
|
|
1637
1649
|
}
|
|
1638
1650
|
return new Promise((resolve) => {
|
|
@@ -1812,10 +1824,10 @@ function parseKeyValueArgs(args2) {
|
|
|
1812
1824
|
}
|
|
1813
1825
|
|
|
1814
1826
|
// src/index.tsx
|
|
1815
|
-
import { jsx as
|
|
1827
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
1816
1828
|
var args = process.argv.slice(2);
|
|
1817
1829
|
if (args.length === 0) {
|
|
1818
|
-
render(/* @__PURE__ */
|
|
1830
|
+
render(/* @__PURE__ */ jsx8(App, {}));
|
|
1819
1831
|
} else {
|
|
1820
1832
|
const commandName = args[0];
|
|
1821
1833
|
const params = parseKeyValueArgs(args.slice(1));
|
package/package.json
CHANGED
|
@@ -8,10 +8,10 @@ ENV NAME=$NAME
|
|
|
8
8
|
ARG DISPLAY_NAME
|
|
9
9
|
ENV DISPLAY_NAME=$DISPLAY_NAME
|
|
10
10
|
|
|
11
|
-
COPY ./ui/
|
|
12
|
-
COPY ./ui/
|
|
13
|
-
COPY ./ui/
|
|
14
|
-
COPY ./ui/
|
|
11
|
+
COPY ./ui/{{platformName}}-customization-ui/caddy/Caddyfile /etc/caddy/Caddyfile
|
|
12
|
+
COPY ./ui/{{platformName}}-customization-ui/assets /usr/share/caddy/assets/
|
|
13
|
+
COPY ./ui/{{platformName}}-customization-ui/dist /usr/share/caddy/
|
|
14
|
+
COPY ./ui/{{platformName}}-customization-ui/CHANGELOG.md /usr/share/caddy/CHANGELOG.md
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
EXPOSE 8080
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@{{organizationName}}/
|
|
2
|
+
"name": "@{{organizationName}}/{{platformName}}-customization-ui",
|
|
3
3
|
"displayName": "Platform Customization UI",
|
|
4
4
|
"version": "1.0.0",
|
|
5
|
-
"main": "./distLib/
|
|
6
|
-
"types": "./distLib/
|
|
5
|
+
"main": "./distLib/{{platformName}}-customization-ui.js",
|
|
6
|
+
"types": "./distLib/{{platformName}}-customization-ui.d.ts",
|
|
7
7
|
"files": [
|
|
8
8
|
"distLib"
|
|
9
9
|
],
|
|
@@ -14,9 +14,9 @@ module.exports = (webpackConfigEnv, argv) => {
|
|
|
14
14
|
});
|
|
15
15
|
|
|
16
16
|
return merge(defaultConfig, {
|
|
17
|
-
entry: './src/
|
|
17
|
+
entry: './src/{{platformName}}-customization-ui.tsx',
|
|
18
18
|
output: {
|
|
19
|
-
filename: '
|
|
19
|
+
filename: '{{platformName}}-customization-ui.js',
|
|
20
20
|
},
|
|
21
21
|
// modify the webpack config however you'd like to by adding to this object
|
|
22
22
|
externals: ['@bluealba/pae-ui-react-core'],
|
|
@@ -6,7 +6,7 @@ PAE_AUTH_JWT_SECRET=
|
|
|
6
6
|
PAE_GATEWAY_SERVICE_ACCESS_SECRET=
|
|
7
7
|
PAE_GATEWAY_URL=https://pae-nestjs-gateway-service:443
|
|
8
8
|
PAE_GATEWAY_HOST_URL=https://localhost:443
|
|
9
|
-
# PAE_FAVICON=/
|
|
9
|
+
# PAE_FAVICON=/{{platformName}}-customization-ui/assets/favicon.ico
|
|
10
10
|
|
|
11
11
|
#
|
|
12
12
|
# DB
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"scripts": {
|
|
8
8
|
"install": "./scripts/install.sh",
|
|
9
9
|
"build": "./scripts/build.sh",
|
|
10
|
-
"start": "docker compose -p
|
|
11
|
-
"stop": "docker compose -p
|
|
10
|
+
"start": "docker compose -p {{platformName}}-local -f docker-compose.yml up -d --build --remove-orphans --force-recreate",
|
|
11
|
+
"stop": "docker compose -p {{platformName}}-local -f docker-compose.yml down",
|
|
12
12
|
"restart": "npm run stop && npm run start",
|
|
13
|
-
"destroy": "docker compose -p
|
|
13
|
+
"destroy": "docker compose -p {{platformName}}-local -f docker-compose.yml down -v --rmi all"
|
|
14
14
|
},
|
|
15
15
|
"engines": {
|
|
16
16
|
"node": ">=20"
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
# Core Services
|
|
2
2
|
services:
|
|
3
|
-
|
|
3
|
+
{{platformName}}-bootstrap-service:
|
|
4
4
|
build:
|
|
5
|
-
context: ../core/services/
|
|
5
|
+
context: ../{{platformName}}-core/services/{{platformName}}-bootstrap-service
|
|
6
6
|
dockerfile: Dockerfile.development
|
|
7
7
|
environment:
|
|
8
8
|
- NODE_TLS_REJECT_UNAUTHORIZED=0
|
|
9
|
-
- SERVICE_ACCESS_NAME=
|
|
9
|
+
- SERVICE_ACCESS_NAME={{platformName}}-bootstrap-service
|
|
10
10
|
- WAIT_TIME=5000
|
|
11
11
|
- SYNC_STRATEGY=${PAE_BOOTSTRAP_SYNC_STRATEGY}
|
|
12
12
|
- GATEWAY_SERVICE_URL=${PAE_GATEWAY_URL}
|
|
@@ -17,9 +17,9 @@ services:
|
|
|
17
17
|
pae-nestjs-gateway-service:
|
|
18
18
|
condition: service_healthy
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
{{platformName}}-customization-ui:
|
|
21
21
|
build:
|
|
22
|
-
context: ../core/ui/
|
|
22
|
+
context: ../{{platformName}}-core/ui/{{platformName}}-customization-ui
|
|
23
23
|
dockerfile: Dockerfile.development
|
|
24
24
|
ports:
|
|
25
25
|
- 9446:80
|
|
@@ -8,8 +8,8 @@ ENV NAME=$NAME
|
|
|
8
8
|
ARG DISPLAY_NAME
|
|
9
9
|
ENV DISPLAY_NAME=$DISPLAY_NAME
|
|
10
10
|
|
|
11
|
-
COPY ./apps/{{applicationName}}-ui/version.json /usr/share/nginx/html/version.json
|
|
12
|
-
COPY ./apps/{{applicationName}}-ui/dist /usr/share/caddy/
|
|
13
|
-
COPY ./apps/{{applicationName}}-ui/caddy/Caddyfile /etc/caddy/Caddyfile
|
|
11
|
+
COPY ./apps/{{platformName}}-{{applicationName}}-ui/version.json /usr/share/nginx/html/version.json
|
|
12
|
+
COPY ./apps/{{platformName}}-{{applicationName}}-ui/dist /usr/share/caddy/
|
|
13
|
+
COPY ./apps/{{platformName}}-{{applicationName}}-ui/caddy/Caddyfile /etc/caddy/Caddyfile
|
|
14
14
|
|
|
15
15
|
EXPOSE 8080
|
|
File without changes
|
/package/templates/platform-init-template/{core → {{platformName}}-core}/.changeset/config.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/templates/platform-init-template/{core → {{platformName}}-core}/packages-versions.json
RENAMED
|
File without changes
|
/package/templates/platform-init-template/{core → {{platformName}}-core}/scripts/preinstall.mjs
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|