@aifabrix/builder 2.60.0 → 2.62.0
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/README.md +14 -11
- package/docs/README.md +80 -0
- package/docs/builder-help/evidence-patterns.json +155 -0
- package/docs/builder-help/golden-examples/crm-company.json +30 -0
- package/docs/builder-help/golden-examples/crm-deal.json +29 -0
- package/docs/builder-help/golden-examples/document-storage-keyed-get.json +85 -0
- package/docs/builder-help/golden-examples/document-storage.json +30 -0
- package/docs/builder-help/golden-examples/meeting-transcript.json +29 -0
- package/docs/builder-help/golden-examples/repository-template.json +29 -0
- package/docs/builder-help/golden-examples/service-ticket.json +29 -0
- package/docs/builder-help/platform-roles.json +98 -0
- package/docs/builder-help/resource-type-catalog.json +402 -0
- package/lib/api/applications.api.js +22 -2
- package/lib/api/bootstrap-snapshot.api.js +115 -0
- package/lib/api/configuration.api.js +131 -0
- package/lib/api/system-secrets.api.js +72 -0
- package/lib/app/deploy.js +14 -5
- package/lib/app/run-docker-fallback.js +6 -1
- package/lib/app/run-env-compose.js +5 -6
- package/lib/app/run-helpers.js +2 -1
- package/lib/app/run-parameter-sync.js +142 -0
- package/lib/app/run.js +6 -4
- package/lib/build/docker-build-args.js +5 -2
- package/lib/build/index.js +3 -2
- package/lib/build/standard-docker-build.js +6 -2
- package/lib/channels/channel-artifact-generator.js +13 -3
- package/lib/cli/infra-guided-footers.js +10 -8
- package/lib/cli/infra-guided.js +30 -10
- package/lib/cli/setup-app.js +5 -0
- package/lib/cli/setup-environment.js +156 -0
- package/lib/cli/setup-infra-up-platform-action.js +14 -1
- package/lib/cli/setup-platform.js +2 -0
- package/lib/commands/auth-config.js +2 -0
- package/lib/commands/datasource-capability-upsert-cli.js +112 -0
- package/lib/commands/datasource-capability.js +4 -2
- package/lib/commands/env-secret-context.js +113 -0
- package/lib/commands/env-secret-list.js +200 -0
- package/lib/commands/env-secret-push-confirm.js +54 -0
- package/lib/commands/env-secret-push-run.js +227 -0
- package/lib/commands/env-secret-push.js +168 -0
- package/lib/commands/login.js +4 -0
- package/lib/commands/repair-datasource-apply.js +5 -1
- package/lib/commands/repair-datasource-keyed-document.js +122 -0
- package/lib/commands/repair-datasource-legacy.js +94 -0
- package/lib/commands/repair-datasource-run.js +1 -0
- package/lib/commands/setup-image-refresh.js +26 -0
- package/lib/commands/setup-modes.js +8 -9
- package/lib/commands/setup-prompts-platform-mode.js +34 -0
- package/lib/commands/setup-prompts.js +2 -180
- package/lib/commands/setup.js +3 -0
- package/lib/commands/up-builder-api.js +24 -8
- package/lib/commands/up-common.js +16 -1
- package/lib/commands/up-dataplane-bootstrap.js +70 -14
- package/lib/commands/up-dataplane-credentials.js +21 -0
- package/lib/commands/up-dataplane.js +37 -18
- package/lib/commands/up-integration-server.js +112 -0
- package/lib/commands/verify-operations-skip-e2e.js +25 -1
- package/lib/commands/verify-operations-steps.js +13 -1
- package/lib/commands/wizard-config-normalizer.js +12 -5
- package/lib/commands/wizard-core.js +5 -157
- package/lib/commands/wizard-file-saving.js +163 -0
- package/lib/core/admin-secrets-env-overlay.js +8 -3
- package/lib/core/env-platform-expand.js +5 -1
- package/lib/core/environment-access-policy.js +121 -0
- package/lib/core/environment-mode-policy.js +177 -0
- package/lib/core/local-env-overrides.js +149 -0
- package/lib/core/secrets-ensure.js +4 -2
- package/lib/core/secrets-env-content.js +17 -10
- package/lib/core/secrets-env-write.js +11 -4
- package/lib/core/secrets-load.js +4 -2
- package/lib/datasource/binary-documents-validator.js +190 -0
- package/lib/datasource/capability/capability-manifest.js +1 -0
- package/lib/datasource/capability/run-capability-upsert.js +202 -0
- package/lib/datasource/capability/upsert-ingredients.js +291 -0
- package/lib/datasource/capability/upsert-operations.js +138 -0
- package/lib/datasource/capability/upsert-test-scaffold.js +189 -0
- package/lib/datasource/validate.js +12 -5
- package/lib/deployment/installation/index.js +14 -1
- package/lib/deployment/installation/infra-catalog.js +3 -0
- package/lib/deployment/installation/local-environment-stage.js +285 -0
- package/lib/deployment/installation/local-installation.js +76 -0
- package/lib/deployment/installation/stage-input.js +5 -1
- package/lib/generator/builders.js +3 -1
- package/lib/generator/index.js +3 -0
- package/lib/generator/split-variables.js +2 -2
- package/lib/lifecycle/product-model.js +4 -3
- package/lib/lifecycle/report-display.js +3 -2
- package/lib/parameters/database-adoption.js +125 -0
- package/lib/parameters/infra-parameter-catalog.js +1 -1
- package/lib/parameters/physical-database-naming.js +136 -0
- package/lib/parameters/physical-secret-name.js +194 -0
- package/lib/parameters/rsa-secret-values.js +165 -0
- package/lib/programmatic/builder-help-enterprise-sync-fabrix.js +1 -1
- package/lib/programmatic/builder-help-governance.js +1 -1
- package/lib/programmatic/builder-help.js +1 -1
- package/lib/programmatic/run-channel-install-artifacts.js +28 -2
- package/lib/programmatic/run-channel-package.js +3 -1
- package/lib/programmatic/workspace-context.js +37 -2
- package/lib/role-assistant/test-runner-workhub-answers.js +4 -1
- package/lib/role-assistant/test-runner-workhub-missing-fields.js +42 -0
- package/lib/role-assistant/test-runner-workhub-wait-stop.js +94 -0
- package/lib/role-assistant/test-runner-workhub.js +28 -19
- package/lib/schema/application-schema.json +14 -2
- package/lib/schema/external-datasource.schema.json +23 -3
- package/lib/schema/infra.parameter.yaml +440 -56
- package/lib/schema/infrastructure-schema.json +213 -120
- package/lib/utils/compose-generate-docker-compose.js +9 -14
- package/lib/utils/compose-generator.js +4 -7
- package/lib/utils/compose-miso-env.js +2 -2
- package/lib/utils/compose-traefik-ingress-base.js +3 -4
- package/lib/utils/datasource-binary-evidence.js +92 -0
- package/lib/utils/datasource-test-run-capability-scope.js +44 -1
- package/lib/utils/datasource-test-run-debug-display.js +2 -0
- package/lib/utils/datasource-test-run-display.js +8 -2
- package/lib/utils/datasource-test-run-issue-guidance.js +176 -0
- package/lib/utils/datasource-test-run-tty-log.js +2 -0
- package/lib/utils/declarative-url-ports.js +3 -0
- package/lib/utils/env-copy.js +11 -10
- package/lib/utils/env-environment-file-paths.js +105 -0
- package/lib/utils/environment-scoped-resources.js +48 -14
- package/lib/utils/external-system-system-test-tty.js +3 -2
- package/lib/utils/image-tags.js +2 -2
- package/lib/utils/paths-system-builder-keys.js +7 -1
- package/lib/utils/paths.js +7 -2
- package/lib/utils/platform-kv-ref.js +1 -1
- package/lib/utils/postgres-platform-bootstrap.js +35 -1
- package/lib/utils/prepare-local-data-mount.js +58 -0
- package/lib/utils/redis-env-scope.js +21 -1
- package/lib/utils/registry-auth-sources.js +154 -0
- package/lib/utils/registry-credentials.js +131 -14
- package/lib/utils/secrets-generator.js +30 -21
- package/lib/utils/secrets-helpers.js +5 -8
- package/lib/utils/secrets-kv-scope.js +127 -28
- package/lib/utils/secrets-materialize-local.js +9 -0
- package/lib/utils/secrets-missing-error.js +35 -1
- package/lib/utils/system-secret-mapping.js +125 -0
- package/lib/utils/test-log-writer.js +2 -1
- package/lib/utils/token-manager.js +14 -8
- package/lib/utils/url-public-path-prefix.js +6 -10
- package/lib/validation/external-manifest-validator.js +5 -0
- package/lib/validation/openapi-contract-surface-validator.js +3 -1
- package/lib/validation/validate-external-file.js +5 -1
- package/package.json +6 -4
- package/templates/agent-kit/agent-kit.yaml +1 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/SKILL.md +2 -1
- package/templates/agent-kit/skills/aifabrix-connected-system/references/delivery-gates.md +15 -0
- package/templates/agent-kit/skills/aifabrix-plan/SKILL.md +3 -2
- package/templates/agent-kit/skills/aifabrix-prove/SKILL.md +6 -2
- package/templates/agent-kit/skills/aifabrix-prove/references/evidence-lifecycle.md +22 -0
- package/templates/agent-kit/skills/aifabrix-role-assistant/SKILL.md +7 -1
- package/templates/agent-kit/skills/aifabrix-role-assistant/references/testing-playbook.md +117 -0
- package/templates/agent-kit/skills/shared/interaction.md +83 -0
- package/templates/agent-kit/skills/shared/status.md +3 -12
- package/templates/applications/builder-api/application.yaml +1 -1
- package/templates/applications/builder-api/env.template +5 -1
- package/templates/applications/dataplane/application.yaml +2 -2
- package/templates/applications/dataplane/env.template +10 -12
- package/templates/applications/integration-server/application.yaml +91 -0
- package/templates/applications/integration-server/env.template +215 -0
- package/templates/applications/keycloak/application.yaml +6 -1
- package/templates/applications/mirrored-templates.json +52 -0
- package/templates/applications/miso-controller/application.yaml +116 -2
- package/templates/applications/miso-controller/env.template +62 -17
- package/templates/applications/miso-controller/rbac.yaml +17 -0
- package/templates/external-system/external-datasource.yaml.hbs +7 -1
- package/templates/marketplace/createUiDefinition.json +52 -4
- package/templates/marketplace/main.json +88 -10
- package/templates/python/docker-compose.hbs +1 -1
- package/templates/agent-kit/skills/aifabrix-plan/references/interaction.md +0 -41
- /package/{lib/programmatic/help-content → docs/builder-help/content}/channel-onboarding.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/cip-overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/connected-system-ui.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/dimensions-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/enterprise-sync-fabrix.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/overview.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/subscription-guide.md +0 -0
- /package/{lib/programmatic/help-content → docs/builder-help/content}/workflow.md +0 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Generate keyed document retrieval from vendor OpenAPI response media types.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const fs = require('fs');
|
|
8
|
+
const { toCamelCaseKey } = require('./repair-datasource-auto-rbac');
|
|
9
|
+
const { loadConfigFile } = require('../utils/config-format');
|
|
10
|
+
const { documentKeyToLocalOpenApiPath } = require('./repair-openapi-export');
|
|
11
|
+
const { findVendorOperation } = require('../validation/openapi-contract-vendor-validation');
|
|
12
|
+
|
|
13
|
+
/** @param {Object} ds @param {Object} options @returns {Object|null} */
|
|
14
|
+
function loadVendorSpec(ds, options) {
|
|
15
|
+
if (options.openapiSpec) return options.openapiSpec;
|
|
16
|
+
if (!options.appPath || !ds.openapi?.documentKey) return null;
|
|
17
|
+
const file = documentKeyToLocalOpenApiPath(options.appPath, ds.systemKey || '', ds.openapi.documentKey);
|
|
18
|
+
return fs.existsSync(file) ? loadConfigFile(file) : null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** @param {Object} operation @returns {Object[]} */
|
|
22
|
+
function binaryResponses(operation) {
|
|
23
|
+
return Object.entries(operation?.responses || {})
|
|
24
|
+
.filter(([status]) => /^2(?:\d\d|XX)$/i.test(status))
|
|
25
|
+
.map(([, response]) => response)
|
|
26
|
+
.filter(response => Object.keys(response?.content || {}).some(type =>
|
|
27
|
+
/^(application\/(octet-stream|pdf)|image\/[^;]+)(;|$)/i.test(type)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/** @param {Object} ds @param {Object} operation @param {Object[]} responses */
|
|
31
|
+
function addMetadataMappings(ds, operation, responses) {
|
|
32
|
+
ds.fieldMappings = ds.fieldMappings || {};
|
|
33
|
+
ds.fieldMappings.attributes = ds.fieldMappings.attributes || {};
|
|
34
|
+
const attributes = ds.fieldMappings.attributes;
|
|
35
|
+
for (const response of responses) {
|
|
36
|
+
for (const name of Object.keys(response.headers || {})) {
|
|
37
|
+
addMappingStub(attributes, name, 'headers');
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
for (const param of operation.parameters || []) {
|
|
41
|
+
if (param.required && ['query', 'path'].includes(param.in) && param.name) {
|
|
42
|
+
addMappingStub(attributes, param.name, 'params');
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** @param {Object} attributes @param {string} name @param {string} source */
|
|
48
|
+
function addMappingStub(attributes, name, source) {
|
|
49
|
+
const key = toCamelCaseKey(name);
|
|
50
|
+
if (!/^[a-z][a-zA-Z0-9]*$/.test(key) || Object.hasOwn(attributes, key)) return;
|
|
51
|
+
attributes[key] = { expression: `{{raw.${source}.${name}}}` };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/** @param {Object} ds @param {string} ref @returns {Object[]} */
|
|
55
|
+
function ensureGetSteps(ds, ref) {
|
|
56
|
+
ds.execution = ds.execution || {};
|
|
57
|
+
ds.execution.engine = 'cip';
|
|
58
|
+
ds.execution.cip = ds.execution.cip || { version: '1.0', operations: {} };
|
|
59
|
+
ds.execution.cip.operations = ds.execution.cip.operations || {};
|
|
60
|
+
const operations = ds.execution.cip.operations;
|
|
61
|
+
if (!operations.get) {
|
|
62
|
+
operations.get = { steps: [
|
|
63
|
+
{ fetch: { source: 'openapi', openapiRef: ref, responseType: 'binary' } },
|
|
64
|
+
{ map: { useFieldMappings: true } },
|
|
65
|
+
{ filter: { abac: { mode: 'mandatory' } } },
|
|
66
|
+
{ output: { mode: 'documents' } }
|
|
67
|
+
] };
|
|
68
|
+
}
|
|
69
|
+
return Array.isArray(operations.get.steps) ? operations.get.steps : [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Leave list-based document sync and author-owned unrelated operations unchanged.
|
|
74
|
+
* @param {Object} ds - Datasource, mutated
|
|
75
|
+
* @param {Object} options - Vendor spec or local appPath
|
|
76
|
+
* @param {string[]} changes - Repair log
|
|
77
|
+
* @returns {boolean}
|
|
78
|
+
*/
|
|
79
|
+
function repairKeyedDocument(ds, options = {}, changes = []) {
|
|
80
|
+
const candidate = keyedDocumentCandidate(ds, options);
|
|
81
|
+
if (!candidate) return false;
|
|
82
|
+
const { ref, vendor, responses } = candidate;
|
|
83
|
+
const before = JSON.stringify(ds);
|
|
84
|
+
const getSteps = ensureGetSteps(ds, ref);
|
|
85
|
+
if (!getSteps.some(step => step?.fetch) || !getSteps.some(step => step?.output)) return false;
|
|
86
|
+
for (const step of getSteps) {
|
|
87
|
+
if (step?.fetch && (step.fetch.openapiRef || 'get') === ref) step.fetch.responseType = 'binary';
|
|
88
|
+
if (step?.output) step.output.mode = 'documents';
|
|
89
|
+
}
|
|
90
|
+
ds.documentStorage = { enabled: true, ingestAfterSync: true,
|
|
91
|
+
...ds.documentStorage, responseType: 'binary', binaryOperationRef: 'get' };
|
|
92
|
+
addMetadataMappings(ds, vendor, responses);
|
|
93
|
+
if (JSON.stringify(ds) === before) return false;
|
|
94
|
+
changes.push('Configured keyed binary get with documents output and header/parameter mappings');
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** @param {Object} ds @param {Object} options @returns {Object|null} */
|
|
99
|
+
function keyedDocumentCandidate(ds, options) {
|
|
100
|
+
if (!['documentStorage', 'document-storage'].includes(ds?.entityType)) return null;
|
|
101
|
+
if (!canGenerateKeyedDocument(ds)) return null;
|
|
102
|
+
const operations = ds.execution?.cip?.operations || {};
|
|
103
|
+
const steps = operations.get?.steps || [];
|
|
104
|
+
const fetch = steps.find(step => step?.fetch)?.fetch;
|
|
105
|
+
if (fetch && !['openapi', undefined].includes(fetch.source)) return null;
|
|
106
|
+
const ref = fetch?.openapiRef || 'get';
|
|
107
|
+
const binding = ds.openapi?.operations?.[ref];
|
|
108
|
+
const vendor = findVendorOperation(loadVendorSpec(ds, options), binding);
|
|
109
|
+
const responses = binaryResponses(vendor);
|
|
110
|
+
return responses.length ? { ref, vendor, responses } : null;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** @param {Object} ds @returns {boolean} */
|
|
114
|
+
function canGenerateKeyedDocument(ds) {
|
|
115
|
+
if (ds.execution?.cip?.operations?.list || ds.openapi?.operations?.list) return false;
|
|
116
|
+
if (ds.capabilities?.some(cap => (cap.key || cap) === 'list')) return false;
|
|
117
|
+
if (ds.documentStorage?.enabled === false) return false;
|
|
118
|
+
if (ds.execution?.engine && ds.execution.engine !== 'cip') return false;
|
|
119
|
+
return !ds.documentStorage?.binaryOperationRef || ds.documentStorage.binaryOperationRef === 'get';
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
module.exports = { repairKeyedDocument };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Migrate legacy datasource storage and mapping shapes.
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
*/
|
|
5
|
+
'use strict';
|
|
6
|
+
|
|
7
|
+
const ENTITY_TYPES = {
|
|
8
|
+
'record-storage': 'recordStorage',
|
|
9
|
+
'document-storage': 'documentStorage',
|
|
10
|
+
'vector-store': 'vectorStore',
|
|
11
|
+
'message-service': 'messageService'
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Preserve legacy attribute types in metadataSchema and qualify raw input paths.
|
|
16
|
+
* @param {Object} parsed
|
|
17
|
+
* @param {string[]} changes
|
|
18
|
+
* @returns {boolean}
|
|
19
|
+
*/
|
|
20
|
+
function repairLegacyAttributes(parsed, changes) {
|
|
21
|
+
let updated = false;
|
|
22
|
+
for (const [key, attr] of Object.entries(parsed.fieldMappings?.attributes || {})) {
|
|
23
|
+
if (!attr || typeof attr !== 'object') continue;
|
|
24
|
+
if (typeof attr.expression === 'string' && /^\{\{\s*metadata\.[\w.[\]]+\s*\}\}$/.test(attr.expression)) {
|
|
25
|
+
attr.expression = attr.expression.replace(/\{\{\s*(metadata\.[\w.[\]]+)\s*\}\}/, '{{raw.$1}}');
|
|
26
|
+
changes.push(`Qualified legacy attribute '${key}' with raw input root`);
|
|
27
|
+
updated = true;
|
|
28
|
+
}
|
|
29
|
+
if (['string', 'number', 'integer', 'boolean', 'object', 'array', 'null'].includes(attr.type)) {
|
|
30
|
+
parsed.metadataSchema ||= { type: 'object', additionalProperties: true };
|
|
31
|
+
parsed.metadataSchema.properties ||= {};
|
|
32
|
+
parsed.metadataSchema.properties[key] ||= { type: attr.type };
|
|
33
|
+
delete attr.type;
|
|
34
|
+
changes.push(`Moved legacy attribute '${key}' type to metadataSchema`);
|
|
35
|
+
updated = true;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return updated;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Move only unambiguous local bindings; preserve unsupported/conflicting input.
|
|
43
|
+
* @param {Object} parsed
|
|
44
|
+
* @param {string[]} changes
|
|
45
|
+
* @returns {boolean}
|
|
46
|
+
*/
|
|
47
|
+
function repairLegacyDimensions(parsed, changes) {
|
|
48
|
+
const legacy = parsed.fieldMappings?.dimensions;
|
|
49
|
+
if (!legacy || typeof legacy !== 'object' || Array.isArray(legacy)) return false;
|
|
50
|
+
let updated = false;
|
|
51
|
+
for (const [key, value] of Object.entries(legacy)) {
|
|
52
|
+
const match = typeof value === 'string' && /^metadata\.([a-z][a-zA-Z0-9]*)$/.exec(value);
|
|
53
|
+
if (!match || !Object.hasOwn(parsed.fieldMappings.attributes || {}, match[1])) continue;
|
|
54
|
+
const binding = { type: 'local', field: match[1] };
|
|
55
|
+
const existing = parsed.dimensions?.[key];
|
|
56
|
+
if (existing && (existing.type !== 'local' || existing.field !== match[1])) continue;
|
|
57
|
+
parsed.dimensions ||= {};
|
|
58
|
+
parsed.dimensions[key] ||= binding;
|
|
59
|
+
delete legacy[key];
|
|
60
|
+
changes.push(`Moved legacy dimension '${key}' to root dimensions`);
|
|
61
|
+
updated = true;
|
|
62
|
+
}
|
|
63
|
+
if (Object.keys(legacy).length === 0) {
|
|
64
|
+
delete parsed.fieldMappings.dimensions;
|
|
65
|
+
updated = true;
|
|
66
|
+
}
|
|
67
|
+
return updated;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @param {Object} parsed
|
|
72
|
+
* @param {string[]} changes
|
|
73
|
+
* @returns {boolean}
|
|
74
|
+
*/
|
|
75
|
+
function repairLegacyDatasource(parsed, changes = []) {
|
|
76
|
+
if (!parsed || typeof parsed !== 'object') return false;
|
|
77
|
+
let updated = false;
|
|
78
|
+
if (Object.hasOwn(ENTITY_TYPES, parsed.entityType)) {
|
|
79
|
+
parsed.entityType = ENTITY_TYPES[parsed.entityType];
|
|
80
|
+
changes.push(`Normalized legacy entityType to ${parsed.entityType}`);
|
|
81
|
+
updated = true;
|
|
82
|
+
}
|
|
83
|
+
if (['recordStorage', 'documentStorage'].includes(parsed.entityType) && !parsed.labelKey
|
|
84
|
+
&& parsed.primaryKey?.length === 1
|
|
85
|
+
&& Object.hasOwn(parsed.fieldMappings?.attributes || {}, parsed.primaryKey[0])) {
|
|
86
|
+
parsed.labelKey = [...parsed.primaryKey];
|
|
87
|
+
changes.push('Defaulted missing labelKey to the sole primary key attribute');
|
|
88
|
+
updated = true;
|
|
89
|
+
}
|
|
90
|
+
updated = repairLegacyAttributes(parsed, changes) || updated;
|
|
91
|
+
return repairLegacyDimensions(parsed, changes) || updated;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = { repairLegacyDatasource };
|
|
@@ -37,6 +37,7 @@ function runDatasourceRepairs(appPath, datasourceFiles, options, dryRun, changes
|
|
|
37
37
|
try {
|
|
38
38
|
const parsed = loadConfigFile(filePath);
|
|
39
39
|
const { updated: fileUpdated, changes: fileChanges } = repairDatasourceFile(parsed, {
|
|
40
|
+
appPath,
|
|
40
41
|
expose: options.expose,
|
|
41
42
|
sync: options.sync,
|
|
42
43
|
test: options.test,
|
|
@@ -105,6 +105,26 @@ function readPlatformDeployImageRef(appName) {
|
|
|
105
105
|
* @param {{ quiet?: boolean }} [opts]
|
|
106
106
|
* @returns {Promise<boolean>} True when a pull was attempted
|
|
107
107
|
*/
|
|
108
|
+
/**
|
|
109
|
+
* True when Docker already holds the image.
|
|
110
|
+
*
|
|
111
|
+
* An installation with no registry configured deploys the `application.yaml` image as it
|
|
112
|
+
* stands, which is built locally and never pushed. Authenticating first would prompt for
|
|
113
|
+
* credentials the install does not need, and pulling would fail against a registry that
|
|
114
|
+
* has never seen the tag, so the local image is the answer when it is already there.
|
|
115
|
+
*
|
|
116
|
+
* @param {string} imageRef - Image reference
|
|
117
|
+
* @returns {Promise<boolean>}
|
|
118
|
+
*/
|
|
119
|
+
async function imageExistsLocally(imageRef) {
|
|
120
|
+
try {
|
|
121
|
+
await dockerExec.execWithDockerEnv(`docker image inspect ${imageRef}`);
|
|
122
|
+
return true;
|
|
123
|
+
} catch {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
108
128
|
async function pullPlatformAppImage(appName, opts = {}) {
|
|
109
129
|
const quiet = Boolean(opts.quiet);
|
|
110
130
|
const imageRef = readPlatformDeployImageRef(appName);
|
|
@@ -114,6 +134,12 @@ async function pullPlatformAppImage(appName, opts = {}) {
|
|
|
114
134
|
}
|
|
115
135
|
return false;
|
|
116
136
|
}
|
|
137
|
+
if (await imageExistsLocally(imageRef)) {
|
|
138
|
+
if (!quiet) {
|
|
139
|
+
logger.log(formatDatasourceListRow('ok', appName, 'image already local'));
|
|
140
|
+
}
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
117
143
|
// A partial stored credential pair fails closed here instead of degrading to a warning.
|
|
118
144
|
await ensureLoginForImageRefs([imageRef]);
|
|
119
145
|
try {
|
|
@@ -58,7 +58,13 @@ const {
|
|
|
58
58
|
} = require('../utils/infra-optional-service-flags');
|
|
59
59
|
|
|
60
60
|
/** Builder app keys touched by `up-platform --force`. */
|
|
61
|
-
const PLATFORM_APPS = [
|
|
61
|
+
const PLATFORM_APPS = [
|
|
62
|
+
'keycloak',
|
|
63
|
+
'miso-controller',
|
|
64
|
+
'dataplane',
|
|
65
|
+
'builder-api',
|
|
66
|
+
'integration-server'
|
|
67
|
+
];
|
|
62
68
|
|
|
63
69
|
function formatBackupSuffix() {
|
|
64
70
|
const d = new Date();
|
|
@@ -322,8 +328,7 @@ function removeUserLocalSecrets() {
|
|
|
322
328
|
}
|
|
323
329
|
|
|
324
330
|
/**
|
|
325
|
-
* Fresh install: wizard collects admin
|
|
326
|
-
* then up-infra + up-platform.
|
|
331
|
+
* Fresh install: wizard collects admin credentials, then runs up-infra + up-platform.
|
|
327
332
|
*
|
|
328
333
|
* @async
|
|
329
334
|
* @param {{ adminEmail: string, adminPassword?: string, passwordBundle?: object }} adminCreds
|
|
@@ -345,9 +350,6 @@ async function runFreshInstall(adminCreds) {
|
|
|
345
350
|
});
|
|
346
351
|
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
347
352
|
await runSetupImageRefresh({ quiet: true });
|
|
348
|
-
// Bring up infra first, then collect optional platform-level secrets (AI tool)
|
|
349
|
-
// so the flow feels like a product installer: infra → platform configuration → platform services.
|
|
350
|
-
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
351
353
|
// Fresh-install should reset dev defaults (env + controller URL) the same way
|
|
352
354
|
// as other setup recovery paths, otherwise the platform can come up pointed at
|
|
353
355
|
// stale configuration.
|
|
@@ -382,7 +384,6 @@ async function runReinstall() {
|
|
|
382
384
|
await runSetupImageRefresh({ quiet: true });
|
|
383
385
|
const adminCreds = await setupPrompts.promptAdminCredentials();
|
|
384
386
|
await config.setAdminEmail(adminCreds.adminEmail);
|
|
385
|
-
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
386
387
|
const infraSpin = startSpinner('Starting infrastructure...');
|
|
387
388
|
await startInfraFromConfig({
|
|
388
389
|
adminEmail: adminCreds.adminEmail,
|
|
@@ -436,7 +437,6 @@ async function runWipeData() {
|
|
|
436
437
|
});
|
|
437
438
|
stopSpinnerSuccess(wipeSpin, 'Databases reset');
|
|
438
439
|
await runSetupImageRefresh({ quiet: true });
|
|
439
|
-
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
440
440
|
const infraSpin = startSpinner('Starting infrastructure...');
|
|
441
441
|
await startInfraFromConfig({});
|
|
442
442
|
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
@@ -460,7 +460,6 @@ async function runWipeData() {
|
|
|
460
460
|
*/
|
|
461
461
|
async function runUpdateImages() {
|
|
462
462
|
await runSetupImageRefresh({ quiet: true });
|
|
463
|
-
await setupPrompts.promptAiTool({ silentIfConfigured: true });
|
|
464
463
|
const infraSpin = startSpinner('Starting infrastructure...');
|
|
465
464
|
await startInfraFromConfig({});
|
|
466
465
|
stopSpinnerSuccess(infraSpin, 'Infrastructure ready');
|
|
@@ -73,8 +73,42 @@ async function promptSetupPlatformMode(options = {}) {
|
|
|
73
73
|
return normalizeSetupPlatformMode(mode);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Whether this installation carries the integration server.
|
|
78
|
+
*
|
|
79
|
+
* It runs once per stack in the `miso` environment and most installations do not need it,
|
|
80
|
+
* so it is opt-in rather than something every install acquires by default. The answer is
|
|
81
|
+
* persisted, so it is asked once rather than on every run.
|
|
82
|
+
*
|
|
83
|
+
* `--integration-server` and `--no-integration-server` answer it non-interactively; a
|
|
84
|
+
* non-TTY run without either defaults to not installing it, because acquiring an extra
|
|
85
|
+
* application by silence is the wrong default.
|
|
86
|
+
*
|
|
87
|
+
* @async
|
|
88
|
+
* @param {Object} [options] - CLI options
|
|
89
|
+
* @returns {Promise<boolean>}
|
|
90
|
+
*/
|
|
91
|
+
async function promptIntegrationServer(options = {}) {
|
|
92
|
+
if (options.integrationServer === true || options.integrationServer === false) {
|
|
93
|
+
return options.integrationServer;
|
|
94
|
+
}
|
|
95
|
+
if (!process.stdin.isTTY || options.yes === true) {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
const { integrationServer } = await inquirer.prompt([
|
|
99
|
+
{
|
|
100
|
+
type: 'confirm',
|
|
101
|
+
name: 'integrationServer',
|
|
102
|
+
message: 'Install the integration server (runs once in the miso environment)?',
|
|
103
|
+
default: false
|
|
104
|
+
}
|
|
105
|
+
]);
|
|
106
|
+
return Boolean(integrationServer);
|
|
107
|
+
}
|
|
108
|
+
|
|
76
109
|
module.exports = {
|
|
77
110
|
resolvePlatformModeFromOptions,
|
|
78
111
|
promptSetupPlatformMode,
|
|
112
|
+
promptIntegrationServer,
|
|
79
113
|
getSetupPlatformModePromptChoices
|
|
80
114
|
};
|
|
@@ -1,23 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Inquirer prompts for `aifabrix setup`.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Setup prompt helpers:
|
|
5
5
|
* 1. {@link promptModeSelection} - Mode menu shown when infra is already up.
|
|
6
6
|
* 2. {@link promptAdminCredentials} - Admin email + password (fresh install only); email default
|
|
7
7
|
* from {@link module:lib/core/config.getAdminEmail} when `adminEmail` exists in config.yaml.
|
|
8
|
-
* 3. {@link promptAiTool} - AI tool provider + keys, only when the merged
|
|
9
|
-
* secret cascade (user-local + shared) does not already provide the keys.
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
* resolution honors both user-local secrets and the shared `aifabrix-secrets`
|
|
13
|
-
* store (file or remote API) when configured.
|
|
14
|
-
*
|
|
15
|
-
* Writes use `setSecretInStore(...)` (primary user `secrets.local.yaml` only; shared is human via
|
|
16
|
-
* `aifabrix secret set --shared`) so the
|
|
17
|
-
* installer can write either to user-local secrets or to the shared store,
|
|
18
|
-
* depending on config.
|
|
19
|
-
*
|
|
20
|
-
* @fileoverview Setup prompts (mode menu, admin creds, AI tool)
|
|
9
|
+
* @fileoverview Setup prompts (mode menu, admin credentials, builder conflicts)
|
|
21
10
|
* @author AI Fabrix Team
|
|
22
11
|
* @version 2.0.0
|
|
23
12
|
*/
|
|
@@ -26,11 +15,6 @@
|
|
|
26
15
|
|
|
27
16
|
const path = require('path');
|
|
28
17
|
const inquirer = require('inquirer');
|
|
29
|
-
const chalk = require('chalk');
|
|
30
|
-
const logger = require('../utils/logger');
|
|
31
|
-
const secretsCore = require('../core/secrets');
|
|
32
|
-
const secretsEnsure = require('../core/secrets-ensure');
|
|
33
|
-
const { formatSuccessLine, infoLine } = require('../utils/cli-test-layout-chalk');
|
|
34
18
|
const { validateEmail, validatePassword } = require('./setup-prompts-validators');
|
|
35
19
|
const {
|
|
36
20
|
promptAdminCredentialsWithProfile,
|
|
@@ -45,13 +29,6 @@ const MODE = Object.freeze({
|
|
|
45
29
|
UPDATE_IMAGES: 'update-images'
|
|
46
30
|
});
|
|
47
31
|
|
|
48
|
-
/** AI tool key names in `secrets.local.yaml` / shared secrets. */
|
|
49
|
-
const AI_KEYS = Object.freeze({
|
|
50
|
-
OPENAI_API_KEY: 'secrets-openaiApiKeyVault',
|
|
51
|
-
AZURE_OPENAI_URL: 'azure-openaiapi-urlKeyVault',
|
|
52
|
-
AZURE_OPENAI_API_KEY: 'secrets-azureOpenaiApiKeyVault'
|
|
53
|
-
});
|
|
54
|
-
|
|
55
32
|
/** Builder folder conflict actions (setup preflight). */
|
|
56
33
|
const BUILDER_DIR_ACTION = Object.freeze({
|
|
57
34
|
KEEP: 'keep',
|
|
@@ -131,158 +108,6 @@ async function promptAdminCredentials(options = {}) {
|
|
|
131
108
|
};
|
|
132
109
|
}
|
|
133
110
|
|
|
134
|
-
/**
|
|
135
|
-
* @typedef {Object} AiToolStatus
|
|
136
|
-
* @property {boolean} openAiConfigured - True when OpenAI key resolves non-empty
|
|
137
|
-
* @property {boolean} azureOpenAiConfigured - True when Azure URL + key resolve non-empty
|
|
138
|
-
*/
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* Detect whether AI tool keys are already present in the merged secret view.
|
|
142
|
-
* Treats values surrounded by Handlebars-style placeholders (e.g. `{{...}}`)
|
|
143
|
-
* as not configured.
|
|
144
|
-
*
|
|
145
|
-
* @async
|
|
146
|
-
* @returns {Promise<AiToolStatus>}
|
|
147
|
-
*/
|
|
148
|
-
async function detectAiToolStatus() {
|
|
149
|
-
let merged = {};
|
|
150
|
-
try {
|
|
151
|
-
merged = await secretsCore.loadSecrets(undefined);
|
|
152
|
-
} catch {
|
|
153
|
-
merged = {};
|
|
154
|
-
}
|
|
155
|
-
const isSet = (key) => {
|
|
156
|
-
const raw = merged ? merged[key] : undefined;
|
|
157
|
-
if (raw === undefined || raw === null) return false;
|
|
158
|
-
const value = String(raw).trim();
|
|
159
|
-
if (!value) return false;
|
|
160
|
-
if (value.startsWith('{{') && value.endsWith('}}')) return false;
|
|
161
|
-
return true;
|
|
162
|
-
};
|
|
163
|
-
return {
|
|
164
|
-
openAiConfigured: isSet(AI_KEYS.OPENAI_API_KEY),
|
|
165
|
-
azureOpenAiConfigured:
|
|
166
|
-
isSet(AI_KEYS.AZURE_OPENAI_URL) && isSet(AI_KEYS.AZURE_OPENAI_API_KEY)
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
/**
|
|
171
|
-
* Ask which AI tool the user wants to configure when none is configured yet.
|
|
172
|
-
* @async
|
|
173
|
-
* @returns {Promise<'openai'|'azure'|'skip'>}
|
|
174
|
-
*/
|
|
175
|
-
async function askAiToolChoice() {
|
|
176
|
-
const { choice } = await inquirer.prompt([
|
|
177
|
-
{
|
|
178
|
-
type: 'list',
|
|
179
|
-
name: 'choice',
|
|
180
|
-
message: 'Which AI tool do you want to configure for the dataplane?',
|
|
181
|
-
choices: [
|
|
182
|
-
{ name: 'OpenAI (api.openai.com)', value: 'openai' },
|
|
183
|
-
{ name: 'Azure OpenAI (your Azure resource)', value: 'azure' },
|
|
184
|
-
{ name: 'Skip for now (set later via aifabrix secret set)', value: 'skip' }
|
|
185
|
-
]
|
|
186
|
-
}
|
|
187
|
-
]);
|
|
188
|
-
return choice;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
/**
|
|
192
|
-
* Collect and persist OpenAI key.
|
|
193
|
-
* @async
|
|
194
|
-
* @returns {Promise<void>}
|
|
195
|
-
*/
|
|
196
|
-
async function collectAndSaveOpenAiKey() {
|
|
197
|
-
const { apiKey } = await inquirer.prompt([
|
|
198
|
-
{
|
|
199
|
-
type: 'password',
|
|
200
|
-
name: 'apiKey',
|
|
201
|
-
message: 'OpenAI API key:',
|
|
202
|
-
mask: '*',
|
|
203
|
-
validate(input) {
|
|
204
|
-
return String(input || '').trim() ? true : 'API key is required';
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
]);
|
|
208
|
-
await secretsEnsure.setSecretInStore(AI_KEYS.OPENAI_API_KEY, String(apiKey).trim());
|
|
209
|
-
logger.log(formatSuccessLine('OpenAI API key saved'));
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
/**
|
|
213
|
-
* Collect and persist Azure OpenAI URL + key.
|
|
214
|
-
* @async
|
|
215
|
-
* @returns {Promise<void>}
|
|
216
|
-
*/
|
|
217
|
-
async function collectAndSaveAzureOpenAi() {
|
|
218
|
-
const answers = await inquirer.prompt([
|
|
219
|
-
{
|
|
220
|
-
type: 'input',
|
|
221
|
-
name: 'url',
|
|
222
|
-
message: 'Azure OpenAI endpoint URL (e.g. https://my-aoai.openai.azure.com):',
|
|
223
|
-
validate(input) {
|
|
224
|
-
const value = String(input || '').trim();
|
|
225
|
-
if (!value) return 'Endpoint URL is required';
|
|
226
|
-
if (!/^https?:\/\//.test(value)) return 'URL must start with http(s)://';
|
|
227
|
-
return true;
|
|
228
|
-
}
|
|
229
|
-
},
|
|
230
|
-
{
|
|
231
|
-
type: 'password',
|
|
232
|
-
name: 'apiKey',
|
|
233
|
-
message: 'Azure OpenAI API key:',
|
|
234
|
-
mask: '*',
|
|
235
|
-
validate(input) {
|
|
236
|
-
return String(input || '').trim() ? true : 'API key is required';
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
]);
|
|
240
|
-
await secretsEnsure.setSecretInStore(AI_KEYS.AZURE_OPENAI_URL, String(answers.url).trim());
|
|
241
|
-
await secretsEnsure.setSecretInStore(AI_KEYS.AZURE_OPENAI_API_KEY, String(answers.apiKey).trim());
|
|
242
|
-
logger.log(formatSuccessLine('Azure OpenAI endpoint and API key saved'));
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
/**
|
|
246
|
-
* Run the AI tool prompt sequence.
|
|
247
|
-
* Skips silently when either provider is already configured (in any source).
|
|
248
|
-
*
|
|
249
|
-
* @async
|
|
250
|
-
* @param {{ silentIfConfigured?: boolean }} [options]
|
|
251
|
-
* @returns {Promise<void>}
|
|
252
|
-
*/
|
|
253
|
-
async function promptAiTool(options = {}) {
|
|
254
|
-
const silentIfConfigured = options && options.silentIfConfigured === true;
|
|
255
|
-
const status = await detectAiToolStatus();
|
|
256
|
-
if (status.openAiConfigured) {
|
|
257
|
-
if (!silentIfConfigured) {
|
|
258
|
-
logger.log(infoLine('OpenAI key already configured - skipping AI tool prompt.'));
|
|
259
|
-
}
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
if (status.azureOpenAiConfigured) {
|
|
263
|
-
if (!silentIfConfigured) {
|
|
264
|
-
logger.log(infoLine('Azure OpenAI endpoint and key already configured - skipping AI tool prompt.'));
|
|
265
|
-
}
|
|
266
|
-
return;
|
|
267
|
-
}
|
|
268
|
-
const choice = await askAiToolChoice();
|
|
269
|
-
if (choice === 'openai') {
|
|
270
|
-
await collectAndSaveOpenAiKey();
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
|
-
if (choice === 'azure') {
|
|
274
|
-
await collectAndSaveAzureOpenAi();
|
|
275
|
-
return;
|
|
276
|
-
}
|
|
277
|
-
logger.log(
|
|
278
|
-
chalk.gray(
|
|
279
|
-
'Skipped. Set later: aifabrix secret set ' +
|
|
280
|
-
AI_KEYS.OPENAI_API_KEY +
|
|
281
|
-
' <key> (or the two azure-openaiapi-urlKeyVault / secrets-azureOpenaiApiKeyVault keys)'
|
|
282
|
-
)
|
|
283
|
-
);
|
|
284
|
-
}
|
|
285
|
-
|
|
286
111
|
/**
|
|
287
112
|
* Absolute directory paths (with trailing sep) shown when setup will replace platform apps.
|
|
288
113
|
*
|
|
@@ -353,7 +178,6 @@ async function promptBuilderDirConflict(info) {
|
|
|
353
178
|
|
|
354
179
|
module.exports = {
|
|
355
180
|
MODE,
|
|
356
|
-
AI_KEYS,
|
|
357
181
|
BUILDER_DIR_ACTION,
|
|
358
182
|
INSTALLATION_PROFILE,
|
|
359
183
|
formatBuilderPlatformReplaceLines,
|
|
@@ -361,8 +185,6 @@ module.exports = {
|
|
|
361
185
|
confirmDestructiveMode,
|
|
362
186
|
promptInstallationProfile,
|
|
363
187
|
promptAdminCredentials,
|
|
364
|
-
promptAiTool,
|
|
365
|
-
detectAiToolStatus,
|
|
366
188
|
promptBuilderDirConflict,
|
|
367
189
|
validateEmail,
|
|
368
190
|
validatePassword
|
package/lib/commands/setup.js
CHANGED
|
@@ -110,8 +110,11 @@ async function runSetupWithCliMode(options, cliMode) {
|
|
|
110
110
|
|
|
111
111
|
async function applySetupPlatformMode(options) {
|
|
112
112
|
const mode = await setupPlatformModePrompts.promptSetupPlatformMode(options);
|
|
113
|
+
const integrationServer = await setupPlatformModePrompts.promptIntegrationServer(options);
|
|
113
114
|
const cfg = await config.getConfig();
|
|
114
115
|
applyPlatformTopologyFlagsToConfig(cfg, mode);
|
|
116
|
+
const { onboardingAppsForIntegrationServer } = require('../core/local-env-overrides');
|
|
117
|
+
cfg.onboardingApps = onboardingAppsForIntegrationServer(integrationServer);
|
|
115
118
|
await config.saveConfig(cfg);
|
|
116
119
|
await syncPlatformControllerUrlsInConfig();
|
|
117
120
|
return mode;
|
|
@@ -23,10 +23,28 @@ const {
|
|
|
23
23
|
resolveUpBuilderApiControllerContext,
|
|
24
24
|
provisionAndDeployBuilderApi,
|
|
25
25
|
refreshBuilderApiEnvAfterProvision,
|
|
26
|
-
computeBuilderApiRunOverrides
|
|
27
|
-
resolveEnvironment
|
|
26
|
+
computeBuilderApiRunOverrides
|
|
28
27
|
} = require('./up-builder-api-provision');
|
|
29
28
|
|
|
29
|
+
const BUILDER_API_ENVIRONMENT_KEY = 'miso';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Builder API is a platform application and is installed once in miso.
|
|
33
|
+
* The selected workload environment only controls which workloads it manages.
|
|
34
|
+
*
|
|
35
|
+
* @param {Object} options
|
|
36
|
+
* @returns {string}
|
|
37
|
+
*/
|
|
38
|
+
function resolveBuilderApiEnvironmentKey(options) {
|
|
39
|
+
const requested = options && options.envKey
|
|
40
|
+
? String(options.envKey).trim().toLowerCase()
|
|
41
|
+
: BUILDER_API_ENVIRONMENT_KEY;
|
|
42
|
+
if (requested !== BUILDER_API_ENVIRONMENT_KEY) {
|
|
43
|
+
throw new Error('Builder-api can only be installed in environment \'miso\'.');
|
|
44
|
+
}
|
|
45
|
+
return BUILDER_API_ENVIRONMENT_KEY;
|
|
46
|
+
}
|
|
47
|
+
|
|
30
48
|
/**
|
|
31
49
|
* @async
|
|
32
50
|
* @param {Object} [options]
|
|
@@ -39,10 +57,7 @@ async function handleUpBuilderApi(options = {}) {
|
|
|
39
57
|
);
|
|
40
58
|
}
|
|
41
59
|
|
|
42
|
-
const environmentKey =
|
|
43
|
-
options && options.envKey
|
|
44
|
-
? String(options.envKey).trim().toLowerCase()
|
|
45
|
-
: await resolveEnvironment();
|
|
60
|
+
const environmentKey = resolveBuilderApiEnvironmentKey(options);
|
|
46
61
|
|
|
47
62
|
const { controllerUrl, authConfig, useBootstrap } = await resolveUpBuilderApiControllerContext(
|
|
48
63
|
options,
|
|
@@ -63,6 +78,7 @@ async function handleUpBuilderApi(options = {}) {
|
|
|
63
78
|
const { portOverride } = await computeBuilderApiRunOverrides(options);
|
|
64
79
|
|
|
65
80
|
const runOpts = {
|
|
81
|
+
env: environmentKey,
|
|
66
82
|
registry: options.registry,
|
|
67
83
|
registryMode: options.registryMode,
|
|
68
84
|
skipEnvOutputPath: true,
|
|
@@ -79,10 +95,10 @@ async function handleUpBuilderApi(options = {}) {
|
|
|
79
95
|
if (options.platformInstall !== true) {
|
|
80
96
|
logger.log(
|
|
81
97
|
formatSuccessParagraph(
|
|
82
|
-
'up-builder-api complete. Builder-api is registered
|
|
98
|
+
'up-builder-api complete. Builder-api is registered in miso and running locally.'
|
|
83
99
|
)
|
|
84
100
|
);
|
|
85
101
|
}
|
|
86
102
|
}
|
|
87
103
|
|
|
88
|
-
module.exports = { handleUpBuilderApi };
|
|
104
|
+
module.exports = { handleUpBuilderApi, resolveBuilderApiEnvironmentKey };
|