@aifabrix/builder 2.44.4 → 2.44.6
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/.cursor/rules/cli-layout.mdc +1 -1
- package/.cursor/rules/project-rules.mdc +1 -1
- package/.npmrc.token +1 -1
- package/README.md +15 -23
- package/integration/hubspot-test/README.md +2 -0
- package/integration/hubspot-test/test.js +5 -3
- package/jest.projects.js +68 -17
- package/lib/api/controller-health.api.js +49 -0
- package/lib/api/dimension-values.api.js +82 -0
- package/lib/api/dimensions.api.js +114 -0
- package/lib/api/external-systems.api.js +1 -0
- package/lib/api/integration-clients.api.js +168 -0
- package/lib/api/types/dimension-values.types.js +28 -0
- package/lib/api/types/dimensions.types.js +31 -0
- package/lib/api/types/integration-clients.types.js +45 -0
- package/lib/api/types/wizard.types.js +2 -1
- package/lib/api/validation-runner.js +46 -25
- package/lib/app/deploy-config.js +11 -1
- package/lib/app/deploy-status-display.js +3 -3
- package/lib/app/deploy.js +36 -14
- package/lib/app/display.js +15 -11
- package/lib/app/push.js +46 -23
- package/lib/app/register.js +1 -1
- package/lib/app/restart-display.js +95 -0
- package/lib/app/rotate-secret.js +1 -1
- package/lib/app/run-container-start.js +12 -6
- package/lib/app/run-env-compose.js +30 -1
- package/lib/app/run-helpers.js +44 -12
- package/lib/app/run-reload-sync.js +148 -0
- package/lib/app/run-resolve-image.js +51 -1
- package/lib/app/run.js +99 -73
- package/lib/build/index.js +75 -45
- package/lib/cli/doctor-check.js +117 -0
- package/lib/cli/index.js +8 -2
- package/lib/cli/infra-guided.js +445 -0
- package/lib/cli/setup-app.help.js +1 -1
- package/lib/cli/setup-app.js +20 -2
- package/lib/cli/setup-app.test-commands.js +9 -5
- package/lib/cli/setup-auth.js +26 -0
- package/lib/cli/setup-dev-path-commands.js +50 -3
- package/lib/cli/setup-infra.js +138 -61
- package/lib/cli/setup-integration-client.js +182 -0
- package/lib/cli/setup-parameters.js +21 -2
- package/lib/cli/setup-platform.js +102 -0
- package/lib/cli/setup-secrets.js +18 -6
- package/lib/cli/setup-utility.js +97 -33
- package/lib/commands/datasource-capability-dimension-cli.js +128 -0
- package/lib/commands/datasource-capability-output.js +29 -0
- package/lib/commands/datasource-capability-relate-cli.js +140 -0
- package/lib/commands/datasource-capability.js +411 -0
- package/lib/commands/datasource-unified-test-cli.options.js +1 -1
- package/lib/commands/datasource.js +53 -13
- package/lib/commands/dev-down.js +3 -3
- package/lib/commands/dev-infra-gate.js +32 -0
- package/lib/commands/dev-init.js +13 -7
- package/lib/commands/dimension-value.js +179 -0
- package/lib/commands/dimension.js +330 -0
- package/lib/commands/integration-client.js +430 -0
- package/lib/commands/login-device.js +65 -30
- package/lib/commands/login.js +21 -10
- package/lib/commands/parameters-validate.js +78 -13
- package/lib/commands/repair-datasource-auto-rbac.js +166 -0
- package/lib/commands/repair-datasource-keys.js +10 -5
- package/lib/commands/repair-datasource.js +19 -7
- package/lib/commands/repair-env-template.js +4 -1
- package/lib/commands/repair-openapi-sync.js +172 -0
- package/lib/commands/repair-persist.js +102 -0
- package/lib/commands/repair-rbac-extract.js +27 -0
- package/lib/commands/repair-rbac-migrate.js +186 -0
- package/lib/commands/repair-rbac.js +225 -19
- package/lib/commands/repair-system-alignment.js +246 -0
- package/lib/commands/repair-system-permissions.js +168 -0
- package/lib/commands/repair.js +120 -354
- package/lib/commands/secure.js +1 -1
- package/lib/commands/setup-modes.js +455 -0
- package/lib/commands/setup-prompts.js +388 -0
- package/lib/commands/setup.js +149 -0
- package/lib/commands/teardown.js +228 -0
- package/lib/commands/test-e2e-external.js +4 -3
- package/lib/commands/up-common.js +97 -12
- package/lib/commands/up-dataplane.js +33 -11
- package/lib/commands/up-miso.js +7 -11
- package/lib/commands/upload.js +109 -23
- package/lib/commands/wizard-core-helpers.js +14 -11
- package/lib/commands/wizard-core.js +58 -15
- package/lib/commands/wizard-dataplane.js +2 -2
- package/lib/commands/wizard-entity-selection.js +72 -14
- package/lib/commands/wizard-headless.js +7 -3
- package/lib/commands/wizard-helpers.js +13 -1
- package/lib/commands/wizard.js +210 -61
- package/lib/constants/infra-compose-service-names.js +40 -0
- package/lib/core/env-reader.js +16 -3
- package/lib/core/secrets-admin-env.js +101 -0
- package/lib/core/secrets-ensure-infra.js +34 -1
- package/lib/core/secrets-ensure.js +88 -66
- package/lib/core/secrets-env-content.js +432 -0
- package/lib/core/secrets-env-write.js +27 -1
- package/lib/core/secrets-load.js +248 -0
- package/lib/core/secrets-names.js +32 -0
- package/lib/core/secrets.js +17 -757
- package/lib/datasource/capability/basic-exposure.js +76 -0
- package/lib/datasource/capability/capability-diff-slice.js +41 -0
- package/lib/datasource/capability/capability-key.js +34 -0
- package/lib/datasource/capability/capability-resolve.js +172 -0
- package/lib/datasource/capability/capability-storage-keys.js +22 -0
- package/lib/datasource/capability/copy-operations.js +348 -0
- package/lib/datasource/capability/copy-test-payload.js +139 -0
- package/lib/datasource/capability/create-operations.js +235 -0
- package/lib/datasource/capability/dimension-operations.js +151 -0
- package/lib/datasource/capability/dimension-validate.js +219 -0
- package/lib/datasource/capability/json-pointer.js +31 -0
- package/lib/datasource/capability/reference-rewrite.js +51 -0
- package/lib/datasource/capability/relate-operations.js +325 -0
- package/lib/datasource/capability/relate-validate.js +219 -0
- package/lib/datasource/capability/remove-operations.js +275 -0
- package/lib/datasource/capability/run-capability-copy.js +152 -0
- package/lib/datasource/capability/run-capability-diff.js +135 -0
- package/lib/datasource/capability/run-capability-dimension.js +291 -0
- package/lib/datasource/capability/run-capability-edit.js +377 -0
- package/lib/datasource/capability/run-capability-relate.js +193 -0
- package/lib/datasource/capability/run-capability-remove.js +105 -0
- package/lib/datasource/capability/templates/minimal-fetch.json +18 -0
- package/lib/datasource/capability/validate-capability-slice.js +35 -0
- package/lib/datasource/list.js +136 -23
- package/lib/datasource/log-viewer.js +2 -4
- package/lib/datasource/unified-validation-run.js +51 -16
- package/lib/datasource/validate.js +53 -1
- package/lib/deployment/deploy-poll-ui.js +60 -0
- package/lib/deployment/deployer-status.js +29 -3
- package/lib/deployment/deployer.js +48 -30
- package/lib/deployment/environment.js +7 -2
- package/lib/deployment/poll-interval.js +72 -0
- package/lib/deployment/push.js +11 -9
- package/lib/external-system/deploy.js +4 -1
- package/lib/external-system/download.js +61 -32
- package/lib/external-system/sync-deploy-manifest.js +33 -0
- package/lib/generator/wizard-prompts.js +7 -1
- package/lib/generator/wizard.js +34 -0
- package/lib/infrastructure/index.js +49 -19
- package/lib/infrastructure/orphan-infra-docker-teardown.js +177 -0
- package/lib/parameters/infra-kv-discovery.js +29 -4
- package/lib/parameters/infra-parameter-catalog.js +6 -3
- package/lib/parameters/infra-parameter-validate.js +67 -19
- package/lib/resolvers/datasource-resolver.js +53 -0
- package/lib/resolvers/dimension-file.js +52 -0
- package/lib/resolvers/manifest-resolver.js +133 -0
- package/lib/schema/external-datasource.schema.json +183 -53
- package/lib/schema/external-system.schema.json +23 -10
- package/lib/schema/infra.parameter.yaml +26 -11
- package/lib/schema/wizard-config.schema.json +2 -2
- package/lib/utils/aifabrix-config-dir-walk.js +40 -0
- package/lib/utils/aifabrix-runtime-config-dir.js +26 -3
- package/lib/utils/app-run-containers.js +2 -2
- package/lib/utils/bash-secret-env.js +59 -0
- package/lib/utils/cli-secrets-error-format.js +78 -0
- package/lib/utils/cli-test-layout-chalk.js +31 -9
- package/lib/utils/cli-utils.js +4 -36
- package/lib/utils/datasource-test-run-display.js +8 -0
- package/lib/utils/dev-hosts-helper.js +3 -2
- package/lib/utils/dev-init-ssh-merge.js +2 -1
- package/lib/utils/docker-build.js +17 -9
- package/lib/utils/docker-reload-mount.js +127 -0
- package/lib/utils/external-readme.js +117 -4
- package/lib/utils/external-system-local-test-tty.js +3 -2
- package/lib/utils/external-system-readiness-core.js +45 -12
- package/lib/utils/external-system-readiness-deploy-display.js +3 -3
- package/lib/utils/external-system-readiness-display-internals.js +33 -3
- package/lib/utils/external-system-readiness-display.js +10 -1
- package/lib/utils/file-upload.js +40 -3
- package/lib/utils/health-check-db-init.js +107 -0
- package/lib/utils/health-check-public-warn.js +69 -0
- package/lib/utils/health-check-url.js +19 -4
- package/lib/utils/health-check.js +135 -105
- package/lib/utils/help-builder.js +5 -1
- package/lib/utils/image-name.js +34 -7
- package/lib/utils/integration-file-backup.js +74 -0
- package/lib/utils/mutagen-install.js +30 -3
- package/lib/utils/paths.js +108 -25
- package/lib/utils/postgres-wipe.js +212 -0
- package/lib/utils/register-aifabrix-shell-env.js +15 -0
- package/lib/utils/remote-dev-auth.js +21 -5
- package/lib/utils/remote-docker-env.js +9 -1
- package/lib/utils/remote-secrets-loader.js +42 -3
- package/lib/utils/resolve-docker-image-ref.js +9 -3
- package/lib/utils/secrets-ancestor-paths.js +47 -0
- package/lib/utils/secrets-helpers.js +17 -10
- package/lib/utils/secrets-kv-refs.js +42 -0
- package/lib/utils/secrets-kv-scope.js +19 -2
- package/lib/utils/secrets-materialize-local.js +134 -0
- package/lib/utils/secrets-path.js +24 -10
- package/lib/utils/secrets-utils.js +2 -2
- package/lib/utils/system-builder-root.js +34 -0
- package/lib/utils/url-declarative-resolve-build.js +6 -1
- package/lib/utils/url-declarative-runtime-base-path.js +32 -0
- package/lib/utils/url-declarative-vdir-inactive-env.js +2 -1
- package/lib/utils/urls-local-registry.js +73 -20
- package/lib/utils/validation-poll-ui.js +81 -0
- package/lib/utils/validation-run-poll.js +29 -5
- package/lib/utils/with-muted-logger.js +53 -0
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +1 -1
- package/templates/applications/dataplane/rbac.yaml +10 -10
- package/templates/applications/keycloak/env.template +8 -6
- package/templates/applications/miso-controller/application.yaml +7 -0
- package/templates/applications/miso-controller/env.template +7 -7
- package/templates/applications/miso-controller/rbac.yaml +9 -9
- package/templates/external-system/README.md.hbs +89 -102
- package/.nyc_output/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/55e9d034-ddab-4579-a706-e02a91d75c91.json +0 -1
- package/.nyc_output/processinfo/index.json +0 -1
- package/lib/api/service-users.api.js +0 -150
- package/lib/api/types/service-users.types.js +0 -65
- package/lib/cli/setup-service-user.js +0 -187
- package/lib/commands/service-user.js +0 -429
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mode handlers for `aifabrix setup`.
|
|
3
|
+
*
|
|
4
|
+
* Five small handlers, one per branch of the setup decision tree:
|
|
5
|
+
* - {@link runFreshInstall} — no infra: wizard for admin creds + AI tool, then up-infra + up-platform.
|
|
6
|
+
* - {@link runReinstall} — Mode 1: down-infra -v, wipe local secrets, up-infra, up-platform --force.
|
|
7
|
+
* - {@link runWipeData} — Mode 2: drop DBs/roles, wipe local secrets, up-infra, up-platform --force.
|
|
8
|
+
* - {@link runCleanInstallFiles}— Mode 3: wipe local secrets, up-infra, up-platform --force (templates re-copied).
|
|
9
|
+
* - {@link runUpdateImages} — Mode 4: docker pull infra + platform images, up-infra, up-platform.
|
|
10
|
+
*
|
|
11
|
+
* Every handler ends with `up-infra` (idempotent, reads flags from
|
|
12
|
+
* `config.yaml`) followed by `up-platform`. Modes 1/2/3 also remove
|
|
13
|
+
* `secrets.local.yaml` so the next platform bootstrap re-resolves
|
|
14
|
+
* service secrets from the catalog and re-prompts the AI tool wizard.
|
|
15
|
+
*
|
|
16
|
+
* @fileoverview aifabrix setup mode handlers
|
|
17
|
+
* @author AI Fabrix Team
|
|
18
|
+
* @version 2.0.0
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
'use strict';
|
|
22
|
+
|
|
23
|
+
const fs = require('fs');
|
|
24
|
+
const path = require('path');
|
|
25
|
+
const chalk = require('chalk');
|
|
26
|
+
const ora = require('ora');
|
|
27
|
+
|
|
28
|
+
const config = require('../core/config');
|
|
29
|
+
const infra = require('../infrastructure');
|
|
30
|
+
const pathsUtil = require('../utils/paths');
|
|
31
|
+
const logger = require('../utils/logger');
|
|
32
|
+
const dockerUtils = require('../utils/docker');
|
|
33
|
+
const dockerExec = require('../utils/docker-exec');
|
|
34
|
+
const {
|
|
35
|
+
formatSuccessLine,
|
|
36
|
+
formatProgress,
|
|
37
|
+
infoLine,
|
|
38
|
+
sectionTitle,
|
|
39
|
+
formatDatasourceListRow,
|
|
40
|
+
successGlyph
|
|
41
|
+
} = require('../utils/cli-test-layout-chalk');
|
|
42
|
+
const { withMutedLogger } = require('../utils/with-muted-logger');
|
|
43
|
+
const infraHelpers = require('../infrastructure/helpers');
|
|
44
|
+
|
|
45
|
+
const upMiso = require('./up-miso');
|
|
46
|
+
const upDataplane = require('./up-dataplane');
|
|
47
|
+
const upCommon = require('./up-common');
|
|
48
|
+
const postgresWipe = require('../utils/postgres-wipe');
|
|
49
|
+
const setupPrompts = require('./setup-prompts');
|
|
50
|
+
const { handleLogin } = require('./login');
|
|
51
|
+
const infraGuided = require('../cli/infra-guided');
|
|
52
|
+
|
|
53
|
+
/** Builder app keys touched by `up-platform --force`. */
|
|
54
|
+
const PLATFORM_APPS = ['keycloak', 'miso-controller', 'dataplane'];
|
|
55
|
+
|
|
56
|
+
function formatBackupSuffix() {
|
|
57
|
+
const d = new Date();
|
|
58
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
59
|
+
return `${d.getFullYear()}${pad(d.getMonth() + 1)}${pad(d.getDate())}-${pad(d.getHours())}${pad(d.getMinutes())}${pad(d.getSeconds())}`;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function listNonDotEntries(dir) {
|
|
63
|
+
try {
|
|
64
|
+
return fs.readdirSync(dir).filter((n) => n && !String(n).startsWith('.'));
|
|
65
|
+
} catch {
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function isExistingNonEmptyDir(dir) {
|
|
71
|
+
if (!fs.existsSync(dir)) return false;
|
|
72
|
+
try {
|
|
73
|
+
const st = fs.statSync(dir);
|
|
74
|
+
if (!st || typeof st.isDirectory !== 'function' || !st.isDirectory()) return false;
|
|
75
|
+
} catch {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return listNonDotEntries(dir).length > 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function makeUniqueBackupPath(parentDir, appName, suffix) {
|
|
82
|
+
const base = path.join(parentDir, `${appName}.backup-${suffix}`);
|
|
83
|
+
if (!fs.existsSync(base)) return base;
|
|
84
|
+
for (let i = 2; i < 1000; i++) {
|
|
85
|
+
const candidate = path.join(parentDir, `${appName}.backup-${suffix}-${i}`);
|
|
86
|
+
if (!fs.existsSync(candidate)) return candidate;
|
|
87
|
+
}
|
|
88
|
+
throw new Error(`Could not create unique backup path for ${appName} under ${parentDir}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Non-empty platform app dirs under {@link pathsUtil.getSystemBuilderRoot}.
|
|
93
|
+
* @returns {{ sysRoot: string|null, apps: string[] }}
|
|
94
|
+
*/
|
|
95
|
+
function getNonEmptySystemPlatformApps() {
|
|
96
|
+
let sysRoot = null;
|
|
97
|
+
try {
|
|
98
|
+
sysRoot = pathsUtil.getSystemBuilderRoot();
|
|
99
|
+
} catch {
|
|
100
|
+
return { sysRoot: null, apps: [] };
|
|
101
|
+
}
|
|
102
|
+
if (!sysRoot || !fs.existsSync(sysRoot)) {
|
|
103
|
+
return { sysRoot, apps: [] };
|
|
104
|
+
}
|
|
105
|
+
const apps = [];
|
|
106
|
+
for (const app of PLATFORM_APPS) {
|
|
107
|
+
const p = path.join(sysRoot, app);
|
|
108
|
+
if (isExistingNonEmptyDir(p)) apps.push(app);
|
|
109
|
+
}
|
|
110
|
+
return { sysRoot, apps };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function backupPlatformAppDirs(platformApps) {
|
|
114
|
+
const suffix = formatBackupSuffix();
|
|
115
|
+
const backedUp = [];
|
|
116
|
+
for (const appName of platformApps) {
|
|
117
|
+
const appDir = path.resolve(pathsUtil.getBuilderPath(appName));
|
|
118
|
+
if (!isExistingNonEmptyDir(appDir)) continue;
|
|
119
|
+
const parentDir = path.dirname(appDir);
|
|
120
|
+
const dest = makeUniqueBackupPath(parentDir, appName, suffix);
|
|
121
|
+
fs.renameSync(appDir, dest);
|
|
122
|
+
backedUp.push({ appName, from: appDir, to: dest });
|
|
123
|
+
}
|
|
124
|
+
return backedUp;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function getBuilderRootEntriesOrNull() {
|
|
128
|
+
const builderRoot = pathsUtil.getBuilderRoot();
|
|
129
|
+
if (!fs.existsSync(builderRoot)) return null;
|
|
130
|
+
let st;
|
|
131
|
+
try {
|
|
132
|
+
st = fs.statSync(builderRoot);
|
|
133
|
+
} catch (err) {
|
|
134
|
+
throw new Error(`Could not read builder folder at ${builderRoot}: ${err.message}`);
|
|
135
|
+
}
|
|
136
|
+
if (!st || typeof st.isDirectory !== 'function' || !st.isDirectory()) {
|
|
137
|
+
throw new Error(`Builder root exists but is not a directory: ${builderRoot}`);
|
|
138
|
+
}
|
|
139
|
+
const entries = listNonDotEntries(builderRoot);
|
|
140
|
+
if (entries.length === 0) return null;
|
|
141
|
+
return { builderRoot, entries };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function handleBuilderDirAction(action) {
|
|
145
|
+
if (action === setupPrompts.BUILDER_DIR_ACTION.ABORT) {
|
|
146
|
+
logger.log(chalk.yellow('Aborted by user.'));
|
|
147
|
+
return { aborted: true, backedUp: [], skipClean: false };
|
|
148
|
+
}
|
|
149
|
+
if (action === setupPrompts.BUILDER_DIR_ACTION.KEEP_FILES) {
|
|
150
|
+
return { aborted: false, backedUp: [], skipClean: true };
|
|
151
|
+
}
|
|
152
|
+
if (action === setupPrompts.BUILDER_DIR_ACTION.BACKUP) {
|
|
153
|
+
const backedUp = backupPlatformAppDirs(PLATFORM_APPS);
|
|
154
|
+
for (const item of backedUp) {
|
|
155
|
+
logger.log(
|
|
156
|
+
chalk.gray(` ${successGlyph()} Backed up ${item.from} → ${path.basename(item.to)}/`)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
return { aborted: false, backedUp, skipClean: false };
|
|
160
|
+
}
|
|
161
|
+
return { aborted: false, backedUp: [], skipClean: false };
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
async function maybePromptForExistingBuilderDir({ force }) {
|
|
165
|
+
if (force !== true) return { aborted: false, backedUp: [], skipClean: false };
|
|
166
|
+
const existing = getBuilderRootEntriesOrNull();
|
|
167
|
+
const { sysRoot, apps: systemPlatformApps } = getNonEmptySystemPlatformApps();
|
|
168
|
+
if (!existing && systemPlatformApps.length === 0) {
|
|
169
|
+
return { aborted: false, backedUp: [], skipClean: false };
|
|
170
|
+
}
|
|
171
|
+
const builderRoot = existing ? existing.builderRoot : pathsUtil.getBuilderRoot();
|
|
172
|
+
const totalEntries = existing ? existing.entries.length : systemPlatformApps.length;
|
|
173
|
+
const action = await setupPrompts.promptBuilderDirConflict({
|
|
174
|
+
builderRoot,
|
|
175
|
+
totalEntries,
|
|
176
|
+
platformApps: PLATFORM_APPS,
|
|
177
|
+
systemBuilderRoot: sysRoot || undefined,
|
|
178
|
+
systemPlatformApps: systemPlatformApps.length ? systemPlatformApps : undefined
|
|
179
|
+
});
|
|
180
|
+
return handleBuilderDirAction(action);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
function shouldUseSpinner() {
|
|
184
|
+
return Boolean(process && process.stdout && process.stdout.isTTY);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function startSpinner(text) {
|
|
188
|
+
if (!shouldUseSpinner()) {
|
|
189
|
+
logger.log(formatProgress(text));
|
|
190
|
+
return null;
|
|
191
|
+
}
|
|
192
|
+
return ora({ text, spinner: 'dots' }).start();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function stopSpinnerSuccess(spinner, text) {
|
|
196
|
+
if (!spinner) {
|
|
197
|
+
logger.log(formatSuccessLine(text));
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
spinner.succeed(text);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/**
|
|
204
|
+
* Start infrastructure using the developer's `config.yaml` flags.
|
|
205
|
+
* Mirrors the relevant slice of `runUpInfraCommand` from `lib/cli/setup-infra.js`
|
|
206
|
+
* without re-applying CLI flag persistence (we never receive flags here).
|
|
207
|
+
*
|
|
208
|
+
* @async
|
|
209
|
+
* @param {Object} [overrides] - Optional admin overrides (fresh install only)
|
|
210
|
+
* @param {string} [overrides.adminEmail] - Override pgAdmin / Keycloak admin email
|
|
211
|
+
* @param {string} [overrides.adminPassword] - Override Postgres / pgAdmin / Keycloak admin password
|
|
212
|
+
* @returns {Promise<void>}
|
|
213
|
+
*/
|
|
214
|
+
async function startInfraFromConfig(overrides = {}) {
|
|
215
|
+
await config.ensureSecretsEncryptionKey();
|
|
216
|
+
const cfg = await config.getConfig();
|
|
217
|
+
await withMutedLogger(async() => {
|
|
218
|
+
await infra.startInfra(null, {
|
|
219
|
+
traefik: cfg.traefik === true,
|
|
220
|
+
pgadmin: cfg.pgadmin !== false,
|
|
221
|
+
redisCommander: cfg.redisCommander !== false,
|
|
222
|
+
adminPassword: overrides.adminPassword,
|
|
223
|
+
adminPwd: overrides.adminPassword,
|
|
224
|
+
adminEmail: overrides.adminEmail,
|
|
225
|
+
tlsEnabled: cfg.tlsEnabled === true
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Run the platform after infra is up: optionally apply force config + clean
|
|
232
|
+
* builder dirs, then `up-miso` followed by `up-dataplane`.
|
|
233
|
+
*
|
|
234
|
+
* @async
|
|
235
|
+
* @param {{ force?: boolean }} [opts]
|
|
236
|
+
* @returns {Promise<void>}
|
|
237
|
+
*/
|
|
238
|
+
async function runUpPlatform(opts = {}) {
|
|
239
|
+
const preflight = await maybePromptForExistingBuilderDir({ force: opts.force === true });
|
|
240
|
+
if (preflight.aborted) return;
|
|
241
|
+
|
|
242
|
+
let forceCleanSummary = null;
|
|
243
|
+
if (opts.force === true) {
|
|
244
|
+
const forceSummary = await upCommon.applyUpPlatformForceConfig({ silent: true });
|
|
245
|
+
if (preflight.skipClean !== true) {
|
|
246
|
+
const cleanedApps = await upCommon.cleanBuilderAppDirs(PLATFORM_APPS, { silent: true });
|
|
247
|
+
forceCleanSummary = { forceSummary, cleanedApps };
|
|
248
|
+
} else {
|
|
249
|
+
forceCleanSummary = { forceSummary, cleanedApps: [] };
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// Reuse the same guided UX as `aifabrix up-platform` (keycloak → miso → auth → dataplane → footer).
|
|
253
|
+
await infraGuided.runGuidedUpPlatform(
|
|
254
|
+
{ base: true },
|
|
255
|
+
upMiso.handleUpMiso,
|
|
256
|
+
upDataplane.handleUpDataplane,
|
|
257
|
+
handleLogin,
|
|
258
|
+
forceCleanSummary
|
|
259
|
+
);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Remove `~/.aifabrix/secrets.local.yaml` if present. Never touches the
|
|
264
|
+
* shared `aifabrix-secrets` file. Idempotent.
|
|
265
|
+
*
|
|
266
|
+
* @returns {boolean} True when a file was removed
|
|
267
|
+
*/
|
|
268
|
+
function removeUserLocalSecrets() {
|
|
269
|
+
const target = pathsUtil.getPrimaryUserSecretsLocalPath();
|
|
270
|
+
if (!fs.existsSync(target)) return false;
|
|
271
|
+
fs.rmSync(target, { force: true });
|
|
272
|
+
logger.log(chalk.gray(` ${successGlyph()} Removed ${target}`));
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Pull infra-compose images (postgres, redis, optional pgadmin/redis-commander/traefik).
|
|
278
|
+
* Best-effort: warns and continues when the compose file is missing.
|
|
279
|
+
*
|
|
280
|
+
* @async
|
|
281
|
+
* @returns {Promise<void>}
|
|
282
|
+
*/
|
|
283
|
+
async function pullInfraImages() {
|
|
284
|
+
const devId = await config.getDeveloperId();
|
|
285
|
+
const infraDir = path.join(pathsUtil.getAifabrixSystemDir(), infraHelpers.getInfraDirName(devId));
|
|
286
|
+
const composePath = path.join(infraDir, 'compose.yaml');
|
|
287
|
+
if (!fs.existsSync(composePath)) {
|
|
288
|
+
logger.log(chalk.yellow(`No infra compose file at ${composePath}; skipping image pull.`));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const project = infraHelpers.getInfraProjectName(devId);
|
|
292
|
+
const composeCmd = await dockerUtils.getComposeCommand();
|
|
293
|
+
logger.log('');
|
|
294
|
+
logger.log(sectionTitle('Pull images'));
|
|
295
|
+
const spin = startSpinner('Pulling infrastructure images...');
|
|
296
|
+
await dockerExec.execWithDockerEnv(`${composeCmd} -f "${composePath}" -p ${project} pull`, { cwd: infraDir });
|
|
297
|
+
stopSpinnerSuccess(spin, 'Infrastructure images pulled');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* Pull a single platform app image based on `builder/<appName>/application.yaml`.
|
|
302
|
+
* Tolerates missing config / unresolvable images by warning and continuing.
|
|
303
|
+
*
|
|
304
|
+
* @async
|
|
305
|
+
* @param {string} appName
|
|
306
|
+
* @returns {Promise<void>}
|
|
307
|
+
*/
|
|
308
|
+
async function pullPlatformAppImage(appName) {
|
|
309
|
+
let imageRef = '';
|
|
310
|
+
try {
|
|
311
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
312
|
+
const builderPath = pathsUtil.getBuilderPath(appName);
|
|
313
|
+
const configPath = pathsUtil.resolveApplicationConfigPath(builderPath);
|
|
314
|
+
const cfg = loadConfigFile(configPath) || {};
|
|
315
|
+
const deploy = cfg.deploy || {};
|
|
316
|
+
if (typeof deploy.image === 'string' && deploy.image.trim()) {
|
|
317
|
+
imageRef = deploy.image.trim();
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
imageRef = '';
|
|
321
|
+
}
|
|
322
|
+
if (!imageRef) {
|
|
323
|
+
logger.log(formatDatasourceListRow('skipped', appName, 'no image ref'));
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
try {
|
|
327
|
+
const spin = startSpinner(`Pulling ${appName} image...`);
|
|
328
|
+
await dockerExec.execWithDockerEnv(`docker pull ${imageRef}`);
|
|
329
|
+
stopSpinnerSuccess(spin, `Pulled ${appName} image`);
|
|
330
|
+
} catch (err) {
|
|
331
|
+
logger.log(chalk.yellow(`Could not pull ${imageRef}: ${err.message}`));
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** Pull every platform app image. */
|
|
336
|
+
async function pullPlatformImages() {
|
|
337
|
+
for (const appName of PLATFORM_APPS) {
|
|
338
|
+
await pullPlatformAppImage(appName);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Fresh install: wizard collects admin email + password, then AI tool keys,
|
|
344
|
+
* then up-infra + up-platform.
|
|
345
|
+
*
|
|
346
|
+
* @async
|
|
347
|
+
* @param {{ adminEmail: string, adminPassword: string }} adminCreds
|
|
348
|
+
* @returns {Promise<void>}
|
|
349
|
+
*/
|
|
350
|
+
async function runFreshInstall(adminCreds) {
|
|
351
|
+
logger.log(infoLine('Setup: fresh install'));
|
|
352
|
+
const infraSpin = startSpinner('Starting infrastructure...');
|
|
353
|
+
await startInfraFromConfig({
|
|
354
|
+
adminEmail: adminCreds.adminEmail,
|
|
355
|
+
adminPassword: adminCreds.adminPassword
|
|
356
|
+
});
|
|
357
|
+
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
358
|
+
// Bring up infra first, then collect optional platform-level secrets (AI tool)
|
|
359
|
+
// so the flow feels like a product installer: infra → platform configuration → platform services.
|
|
360
|
+
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
361
|
+
// Fresh-install should reset dev defaults (env + controller URL) the same way
|
|
362
|
+
// as other setup recovery paths, otherwise the platform can come up pointed at
|
|
363
|
+
// stale configuration.
|
|
364
|
+
await runUpPlatform({ force: true });
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
/**
|
|
368
|
+
* Mode 1 — Re-install: stop infra + remove all volumes, wipe local secrets,
|
|
369
|
+
* then up-infra + up-platform --force.
|
|
370
|
+
*
|
|
371
|
+
* @async
|
|
372
|
+
* @returns {Promise<void>}
|
|
373
|
+
*/
|
|
374
|
+
async function runReinstall() {
|
|
375
|
+
logger.log(infoLine('Setup: re-install (volumes will be removed)'));
|
|
376
|
+
const downSpin = startSpinner('Stopping infrastructure (down-infra -v)...');
|
|
377
|
+
await withMutedLogger(async() => {
|
|
378
|
+
await infra.stopInfraWithVolumes();
|
|
379
|
+
});
|
|
380
|
+
stopSpinnerSuccess(downSpin, 'Infrastructure stopped and volumes removed');
|
|
381
|
+
removeUserLocalSecrets();
|
|
382
|
+
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
383
|
+
const infraSpin = startSpinner('Starting infrastructure...');
|
|
384
|
+
await startInfraFromConfig({});
|
|
385
|
+
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
386
|
+
await runUpPlatform({ force: true });
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Mode 2 — Wipe data: drop DBs and DB users, wipe local secrets, then
|
|
391
|
+
* up-infra + up-platform --force. Postgres volume + admin password preserved.
|
|
392
|
+
*
|
|
393
|
+
* @async
|
|
394
|
+
* @returns {Promise<void>}
|
|
395
|
+
*/
|
|
396
|
+
async function runWipeData() {
|
|
397
|
+
logger.log(infoLine('Setup: wipe data (databases and DB users)'));
|
|
398
|
+
await postgresWipe.wipePostgresData();
|
|
399
|
+
removeUserLocalSecrets();
|
|
400
|
+
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
401
|
+
const infraSpin = startSpinner('Starting infrastructure...');
|
|
402
|
+
await startInfraFromConfig({});
|
|
403
|
+
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
404
|
+
await runUpPlatform({ force: true });
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* Mode 3 — Clean install files: wipe local secrets, then up-infra +
|
|
409
|
+
* up-platform --force (which removes builder/<keycloak|miso-controller|dataplane>
|
|
410
|
+
* and re-fetches from templates).
|
|
411
|
+
*
|
|
412
|
+
* @async
|
|
413
|
+
* @returns {Promise<void>}
|
|
414
|
+
*/
|
|
415
|
+
async function runCleanInstallFiles() {
|
|
416
|
+
logger.log(infoLine('Setup: clean installation files and re-install platform services'));
|
|
417
|
+
removeUserLocalSecrets();
|
|
418
|
+
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
419
|
+
const infraSpin = startSpinner('Starting infrastructure...');
|
|
420
|
+
await startInfraFromConfig({});
|
|
421
|
+
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
422
|
+
await runUpPlatform({ force: true });
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/**
|
|
426
|
+
* Mode 4 — Update images: docker pull infra + platform images, then up-infra +
|
|
427
|
+
* up-platform (no force; secrets and data preserved).
|
|
428
|
+
*
|
|
429
|
+
* @async
|
|
430
|
+
* @returns {Promise<void>}
|
|
431
|
+
*/
|
|
432
|
+
async function runUpdateImages() {
|
|
433
|
+
logger.log(infoLine('Setup: update docker images'));
|
|
434
|
+
await pullInfraImages();
|
|
435
|
+
await pullPlatformImages();
|
|
436
|
+
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
437
|
+
const infraSpin = startSpinner('Starting infrastructure...');
|
|
438
|
+
await startInfraFromConfig({});
|
|
439
|
+
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
440
|
+
await runUpPlatform({ force: false });
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
module.exports = {
|
|
444
|
+
PLATFORM_APPS,
|
|
445
|
+
startInfraFromConfig,
|
|
446
|
+
runUpPlatform,
|
|
447
|
+
removeUserLocalSecrets,
|
|
448
|
+
pullInfraImages,
|
|
449
|
+
pullPlatformImages,
|
|
450
|
+
runFreshInstall,
|
|
451
|
+
runReinstall,
|
|
452
|
+
runWipeData,
|
|
453
|
+
runCleanInstallFiles,
|
|
454
|
+
runUpdateImages
|
|
455
|
+
};
|