@aifabrix/builder 2.46.0 → 2.47.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/.npmrc.token +1 -0
- package/.temp/jest-protection-convert/run-IFN2nv/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-IvmKLO/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-convert/run-SdvblF/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-b51TsW/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-fiLmb1/.protection/hubspot-companies.json +1 -0
- package/.temp/jest-protection-convert/run-qYGHMU/.protection/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-Mq5re8/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-f3u4YL/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-iQtd1O/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-mdmz5M/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-qbKYxQ/hubspot-companies.yaml +17 -0
- package/.temp/jest-protection-fixtures/hubspot-yzlJy6/hubspot-companies.yaml +17 -0
- package/.temp/validation/summary.txt +5 -0
- package/jest.isolated-projects.js +18 -2
- package/jest.projects.js +24 -0
- package/lib/api/dataplane-health.api.js +19 -7
- package/lib/api/lifecycle.api.js +22 -1
- package/lib/api/resource-types.api.js +107 -0
- package/lib/api/runtime-configuration.api.js +72 -0
- package/lib/api/types/resource-types.types.js +45 -0
- package/lib/api/user-groups.api.js +9 -9
- package/lib/api/users.api.js +8 -8
- package/lib/api/wizard.api.js +10 -2
- package/lib/app/down.js +58 -26
- package/lib/app/index.js +2 -2
- package/lib/app/run-resolve-image.js +2 -1
- package/lib/app/run-stop-containers.js +113 -0
- package/lib/app/run.js +1 -31
- package/lib/app/show-display.js +35 -0
- package/lib/app/show.js +32 -1
- package/lib/build/index.js +17 -5
- package/lib/build/miso-controller-npm-sdk-guard.js +25 -0
- package/lib/channels/add-channel.js +348 -0
- package/lib/channels/channel-artifact-generator.js +141 -0
- package/lib/channels/channel-audit.js +101 -0
- package/lib/channels/channel-auth-context.js +37 -0
- package/lib/channels/channel-credential.js +200 -0
- package/lib/channels/channel-display-name.js +64 -0
- package/lib/channels/channel-external-system.js +106 -0
- package/lib/channels/channel-integration-generator.js +274 -0
- package/lib/channels/channel-probe.js +89 -0
- package/lib/channels/channel-runtime-resolver.js +152 -0
- package/lib/channels/channel-status-display.js +141 -0
- package/lib/channels/channel-targets.js +115 -0
- package/lib/cli/index.js +16 -4
- package/lib/cli/setup-app.js +54 -3
- package/lib/cli/setup-infra-up-dataplane-action.js +2 -2
- package/lib/cli/setup-infra-up-platform-action.js +2 -1
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-utility-help-after.js +4 -1
- package/lib/cli/setup-utility-resolve.js +8 -5
- package/lib/commands/app-logs.js +54 -26
- package/lib/commands/app.js +41 -0
- package/lib/commands/auth-status-dataplane-version.js +97 -61
- package/lib/commands/auth-status.js +2 -7
- package/lib/commands/channel.js +58 -0
- package/lib/commands/datasource.js +1 -1
- package/lib/commands/identity-apply-sync.js +49 -8
- package/lib/commands/identity-group-cli.js +66 -26
- package/lib/commands/identity-membership-role-cache.js +58 -37
- package/lib/commands/identity-shared.js +22 -1
- package/lib/commands/identity-user-cli.js +80 -34
- package/lib/commands/repair-auth-apply.js +30 -4
- package/lib/commands/repair-auth-config.js +8 -13
- package/lib/commands/repair-datasource-com-v2.js +15 -0
- package/lib/commands/repair-datasource-service-contract.js +206 -0
- package/lib/commands/repair-datasource.js +53 -18
- package/lib/commands/repair-env-template.js +12 -12
- package/lib/commands/repair-openapi-sync.js +26 -4
- package/lib/commands/repair-steps.js +28 -13
- package/lib/commands/repair-system-alignment.js +7 -4
- package/lib/commands/resource-type.js +371 -0
- package/lib/commands/setup-modes.js +1 -1
- package/lib/commands/setup-prompts-platform-mode.js +24 -21
- package/lib/commands/test-trust-external.js +39 -90
- package/lib/commands/up-common.js +33 -1
- package/lib/commands/up-dataplane.js +8 -4
- package/lib/commands/upload.js +24 -3
- package/lib/commands/verify-trust-command-action.js +4 -1
- package/lib/commands/verify-trust-external.js +12 -20
- package/lib/core/config-setup-platform-mode.js +3 -3
- package/lib/core/setup-platform-mode.js +41 -6
- package/lib/datasource/capability/capability-diff-slice.js +2 -2
- package/lib/datasource/capability/capability-manifest.js +254 -0
- package/lib/datasource/capability/capability-resolve.js +3 -4
- package/lib/datasource/capability/copy-operations.js +5 -3
- package/lib/datasource/capability/remove-operations.js +2 -1
- package/lib/datasource/capability/run-capability-copy.js +32 -4
- package/lib/datasource/capability/run-capability-diff.js +3 -3
- package/lib/datasource/capability/run-capability-dimension.js +2 -4
- package/lib/datasource/capability/run-capability-edit.js +4 -7
- package/lib/datasource/capability/run-capability-relate.js +2 -4
- package/lib/datasource/capability/run-capability-remove.js +2 -4
- package/lib/datasource/capability/validate-capability-slice.js +2 -1
- package/lib/datasource/datasource-identifier.js +2 -1
- package/lib/datasource/datasource-validate-display.js +1 -1
- package/lib/datasource/field-reference-validator.js +24 -3
- package/lib/datasource/orphan-profiles-validator.js +98 -0
- package/lib/datasource/validate.js +41 -23
- package/lib/external-system/download-helpers.js +87 -0
- package/lib/external-system/download.js +61 -122
- package/lib/external-system/generator.js +1 -59
- package/lib/external-system/test.js +10 -15
- package/lib/generator/builders.js +11 -1
- package/lib/generator/external-controller-manifest.js +5 -2
- package/lib/generator/split.js +3 -1
- package/lib/generator/wizard.js +1 -28
- package/lib/identity/fk-reference.js +65 -0
- package/lib/identity/identity-apply-core.js +13 -58
- package/lib/identity/identity-apply-phases.js +5 -1
- package/lib/identity/identity-display.js +243 -0
- package/lib/identity/identity-response-helpers.js +52 -0
- package/lib/identity/identity-sync-errors.js +62 -0
- package/lib/identity/resolve-user-id.js +129 -0
- package/lib/identity/username-default.js +31 -0
- package/lib/lifecycle/certification-progress.js +2 -2
- package/lib/lifecycle/report-display-trust.js +70 -0
- package/lib/lifecycle/report-display.js +14 -13
- package/lib/resolvers/datasource-resolver.js +2 -3
- package/lib/resolvers/resource-type-file.js +159 -0
- package/lib/schema/application-schema.json +16 -0
- package/lib/schema/deployment-rules.yaml +2 -1
- package/lib/schema/external-datasource.schema.json +372 -58
- package/lib/schema/external-system.schema.json +331 -2
- package/lib/schema/type/document-storage.json +9 -5
- package/lib/utils/app-run-containers.js +25 -2
- package/lib/utils/authentication-shape.js +224 -0
- package/lib/utils/build-copy.js +36 -5
- package/lib/utils/build-resolve-image.js +66 -12
- package/lib/utils/celery-companion-apps.js +53 -0
- package/lib/utils/cli-utils.js +4 -0
- package/lib/utils/compose-celery-worker.js +23 -0
- package/lib/utils/compose-generate-docker-compose.js +9 -1
- package/lib/utils/configuration-env-resolver.js +36 -0
- package/lib/utils/credential-secrets-env-kv.js +216 -0
- package/lib/utils/credential-secrets-env.js +52 -262
- package/lib/utils/dataplane-resolver.js +4 -115
- package/lib/utils/declarative-url-ports.js +24 -1
- package/lib/utils/docker-build.js +1 -4
- package/lib/utils/external-env-template.js +10 -3
- package/lib/utils/external-system-validators.js +8 -2
- package/lib/utils/help-builder.js +2 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +2 -1
- package/lib/utils/platform-kv-ref.js +57 -0
- package/lib/utils/runtime-configuration-download.js +189 -0
- package/lib/utils/runtime-configuration-values.js +119 -0
- package/lib/utils/schema-loader.js +19 -4
- package/lib/utils/worker-sidecars.js +142 -0
- package/lib/validation/external-manifest-validator.js +2 -0
- package/lib/validation/runtime-configuration-rules.js +98 -0
- package/lib/validation/validate-display-dimensions.js +154 -0
- package/lib/validation/validate-display-sections.js +276 -0
- package/lib/validation/validate-display-steps.js +67 -0
- package/lib/validation/validate-display.js +24 -402
- package/package.json +1 -1
- package/templates/applications/dataplane/application.yaml +5 -0
- package/templates/applications/dataplane/env.template +26 -13
- package/templates/applications/dataplane/rbac.yaml +108 -1
- package/templates/applications/miso-controller/application.yaml +2 -2
- package/templates/applications/miso-controller/env.template +37 -122
- package/templates/applications/miso-controller/rbac.yaml +28 -13
- package/templates/channels/chatgpt/install.template.md.hbs +49 -0
- package/templates/channels/chatgpt/manifest.template.json.hbs +9 -0
- package/templates/channels/microsoft-copilot/install.template.md.hbs +49 -0
- package/templates/channels/microsoft-copilot/manifest.template.json.hbs +8 -0
- package/templates/channels/slack/install.template.md.hbs +49 -0
- package/templates/channels/slack/manifest.template.json.hbs +66 -0
- package/templates/channels/teams-bot/install.template.md.hbs +49 -0
- package/templates/channels/teams-bot/manifest.template.json.hbs +13 -0
- package/templates/channels/web-embed/install.template.md.hbs +49 -0
- package/templates/channels/web-embed/manifest.template.json.hbs +8 -0
- package/templates/python/docker-compose.hbs +56 -0
- package/templates/typescript/docker-compose.hbs +52 -0
|
@@ -29,7 +29,12 @@ const { checkHealthEndpoint } = require('../utils/health-check');
|
|
|
29
29
|
const { validateControllerUrl } = require('../utils/auth-config-validator');
|
|
30
30
|
const app = require('../app');
|
|
31
31
|
const { assertDevInfraUp } = require('./dev-infra-gate');
|
|
32
|
-
const {
|
|
32
|
+
const { dataplaneDockerHostPort } = require('../utils/declarative-url-ports');
|
|
33
|
+
const {
|
|
34
|
+
ensureDataplaneAppsFromTemplate,
|
|
35
|
+
validateEnvOutputPathFolderOrNull,
|
|
36
|
+
refreshUrlsLocalRegistryForCurrentProject
|
|
37
|
+
} = require('./up-common');
|
|
33
38
|
|
|
34
39
|
const CONTROLLER_HEALTH_PATH = '/health';
|
|
35
40
|
|
|
@@ -198,8 +203,7 @@ function computeDataplanePortOverride(runEnvKey, developerIdNum) {
|
|
|
198
203
|
if (runEnvKey !== 'dev' && runEnvKey !== 'tst') {
|
|
199
204
|
return undefined;
|
|
200
205
|
}
|
|
201
|
-
|
|
202
|
-
return runEnvKey === 'dev' ? baseHostPort + 10 : baseHostPort + 20;
|
|
206
|
+
return dataplaneDockerHostPort(3001, developerIdNum, runEnvKey);
|
|
203
207
|
}
|
|
204
208
|
|
|
205
209
|
function assertDevEnvironmentForDataplane(cfg) {
|
|
@@ -243,7 +247,7 @@ async function handleUpDataplane(options = {}) {
|
|
|
243
247
|
: await resolveEnvironment();
|
|
244
248
|
const { controllerUrl, authConfig } = await resolveUpDataplaneAuthContext(options, environmentKey);
|
|
245
249
|
|
|
246
|
-
await
|
|
250
|
+
await ensureDataplaneAppsFromTemplate();
|
|
247
251
|
// If envOutputPath target folder does not exist, set envOutputPath to null
|
|
248
252
|
validateEnvOutputPathFolderOrNull('dataplane');
|
|
249
253
|
|
package/lib/commands/upload.js
CHANGED
|
@@ -32,6 +32,7 @@ const {
|
|
|
32
32
|
resolveConfigurationValues,
|
|
33
33
|
collectResolvedVariableConfigurationNames
|
|
34
34
|
} = require('../utils/configuration-env-resolver');
|
|
35
|
+
const { pushRuntimeConfigurationValues } = require('../utils/runtime-configuration-values');
|
|
35
36
|
const { validateExternalSystemComplete } = require('../validation/validate');
|
|
36
37
|
const { displayValidationResults } = require('../validation/validate-display');
|
|
37
38
|
const { generateControllerManifest } = require('../generator/external-controller-manifest');
|
|
@@ -219,6 +220,24 @@ async function pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey,
|
|
|
219
220
|
if (pushResult.warning) {
|
|
220
221
|
logger.log(chalk.yellow(`Warning: ${pushResult.warning}`));
|
|
221
222
|
}
|
|
223
|
+
try {
|
|
224
|
+
const configPush = await pushRuntimeConfigurationValues(
|
|
225
|
+
dataplaneUrl,
|
|
226
|
+
authConfig,
|
|
227
|
+
systemKey,
|
|
228
|
+
payload
|
|
229
|
+
);
|
|
230
|
+
if (configPush.pushed > 0) {
|
|
231
|
+
const nameList = configPush.names.length ? ` (${configPush.names.join(', ')})` : '';
|
|
232
|
+
logger.log(
|
|
233
|
+
formatSuccessLine(
|
|
234
|
+
`Stored ${configPush.pushed} runtime configuration value(s) in dataplane${nameList}.`
|
|
235
|
+
)
|
|
236
|
+
);
|
|
237
|
+
}
|
|
238
|
+
} catch (err) {
|
|
239
|
+
logger.log(chalk.yellow(`Warning: runtime configuration store skipped: ${err.message}`));
|
|
240
|
+
}
|
|
222
241
|
}
|
|
223
242
|
|
|
224
243
|
/**
|
|
@@ -314,7 +333,7 @@ async function buildValidatedUploadManifestPayload(systemKey, opts = {}) {
|
|
|
314
333
|
* @param {Object} manifest
|
|
315
334
|
* @returns {Promise<void>}
|
|
316
335
|
*/
|
|
317
|
-
async function logAndSyncLocalOpenApiForUpload(systemKey, manifest) {
|
|
336
|
+
async function logAndSyncLocalOpenApiForUpload(systemKey, manifest, uploadContext = {}) {
|
|
318
337
|
const appPath = getIntegrationPath(systemKey);
|
|
319
338
|
const ei = manifest && manifest.externalIntegration;
|
|
320
339
|
const datasourceFiles = ei && Array.isArray(ei.dataSources) ? ei.dataSources : [];
|
|
@@ -323,7 +342,9 @@ async function logAndSyncLocalOpenApiForUpload(systemKey, manifest) {
|
|
|
323
342
|
dryRun: false,
|
|
324
343
|
appPath,
|
|
325
344
|
systemKey,
|
|
326
|
-
datasourceFiles
|
|
345
|
+
datasourceFiles,
|
|
346
|
+
dataplaneUrl: uploadContext.dataplaneUrl,
|
|
347
|
+
authConfig: uploadContext.authConfig
|
|
327
348
|
});
|
|
328
349
|
for (const line of openapiSyncLines) {
|
|
329
350
|
logger.log(line.startsWith('Skipped') ? formatWarningLine(line) : formatSuccessLine(line));
|
|
@@ -372,7 +393,7 @@ async function runUploadPublishAndSummary(systemKey, options, manifest, payload)
|
|
|
372
393
|
await pushAndLogCredentialSecrets(dataplaneUrl, authConfig, systemKey, payload, {
|
|
373
394
|
json: options.json === true
|
|
374
395
|
});
|
|
375
|
-
await logAndSyncLocalOpenApiForUpload(systemKey, manifest);
|
|
396
|
+
await logAndSyncLocalOpenApiForUpload(systemKey, manifest, { dataplaneUrl, authConfig });
|
|
376
397
|
await handlePublicationAndFollowups(
|
|
377
398
|
{
|
|
378
399
|
systemKey,
|
|
@@ -39,7 +39,10 @@ async function runVerifyTrustCommandAction(appName, options, cmd) {
|
|
|
39
39
|
systemKey: result.systemKey,
|
|
40
40
|
command: result.command,
|
|
41
41
|
verdict: result.verdict,
|
|
42
|
-
|
|
42
|
+
aiTrustPercent: result.aiTrustPercent,
|
|
43
|
+
accessConfidencePercent: result.accessConfidencePercent,
|
|
44
|
+
businessConfidencePercent: result.businessConfidencePercent,
|
|
45
|
+
findings: result.findings,
|
|
43
46
|
datasourceRows: opts.details ? result.datasourceRows : undefined
|
|
44
47
|
},
|
|
45
48
|
opts.details || opts.verbose
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @fileoverview verify-trust orchestration with
|
|
2
|
+
* @fileoverview verify-trust orchestration with dual-confidence report (433.0).
|
|
3
3
|
* @author AI Fabrix Team
|
|
4
|
-
* @version
|
|
4
|
+
* @version 2.0.0
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
9
|
const { runTestTrustForExternalSystem } = require('./test-trust-external');
|
|
10
|
-
const {
|
|
11
|
-
VERDICT,
|
|
12
|
-
verdictFromPassed,
|
|
13
|
-
worstConfidencePercent
|
|
14
|
-
} = require('../lifecycle/product-model');
|
|
10
|
+
const { VERDICT, verdictFromPassed } = require('../lifecycle/product-model');
|
|
15
11
|
|
|
16
12
|
/**
|
|
17
13
|
* @param {Array<Object>} rows
|
|
@@ -20,14 +16,12 @@ const {
|
|
|
20
16
|
function mapTrustDatasourceRows(rows) {
|
|
21
17
|
return (rows || []).map(row => {
|
|
22
18
|
const tr = row.trustRun;
|
|
23
|
-
const confidencePercent =
|
|
24
|
-
tr && typeof tr.confidence === 'number' ? Math.round(tr.confidence * 100) : null;
|
|
25
19
|
const verdict = row.success ? VERDICT.VERIFIED : VERDICT.FAILED;
|
|
26
20
|
return {
|
|
27
21
|
datasourceKey: row.key,
|
|
28
22
|
verdict,
|
|
29
|
-
confidencePercent,
|
|
30
23
|
trustDecision: tr?.trustDecision,
|
|
24
|
+
validationStatus: tr?.validationStatus,
|
|
31
25
|
error: row.error
|
|
32
26
|
};
|
|
33
27
|
});
|
|
@@ -40,22 +34,20 @@ function mapTrustDatasourceRows(rows) {
|
|
|
40
34
|
* @returns {Promise<Object>}
|
|
41
35
|
*/
|
|
42
36
|
async function runVerifyTrustForExternalSystem(systemKey, options = {}) {
|
|
43
|
-
const { success, results, systemKey: resolvedKey } =
|
|
44
|
-
systemKey,
|
|
45
|
-
options
|
|
46
|
-
);
|
|
37
|
+
const { success, results, systemKey: resolvedKey, trustReport } =
|
|
38
|
+
await runTestTrustForExternalSystem(systemKey, options);
|
|
47
39
|
const datasourceRows = mapTrustDatasourceRows(results);
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
.filter(v => v !== null);
|
|
51
|
-
const businessContextConfidencePercent = worstConfidencePercent(confidences);
|
|
52
|
-
const verdict = verdictFromPassed(success);
|
|
40
|
+
const report = trustReport || {};
|
|
41
|
+
const verdict = report.verdict ? report.verdict : verdictFromPassed(success);
|
|
53
42
|
|
|
54
43
|
return {
|
|
55
44
|
systemKey: resolvedKey || systemKey,
|
|
56
45
|
command: 'verify-trust',
|
|
57
46
|
verdict,
|
|
58
|
-
|
|
47
|
+
aiTrustPercent: report.aiTrustPercent ?? null,
|
|
48
|
+
accessConfidencePercent: report.accessConfidencePercent ?? null,
|
|
49
|
+
businessConfidencePercent: report.businessConfidencePercent ?? null,
|
|
50
|
+
findings: Array.isArray(report.findings) ? report.findings : [],
|
|
59
51
|
datasourceRows,
|
|
60
52
|
results
|
|
61
53
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `setupPlatformMode` field in `config.yaml` (`single` | `full`).
|
|
2
|
+
* `setupPlatformMode` field in `config.yaml` (`single` | `single-traefik` | `full`).
|
|
3
3
|
*
|
|
4
4
|
* @fileoverview Persists setup wizard platform mode
|
|
5
5
|
* @author AI Fabrix Team
|
|
@@ -15,7 +15,7 @@ const {
|
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* @param {() => Promise<Object>} getConfig
|
|
18
|
-
* @returns {Promise<'single'|'full'>}
|
|
18
|
+
* @returns {Promise<'single'|'single-traefik'|'full'>}
|
|
19
19
|
*/
|
|
20
20
|
async function getSetupPlatformModeFromConfig(getConfig) {
|
|
21
21
|
const cfg = await getConfig();
|
|
@@ -29,7 +29,7 @@ async function getSetupPlatformModeFromConfig(getConfig) {
|
|
|
29
29
|
* @param {() => Promise<Object>} getConfig
|
|
30
30
|
* @param {(data: Object) => Promise<void>} saveConfig
|
|
31
31
|
* @param {unknown} mode
|
|
32
|
-
* @returns {Promise<'single'|'full'>}
|
|
32
|
+
* @returns {Promise<'single'|'single-traefik'|'full'>}
|
|
33
33
|
*/
|
|
34
34
|
async function setSetupPlatformModeInConfig(getConfig, saveConfig, mode) {
|
|
35
35
|
const normalized = normalizeSetupPlatformMode(mode);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Setup platform topology mode (`single` | `full`).
|
|
2
|
+
* Setup platform topology mode (`single` | `single-traefik` | `full`).
|
|
3
3
|
*
|
|
4
4
|
* This is distinct from `setupInstallationProfile` (dev/pro password bundle) and from
|
|
5
5
|
* the login/run environment (`dev` | `tst` | `pro`).
|
|
@@ -14,12 +14,20 @@
|
|
|
14
14
|
/** @enum {string} */
|
|
15
15
|
const SETUP_PLATFORM_MODE = Object.freeze({
|
|
16
16
|
SINGLE: 'single',
|
|
17
|
+
SINGLE_TRAEFIK: 'single-traefik',
|
|
17
18
|
FULL: 'full'
|
|
18
19
|
});
|
|
19
20
|
|
|
21
|
+
/** @type {readonly string[]} */
|
|
22
|
+
const SETUP_PLATFORM_MODE_CLI_VALUES = Object.freeze([
|
|
23
|
+
SETUP_PLATFORM_MODE.SINGLE,
|
|
24
|
+
SETUP_PLATFORM_MODE.SINGLE_TRAEFIK,
|
|
25
|
+
SETUP_PLATFORM_MODE.FULL
|
|
26
|
+
]);
|
|
27
|
+
|
|
20
28
|
/**
|
|
21
29
|
* @param {unknown} value
|
|
22
|
-
* @returns {'single'|'full'}
|
|
30
|
+
* @returns {'single'|'single-traefik'|'full'}
|
|
23
31
|
*/
|
|
24
32
|
function normalizeSetupPlatformMode(value) {
|
|
25
33
|
const raw = String(value ?? '')
|
|
@@ -27,6 +35,8 @@ function normalizeSetupPlatformMode(value) {
|
|
|
27
35
|
.toLowerCase();
|
|
28
36
|
if (raw === SETUP_PLATFORM_MODE.FULL) return SETUP_PLATFORM_MODE.FULL;
|
|
29
37
|
if (raw === 'all' || raw === 'full-platform' || raw === 'platform-full') return SETUP_PLATFORM_MODE.FULL;
|
|
38
|
+
if (raw === SETUP_PLATFORM_MODE.SINGLE_TRAEFIK) return SETUP_PLATFORM_MODE.SINGLE_TRAEFIK;
|
|
39
|
+
if (raw === 'ingress' || raw === 'single-ingress' || raw === 'traefik') return SETUP_PLATFORM_MODE.SINGLE_TRAEFIK;
|
|
30
40
|
return SETUP_PLATFORM_MODE.SINGLE;
|
|
31
41
|
}
|
|
32
42
|
|
|
@@ -34,22 +44,47 @@ function normalizeSetupPlatformMode(value) {
|
|
|
34
44
|
* Derived config flags for a chosen platform mode.
|
|
35
45
|
*
|
|
36
46
|
* - single: direct ports, no front door ingress
|
|
37
|
-
* -
|
|
47
|
+
* - single-traefik: Traefik front door (domain + TLS) for one environment only
|
|
48
|
+
* - full: Traefik ingress + env-scoped resources (multi-env; CLI only until menu returns)
|
|
38
49
|
*
|
|
39
|
-
* @param {'single'|'full'} mode
|
|
50
|
+
* @param {'single'|'single-traefik'|'full'} mode
|
|
40
51
|
* @returns {{ traefik: boolean, useEnvironmentScopedResources: boolean }}
|
|
41
52
|
*/
|
|
42
53
|
function flagsForSetupPlatformMode(mode) {
|
|
43
54
|
const m = normalizeSetupPlatformMode(mode);
|
|
55
|
+
const traefik =
|
|
56
|
+
m === SETUP_PLATFORM_MODE.SINGLE_TRAEFIK || m === SETUP_PLATFORM_MODE.FULL;
|
|
44
57
|
return {
|
|
45
|
-
traefik
|
|
58
|
+
traefik,
|
|
46
59
|
useEnvironmentScopedResources: m === SETUP_PLATFORM_MODE.FULL
|
|
47
60
|
};
|
|
48
61
|
}
|
|
49
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Interactive setup menu choices (full platform hidden until multi-env path ships).
|
|
65
|
+
*
|
|
66
|
+
* @returns {{ name: string, value: string }[]}
|
|
67
|
+
*/
|
|
68
|
+
function getSetupPlatformModePromptChoices() {
|
|
69
|
+
return [
|
|
70
|
+
{
|
|
71
|
+
name: 'Single environment — direct ports (no Traefik front door)',
|
|
72
|
+
value: SETUP_PLATFORM_MODE.SINGLE
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
name: 'Single environment — Traefik front door (domain + TLS)',
|
|
76
|
+
value: SETUP_PLATFORM_MODE.SINGLE_TRAEFIK
|
|
77
|
+
}
|
|
78
|
+
// Full platform — Traefik front door + miso/dev/tst/pro (shared infra) — menu returns soon.
|
|
79
|
+
// { name: 'Full platform — Traefik front door + miso/dev/tst/pro (shared infra)', value: SETUP_PLATFORM_MODE.FULL },
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
|
|
50
83
|
module.exports = {
|
|
51
84
|
SETUP_PLATFORM_MODE,
|
|
85
|
+
SETUP_PLATFORM_MODE_CLI_VALUES,
|
|
52
86
|
normalizeSetupPlatformMode,
|
|
53
|
-
flagsForSetupPlatformMode
|
|
87
|
+
flagsForSetupPlatformMode,
|
|
88
|
+
getSetupPlatformModePromptChoices
|
|
54
89
|
};
|
|
55
90
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { deepClone } = require('./copy-operations');
|
|
10
|
+
const { capabilitiesIncludes } = require('./capability-manifest');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* @param {object} doc - Parsed datasource JSON
|
|
@@ -16,8 +17,7 @@ const { deepClone } = require('./copy-operations');
|
|
|
16
17
|
*/
|
|
17
18
|
function extractCapabilitySliceForDiff(doc, capabilityKey, profileKey) {
|
|
18
19
|
const cap = capabilityKey;
|
|
19
|
-
const listed =
|
|
20
|
-
Boolean(Array.isArray(doc.capabilities) && doc.capabilities.includes(cap));
|
|
20
|
+
const listed = capabilitiesIncludes(doc.capabilities, cap);
|
|
21
21
|
const openapiOp = doc.openapi?.operations?.[cap];
|
|
22
22
|
const cipOp = doc.execution?.cip?.operations?.[cap];
|
|
23
23
|
let exposedProfile;
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* COM v2 capability object helpers for datasource manifests.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview capability-manifest
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const FORBIDDEN_ROOT_KEYS = new Set([
|
|
12
|
+
'context',
|
|
13
|
+
'origin',
|
|
14
|
+
'generatedBy',
|
|
15
|
+
'composition',
|
|
16
|
+
'generation',
|
|
17
|
+
'enterpriseResolver'
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const DEFAULT_RISK_BY_KEY = {
|
|
21
|
+
list: 'low',
|
|
22
|
+
get: 'low',
|
|
23
|
+
search: 'low',
|
|
24
|
+
create: 'medium',
|
|
25
|
+
update: 'medium',
|
|
26
|
+
delete: 'high'
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const RESOURCE_TYPE_MAP = {
|
|
30
|
+
conversation: 'message',
|
|
31
|
+
user: 'employee',
|
|
32
|
+
person: 'employee',
|
|
33
|
+
record: 'document',
|
|
34
|
+
folder: 'document',
|
|
35
|
+
country: 'organization',
|
|
36
|
+
report: 'document',
|
|
37
|
+
calendar: 'event',
|
|
38
|
+
subscription: 'event'
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* @param {unknown} entry
|
|
43
|
+
* @returns {string}
|
|
44
|
+
*/
|
|
45
|
+
function capabilityKeyFromEntry(entry) {
|
|
46
|
+
if (typeof entry === 'string' && entry.trim()) {
|
|
47
|
+
return entry.trim();
|
|
48
|
+
}
|
|
49
|
+
if (entry && typeof entry === 'object' && typeof entry.key === 'string' && entry.key.trim()) {
|
|
50
|
+
return entry.key.trim();
|
|
51
|
+
}
|
|
52
|
+
return '';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @param {unknown} capabilities
|
|
57
|
+
* @returns {string[]}
|
|
58
|
+
*/
|
|
59
|
+
function listCapabilityKeys(capabilities) {
|
|
60
|
+
if (!Array.isArray(capabilities)) {
|
|
61
|
+
return [];
|
|
62
|
+
}
|
|
63
|
+
return capabilities.map(capabilityKeyFromEntry).filter(Boolean);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {unknown} capabilities
|
|
68
|
+
* @param {string} key
|
|
69
|
+
* @returns {boolean}
|
|
70
|
+
*/
|
|
71
|
+
function capabilitiesIncludes(capabilities, key) {
|
|
72
|
+
const target = String(key).toLowerCase();
|
|
73
|
+
return listCapabilityKeys(capabilities).some((item) => item.toLowerCase() === target);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {string} key
|
|
78
|
+
* @param {string} [displayName]
|
|
79
|
+
* @returns {object}
|
|
80
|
+
*/
|
|
81
|
+
function buildCapabilityObject(key, displayName) {
|
|
82
|
+
const normalized = String(key || '').trim();
|
|
83
|
+
const label = displayName && String(displayName).trim() ? String(displayName).trim() : 'records';
|
|
84
|
+
return {
|
|
85
|
+
key: normalized,
|
|
86
|
+
description: `${normalized} operation on ${label}`,
|
|
87
|
+
riskLevel: DEFAULT_RISK_BY_KEY[normalized.toLowerCase()] || 'medium',
|
|
88
|
+
approvalRequired: false
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @param {object} parsed
|
|
94
|
+
* @returns {object[]}
|
|
95
|
+
*/
|
|
96
|
+
function normalizeCapabilitiesToObjects(parsed) {
|
|
97
|
+
const caps = parsed?.capabilities;
|
|
98
|
+
const displayName = parsed?.displayName || parsed?.key || 'records';
|
|
99
|
+
if (!Array.isArray(caps) || caps.length === 0) {
|
|
100
|
+
return [];
|
|
101
|
+
}
|
|
102
|
+
const out = [];
|
|
103
|
+
const seen = new Set();
|
|
104
|
+
caps.forEach((item) => {
|
|
105
|
+
if (typeof item === 'string' && item.trim()) {
|
|
106
|
+
const key = item.trim();
|
|
107
|
+
if (seen.has(key)) return;
|
|
108
|
+
seen.add(key);
|
|
109
|
+
out.push(buildCapabilityObject(key, displayName));
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
if (!item || typeof item !== 'object') return;
|
|
113
|
+
const key = capabilityKeyFromEntry(item);
|
|
114
|
+
if (!key || seen.has(key)) return;
|
|
115
|
+
seen.add(key);
|
|
116
|
+
const row = buildCapabilityObject(key, displayName);
|
|
117
|
+
if (typeof item.description === 'string' && item.description.trim()) {
|
|
118
|
+
row.description = item.description.trim();
|
|
119
|
+
}
|
|
120
|
+
if (typeof item.riskLevel === 'string' && item.riskLevel.trim()) {
|
|
121
|
+
row.riskLevel = item.riskLevel.trim();
|
|
122
|
+
}
|
|
123
|
+
if (item.approvalRequired === true) {
|
|
124
|
+
row.approvalRequired = true;
|
|
125
|
+
}
|
|
126
|
+
out.push(row);
|
|
127
|
+
});
|
|
128
|
+
return out;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {object} node
|
|
133
|
+
* @returns {void}
|
|
134
|
+
*/
|
|
135
|
+
function stripSemanticExtras(node) {
|
|
136
|
+
if (!node || typeof node !== 'object') return;
|
|
137
|
+
const semantic = node.semantic;
|
|
138
|
+
if (semantic && typeof semantic === 'object') {
|
|
139
|
+
delete semantic.categories;
|
|
140
|
+
delete semantic.synonyms;
|
|
141
|
+
if (Object.keys(semantic).length === 0) {
|
|
142
|
+
delete node.semantic;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
Object.values(node).forEach((value) => {
|
|
146
|
+
if (value && typeof value === 'object') {
|
|
147
|
+
if (Array.isArray(value)) {
|
|
148
|
+
value.forEach((item) => stripSemanticExtras(item));
|
|
149
|
+
} else {
|
|
150
|
+
stripSemanticExtras(value);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* @param {object} parsed
|
|
158
|
+
* @param {string[]} changes
|
|
159
|
+
* @returns {boolean}
|
|
160
|
+
*/
|
|
161
|
+
function removeForbiddenComRootKeys(parsed, changes) {
|
|
162
|
+
let updated = false;
|
|
163
|
+
FORBIDDEN_ROOT_KEYS.forEach((key) => {
|
|
164
|
+
if (Object.prototype.hasOwnProperty.call(parsed, key)) {
|
|
165
|
+
delete parsed[key];
|
|
166
|
+
changes.push(`Removed forbidden COM v2 root key: ${key}`);
|
|
167
|
+
updated = true;
|
|
168
|
+
}
|
|
169
|
+
});
|
|
170
|
+
return updated;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* @param {object} parsed
|
|
175
|
+
* @param {string[]} changes
|
|
176
|
+
* @returns {boolean}
|
|
177
|
+
*/
|
|
178
|
+
function stripFieldMappingSemanticExtras(parsed, changes) {
|
|
179
|
+
if (!parsed.fieldMappings) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
const before = JSON.stringify(parsed.fieldMappings);
|
|
183
|
+
stripSemanticExtras(parsed.fieldMappings);
|
|
184
|
+
if (JSON.stringify(parsed.fieldMappings) === before) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
changes.push('Removed fieldMappings.*.semantic.categories/synonyms (COM v2)');
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* @param {object} parsed
|
|
193
|
+
* @param {string[]} changes
|
|
194
|
+
* @returns {boolean}
|
|
195
|
+
*/
|
|
196
|
+
function applyResourceTypeCatalogMap(parsed, changes) {
|
|
197
|
+
const resourceType = parsed.resourceType;
|
|
198
|
+
if (typeof resourceType !== 'string') {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
const mapped = RESOURCE_TYPE_MAP[resourceType.trim()];
|
|
202
|
+
if (!mapped) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
parsed.resourceType = mapped;
|
|
206
|
+
changes.push(`Mapped resourceType ${resourceType} → ${mapped}`);
|
|
207
|
+
return true;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* @param {object} parsed
|
|
212
|
+
* @param {string[]} changes
|
|
213
|
+
* @returns {boolean}
|
|
214
|
+
*/
|
|
215
|
+
function migrateCapabilitiesToComObjects(parsed, changes) {
|
|
216
|
+
const caps = parsed.capabilities;
|
|
217
|
+
const needsObjectMigration = Array.isArray(caps)
|
|
218
|
+
&& caps.some((item) => typeof item === 'string' || (item && typeof item === 'object' && !item.key));
|
|
219
|
+
const hasStringCapabilities = Array.isArray(caps) && caps.length > 0 && typeof caps[0] === 'string';
|
|
220
|
+
if (!needsObjectMigration && !hasStringCapabilities) {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
parsed.capabilities = normalizeCapabilitiesToObjects(parsed);
|
|
224
|
+
changes.push('Migrated capabilities[] to COM v2 capability objects');
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @param {object} parsed
|
|
230
|
+
* @param {string[]} changes
|
|
231
|
+
* @returns {boolean}
|
|
232
|
+
*/
|
|
233
|
+
function repairComV2Manifest(parsed, changes) {
|
|
234
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
235
|
+
return false;
|
|
236
|
+
}
|
|
237
|
+
return [
|
|
238
|
+
removeForbiddenComRootKeys(parsed, changes),
|
|
239
|
+
stripFieldMappingSemanticExtras(parsed, changes),
|
|
240
|
+
applyResourceTypeCatalogMap(parsed, changes),
|
|
241
|
+
migrateCapabilitiesToComObjects(parsed, changes)
|
|
242
|
+
].some(Boolean);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
module.exports = {
|
|
246
|
+
FORBIDDEN_ROOT_KEYS,
|
|
247
|
+
capabilityKeyFromEntry,
|
|
248
|
+
listCapabilityKeys,
|
|
249
|
+
capabilitiesIncludes,
|
|
250
|
+
buildCapabilityObject,
|
|
251
|
+
normalizeCapabilitiesToObjects,
|
|
252
|
+
stripSemanticExtras,
|
|
253
|
+
repairComV2Manifest
|
|
254
|
+
};
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
+
const { capabilitiesIncludes } = require('./capability-manifest');
|
|
10
|
+
|
|
9
11
|
/**
|
|
10
12
|
* @param {object|undefined} operations
|
|
11
13
|
* @param {string} logicalKey
|
|
@@ -146,10 +148,7 @@ function resolveProfileKeyForLogical(doc, logicalKey) {
|
|
|
146
148
|
* @returns {boolean}
|
|
147
149
|
*/
|
|
148
150
|
function capabilityLogicalExists(doc, name) {
|
|
149
|
-
if (
|
|
150
|
-
Array.isArray(doc.capabilities) &&
|
|
151
|
-
doc.capabilities.some((c) => String(c).toLowerCase() === String(name).toLowerCase())
|
|
152
|
-
) {
|
|
151
|
+
if (capabilitiesIncludes(doc.capabilities, name)) {
|
|
153
152
|
return true;
|
|
154
153
|
}
|
|
155
154
|
if (findMatchingOpsKeys(doc.openapi?.operations, name).length > 0) {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { rewriteCapabilityReferences } = require('./reference-rewrite');
|
|
10
|
+
const { capabilityKeyFromEntry } = require('./capability-manifest');
|
|
10
11
|
const { jsonPointerPath } = require('./json-pointer');
|
|
11
12
|
const { buildBasicExposureProfileArray } = require('./basic-exposure');
|
|
12
13
|
const {
|
|
@@ -53,9 +54,10 @@ function removeCapability(doc, logicalKey) {
|
|
|
53
54
|
const profileKey = resolveProfileKeyForLogical(doc, logicalKey);
|
|
54
55
|
|
|
55
56
|
if (Array.isArray(doc.capabilities)) {
|
|
56
|
-
doc.capabilities = doc.capabilities.filter(
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
doc.capabilities = doc.capabilities.filter((c) => {
|
|
58
|
+
const key = capabilityKeyFromEntry(c);
|
|
59
|
+
return key.toLowerCase() !== String(logicalKey).toLowerCase();
|
|
60
|
+
});
|
|
59
61
|
}
|
|
60
62
|
if (openapiKey && oo) {
|
|
61
63
|
delete oo[openapiKey];
|
|
@@ -17,6 +17,7 @@ const {
|
|
|
17
17
|
findMatchingOpsKeys,
|
|
18
18
|
resolveProfileKeyForLogical
|
|
19
19
|
} = require('./capability-resolve');
|
|
20
|
+
const { capabilityKeyFromEntry } = require('./capability-manifest');
|
|
20
21
|
|
|
21
22
|
/**
|
|
22
23
|
* @param {unknown} capabilities
|
|
@@ -28,7 +29,7 @@ function findCapabilityIndex(capabilities, logicalName) {
|
|
|
28
29
|
return -1;
|
|
29
30
|
}
|
|
30
31
|
return capabilities.findIndex(
|
|
31
|
-
(c) =>
|
|
32
|
+
(c) => capabilityKeyFromEntry(c).toLowerCase() === String(logicalName).toLowerCase()
|
|
32
33
|
);
|
|
33
34
|
}
|
|
34
35
|
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
const fs = require('node:fs');
|
|
10
10
|
const path = require('path');
|
|
11
|
+
const { loadConfigFile, writeConfigFile } = require('../../utils/config-format');
|
|
11
12
|
const { writeBackup } = require('../../utils/integration-file-backup');
|
|
12
13
|
const {
|
|
13
14
|
resolveValidateInputPath,
|
|
@@ -46,6 +47,33 @@ function resolveCapabilityCopyInputPath(identifier) {
|
|
|
46
47
|
return resolveValidateInputPath(trimmed);
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
/**
|
|
51
|
+
* Read a datasource config file (.json, .yaml, or .yml).
|
|
52
|
+
*
|
|
53
|
+
* @param {string} filePath
|
|
54
|
+
* @returns {object}
|
|
55
|
+
*/
|
|
56
|
+
function readDatasourceConfigFile(filePath) {
|
|
57
|
+
return loadConfigFile(filePath);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* @param {string} filePath
|
|
62
|
+
* @returns {'json'|'yaml'}
|
|
63
|
+
*/
|
|
64
|
+
function inferDatasourceConfigFormat(filePath) {
|
|
65
|
+
const ext = path.extname(filePath).toLowerCase();
|
|
66
|
+
if (ext === '.json') {
|
|
67
|
+
return 'json';
|
|
68
|
+
}
|
|
69
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
70
|
+
return 'yaml';
|
|
71
|
+
}
|
|
72
|
+
throw new Error(
|
|
73
|
+
`Unsupported datasource config extension: ${ext || '(none)'}. Use .json, .yaml, or .yml`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
49
77
|
/**
|
|
50
78
|
* @param {string} filePath
|
|
51
79
|
* @param {object} obj
|
|
@@ -53,9 +81,9 @@ function resolveCapabilityCopyInputPath(identifier) {
|
|
|
53
81
|
*/
|
|
54
82
|
function atomicWriteJson(filePath, obj) {
|
|
55
83
|
const dir = path.dirname(filePath);
|
|
84
|
+
const format = inferDatasourceConfigFormat(filePath);
|
|
56
85
|
const tmp = path.join(dir, `.${path.basename(filePath)}.${process.pid}.tmp`);
|
|
57
|
-
|
|
58
|
-
fs.writeFileSync(tmp, payload, 'utf8');
|
|
86
|
+
writeConfigFile(tmp, obj, format);
|
|
59
87
|
fs.renameSync(tmp, filePath);
|
|
60
88
|
}
|
|
61
89
|
|
|
@@ -89,8 +117,7 @@ function atomicWriteJson(filePath, obj) {
|
|
|
89
117
|
*/
|
|
90
118
|
async function runCapabilityCopy(opts) {
|
|
91
119
|
const resolvedPath = resolveCapabilityCopyInputPath(opts.fileOrKey.trim());
|
|
92
|
-
const
|
|
93
|
-
const parsed = JSON.parse(raw);
|
|
120
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
94
121
|
|
|
95
122
|
const to = normalizeCapabilityKey(opts.as, 'Target (--as)');
|
|
96
123
|
const fromRaw = opts.from !== undefined && opts.from !== null ? String(opts.from).trim() : '';
|
|
@@ -148,5 +175,6 @@ async function runCapabilityCopy(opts) {
|
|
|
148
175
|
module.exports = {
|
|
149
176
|
runCapabilityCopy,
|
|
150
177
|
writeBackup,
|
|
178
|
+
readDatasourceConfigFile,
|
|
151
179
|
atomicWriteJson
|
|
152
180
|
};
|