@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
package/lib/utils/paths.js
CHANGED
|
@@ -315,6 +315,30 @@ function getDevDirectory(appName, developerId) {
|
|
|
315
315
|
return baseDir;
|
|
316
316
|
}
|
|
317
317
|
|
|
318
|
+
/**
|
|
319
|
+
* Target directory for `aifabrix create` — always under {@link process.cwd} (`builder/` or
|
|
320
|
+
* `integration/`) even when those folders do not exist yet. Platform system apps still
|
|
321
|
+
* materialize under {@link getAppsMaterializationParent}.
|
|
322
|
+
*
|
|
323
|
+
* Post-create lookup uses {@link getAppPath} / {@link getBuilderPath} / {@link getIntegrationPath}.
|
|
324
|
+
*
|
|
325
|
+
* @param {string} appName - Application name
|
|
326
|
+
* @param {string} [appType] - Application type (`external` or other)
|
|
327
|
+
* @returns {string} Absolute path to the new application directory
|
|
328
|
+
*/
|
|
329
|
+
function getAppCreatePath(appName, appType) {
|
|
330
|
+
if (!appName || typeof appName !== 'string') {
|
|
331
|
+
throw new Error('App name is required and must be a string');
|
|
332
|
+
}
|
|
333
|
+
if (appType === 'external') {
|
|
334
|
+
return path.join(path.resolve(process.cwd()), 'integration', appName);
|
|
335
|
+
}
|
|
336
|
+
if (isSystemBuilderAppName(appName)) {
|
|
337
|
+
return path.join(getAppsMaterializationParent(), 'builder', appName);
|
|
338
|
+
}
|
|
339
|
+
return path.join(path.resolve(process.cwd()), 'builder', appName);
|
|
340
|
+
}
|
|
341
|
+
|
|
318
342
|
/**
|
|
319
343
|
* Gets the application path (builder or integration folder).
|
|
320
344
|
* Matches {@link getBuilderPath} / {@link getIntegrationPath} (cwd `integration/` / `builder/`, then
|
|
@@ -881,6 +905,7 @@ module.exports = {
|
|
|
881
905
|
getApplicationsBaseDir,
|
|
882
906
|
getDevDirectory,
|
|
883
907
|
getAppPath,
|
|
908
|
+
getAppCreatePath,
|
|
884
909
|
getAppsMaterializationParent,
|
|
885
910
|
getCwdIntegrationRoot,
|
|
886
911
|
getCwdBuilderRoot,
|
|
@@ -18,6 +18,7 @@ const { loadConfigFile } = require('./config-format');
|
|
|
18
18
|
const { computePublicUrlBaseString } = require('./url-declarative-public-base');
|
|
19
19
|
const { joinUrlPath, normalizeFrontDoorPatternForHealth } = require('./health-check-url');
|
|
20
20
|
const { getDevPorts } = require('./dev-config');
|
|
21
|
+
const { flagsForSetupPlatformMode } = require('../core/setup-platform-mode');
|
|
21
22
|
|
|
22
23
|
const MISO_CONTROLLER_APP = 'miso-controller';
|
|
23
24
|
|
|
@@ -74,7 +75,7 @@ function loadAppVariables(appName) {
|
|
|
74
75
|
|
|
75
76
|
function computeLocalFullPlatformFrontDoorUrl(params) {
|
|
76
77
|
const { setupPlatformMode, remoteServer, developerIdNum, frontDoorRouting } = params;
|
|
77
|
-
if (setupPlatformMode
|
|
78
|
+
if (!flagsForSetupPlatformMode(setupPlatformMode).traefik) {
|
|
78
79
|
return null;
|
|
79
80
|
}
|
|
80
81
|
if (remoteServer && String(remoteServer).trim()) {
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform installation kv:// refs from infra.parameter.yaml (flat keys, no path segments).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Distinguish platform catalog secrets from per-integration path-style kv refs
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const { getInfraParameterCatalog } = require('../parameters/infra-parameter-catalog');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Returns the single-segment path after kv:// when the ref has no slashes.
|
|
15
|
+
*
|
|
16
|
+
* @param {string} val - kv:// reference
|
|
17
|
+
* @returns {string|null}
|
|
18
|
+
*/
|
|
19
|
+
function kvRefSegment(val) {
|
|
20
|
+
if (typeof val !== 'string' || !val.trim().toLowerCase().startsWith('kv://')) return null;
|
|
21
|
+
const after = val.trim().slice(5);
|
|
22
|
+
if (!after || after.includes('/')) return null;
|
|
23
|
+
return after;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* True when val is kv://<key> and key exists in shipped infra.parameter.yaml.
|
|
28
|
+
*
|
|
29
|
+
* @param {string} val - kv:// reference
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
function isPlatformCatalogKvRef(val) {
|
|
33
|
+
const segment = kvRefSegment(val);
|
|
34
|
+
if (!segment) return false;
|
|
35
|
+
try {
|
|
36
|
+
const catalog = getInfraParameterCatalog();
|
|
37
|
+
return Boolean(catalog.findEntryForKey(segment));
|
|
38
|
+
} catch {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* True when repair should normalize a kv value to path-style kv://systemKey/variable.
|
|
45
|
+
* Platform catalog refs (e.g. kv://secrets-openaiApiKeyVault) are never legacy.
|
|
46
|
+
*
|
|
47
|
+
* @param {string} val - Value from authentication.security or configuration
|
|
48
|
+
* @returns {boolean}
|
|
49
|
+
*/
|
|
50
|
+
function isLegacyKvValue(val) {
|
|
51
|
+
if (typeof val !== 'string' || !val.trim().toLowerCase().startsWith('kv://')) return false;
|
|
52
|
+
if (isPlatformCatalogKvRef(val)) return false;
|
|
53
|
+
const after = val.trim().slice(5);
|
|
54
|
+
return after.includes('KeyVault') || !after.includes('/');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
module.exports = { kvRefSegment, isPlatformCatalogKvRef, isLegacyKvValue };
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync runtime configuration_values from dataplane on download (values → env.template; manifest → placeholders).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Download-time runtime configuration sync
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const fs = require('fs');
|
|
10
|
+
const fsPromises = require('fs').promises;
|
|
11
|
+
const path = require('path');
|
|
12
|
+
const yaml = require('js-yaml');
|
|
13
|
+
|
|
14
|
+
const {
|
|
15
|
+
getExternalSystemConfigurationResolved,
|
|
16
|
+
getExternalDataSourceConfigurationResolved
|
|
17
|
+
} = require('../api/runtime-configuration.api');
|
|
18
|
+
const {
|
|
19
|
+
retemplateAllVariableDefinitions,
|
|
20
|
+
retemplateDatasourceConfigurationOverrides
|
|
21
|
+
} = require('./configuration-env-resolver');
|
|
22
|
+
const { mergeEnvTemplateWithExisting } = require('../generator/split');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @param {Object} response - Dataplane API client response
|
|
26
|
+
* @returns {Record<string, string>}
|
|
27
|
+
*/
|
|
28
|
+
function extractResolvedVariableValues(response) {
|
|
29
|
+
if (!response || !response.success) {
|
|
30
|
+
return {};
|
|
31
|
+
}
|
|
32
|
+
const body = response.data && typeof response.data === 'object' ? response.data : {};
|
|
33
|
+
const variables = body.variables && typeof body.variables === 'object' ? body.variables : {};
|
|
34
|
+
const out = {};
|
|
35
|
+
for (const [name, entry] of Object.entries(variables)) {
|
|
36
|
+
if (!entry || typeof entry.value !== 'string') {
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
const value = entry.value.trim();
|
|
40
|
+
if (!value || value.startsWith('kv://')) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
out[name] = value;
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {string} dataplaneUrl
|
|
50
|
+
* @param {Object} authConfig
|
|
51
|
+
* @param {string} systemKey
|
|
52
|
+
* @param {Array<{ key?: string }>} dataSources
|
|
53
|
+
* @returns {Promise<Record<string, string>>}
|
|
54
|
+
*/
|
|
55
|
+
async function collectResolvedConfigurationEnvUpdates(
|
|
56
|
+
dataplaneUrl,
|
|
57
|
+
authConfig,
|
|
58
|
+
systemKey,
|
|
59
|
+
dataSources
|
|
60
|
+
) {
|
|
61
|
+
const updates = {};
|
|
62
|
+
const systemResponse = await getExternalSystemConfigurationResolved(
|
|
63
|
+
dataplaneUrl,
|
|
64
|
+
systemKey,
|
|
65
|
+
authConfig
|
|
66
|
+
);
|
|
67
|
+
Object.assign(updates, extractResolvedVariableValues(systemResponse));
|
|
68
|
+
|
|
69
|
+
for (const ds of dataSources || []) {
|
|
70
|
+
if (!ds?.key) {
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
const dsResponse = await getExternalDataSourceConfigurationResolved(
|
|
74
|
+
dataplaneUrl,
|
|
75
|
+
ds.key,
|
|
76
|
+
authConfig
|
|
77
|
+
);
|
|
78
|
+
Object.assign(updates, extractResolvedVariableValues(dsResponse));
|
|
79
|
+
}
|
|
80
|
+
return updates;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @param {string} integrationPath
|
|
85
|
+
* @param {Record<string, string>} updates
|
|
86
|
+
* @returns {Promise<boolean>}
|
|
87
|
+
*/
|
|
88
|
+
async function mergeConfigurationUpdatesIntoEnvTemplate(integrationPath, updates) {
|
|
89
|
+
const keys = Object.keys(updates || {});
|
|
90
|
+
if (!keys.length) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const envTemplatePath = path.join(integrationPath, 'env.template');
|
|
94
|
+
const expectedByKey = new Map();
|
|
95
|
+
for (const key of keys) {
|
|
96
|
+
expectedByKey.set(key, `${key}=${updates[key]}`);
|
|
97
|
+
}
|
|
98
|
+
const existingContent = fs.existsSync(envTemplatePath)
|
|
99
|
+
? await fsPromises.readFile(envTemplatePath, 'utf8')
|
|
100
|
+
: '';
|
|
101
|
+
const merged = mergeEnvTemplateWithExisting(existingContent, expectedByKey);
|
|
102
|
+
await fsPromises.writeFile(envTemplatePath, merged, { mode: 0o644, encoding: 'utf8' });
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* @param {string} filePath
|
|
108
|
+
* @returns {Promise<boolean>}
|
|
109
|
+
*/
|
|
110
|
+
async function retemplateConfigurationFile(filePath, { system = false } = {}) {
|
|
111
|
+
if (!filePath || !fs.existsSync(filePath)) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
const raw = await fsPromises.readFile(filePath, 'utf8');
|
|
115
|
+
const isJson = filePath.endsWith('.json');
|
|
116
|
+
const parsed = isJson ? JSON.parse(raw) : yaml.load(raw);
|
|
117
|
+
if (!parsed || typeof parsed !== 'object') {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
if (system) {
|
|
121
|
+
retemplateAllVariableDefinitions(parsed.configuration);
|
|
122
|
+
} else {
|
|
123
|
+
retemplateDatasourceConfigurationOverrides(parsed.configuration);
|
|
124
|
+
}
|
|
125
|
+
const next = isJson ? `${JSON.stringify(parsed, null, 2)}\n` : yaml.dump(parsed, { indent: 2, lineWidth: -1 });
|
|
126
|
+
await fsPromises.writeFile(filePath, next, { mode: 0o644, encoding: 'utf8' });
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* @param {string} integrationPath
|
|
132
|
+
* @param {string} systemKey
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async function retemplateDownloadedConfigurationFiles(integrationPath, systemKey) {
|
|
136
|
+
for (const ext of ['yaml', 'json']) {
|
|
137
|
+
const systemPath = path.join(integrationPath, `${systemKey}-system.${ext}`);
|
|
138
|
+
if (fs.existsSync(systemPath)) {
|
|
139
|
+
await retemplateConfigurationFile(systemPath, { system: true });
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const entries = await fsPromises.readdir(integrationPath);
|
|
143
|
+
for (const name of entries) {
|
|
144
|
+
if (!name.includes('-datasource-') || (!name.endsWith('.yaml') && !name.endsWith('.json'))) {
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
await retemplateConfigurationFile(path.join(integrationPath, name), { system: false });
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Pulls configuration_values from dataplane, merges env.template, and re-templates manifests.
|
|
153
|
+
*
|
|
154
|
+
* @param {Object} params
|
|
155
|
+
* @param {string} params.dataplaneUrl
|
|
156
|
+
* @param {Object} params.authConfig
|
|
157
|
+
* @param {string} params.systemKey
|
|
158
|
+
* @param {string} params.integrationPath
|
|
159
|
+
* @param {Array<{ key?: string }>} params.dataSources
|
|
160
|
+
* @returns {Promise<{ merged: number, names: string[] }>}
|
|
161
|
+
*/
|
|
162
|
+
async function syncRuntimeConfigurationFromDataplane({
|
|
163
|
+
dataplaneUrl,
|
|
164
|
+
authConfig,
|
|
165
|
+
systemKey,
|
|
166
|
+
integrationPath,
|
|
167
|
+
dataSources
|
|
168
|
+
}) {
|
|
169
|
+
const updates = await collectResolvedConfigurationEnvUpdates(
|
|
170
|
+
dataplaneUrl,
|
|
171
|
+
authConfig,
|
|
172
|
+
systemKey,
|
|
173
|
+
dataSources
|
|
174
|
+
);
|
|
175
|
+
const names = Object.keys(updates);
|
|
176
|
+
if (names.length) {
|
|
177
|
+
await mergeConfigurationUpdatesIntoEnvTemplate(integrationPath, updates);
|
|
178
|
+
}
|
|
179
|
+
await retemplateDownloadedConfigurationFiles(integrationPath, systemKey);
|
|
180
|
+
return { merged: names.length, names };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
module.exports = {
|
|
184
|
+
extractResolvedVariableValues,
|
|
185
|
+
collectResolvedConfigurationEnvUpdates,
|
|
186
|
+
mergeConfigurationUpdatesIntoEnvTemplate,
|
|
187
|
+
retemplateDownloadedConfigurationFiles,
|
|
188
|
+
syncRuntimeConfigurationFromDataplane
|
|
189
|
+
};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Push runtime configuration_values to dataplane after publish (never logs values).
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Post-publish configuration PUT helpers
|
|
5
|
+
* @author AI Fabrix Team
|
|
6
|
+
* @version 1.0.0
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const {
|
|
10
|
+
putExternalSystemConfiguration,
|
|
11
|
+
putExternalDataSourceConfiguration
|
|
12
|
+
} = require('../api/runtime-configuration.api');
|
|
13
|
+
const { buildResolvedEnvMapForIntegration } = require('./configuration-env-resolver');
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @param {Array<{ name?: string, location?: string }>|undefined} systemConfiguration
|
|
17
|
+
* @param {Object.<string, string>} envMap
|
|
18
|
+
* @returns {Array<{ name: string, value: string }>}
|
|
19
|
+
*/
|
|
20
|
+
function collectSystemVariablePutRequests(systemConfiguration, envMap) {
|
|
21
|
+
if (!Array.isArray(systemConfiguration)) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
const requests = [];
|
|
25
|
+
for (const item of systemConfiguration) {
|
|
26
|
+
if (!item || !item.name) {
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
const location = String(item.location || 'variable').toLowerCase();
|
|
30
|
+
if (location !== 'variable') {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const name = String(item.name).trim();
|
|
34
|
+
const raw = envMap[name];
|
|
35
|
+
if (raw === undefined || raw === null) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
const value = String(raw).trim();
|
|
39
|
+
if (!value || value.startsWith('kv://') || value.includes('{{')) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
requests.push({ name, value });
|
|
43
|
+
}
|
|
44
|
+
return requests;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Datasource overrides are name+value only; values may already be resolved in upload payload.
|
|
49
|
+
*
|
|
50
|
+
* @param {Array<{ name?: string, value?: string }>|undefined} datasourceConfiguration
|
|
51
|
+
* @returns {Array<{ name: string, value: string }>}
|
|
52
|
+
*/
|
|
53
|
+
function collectDatasourceOverridePutRequests(datasourceConfiguration) {
|
|
54
|
+
if (!Array.isArray(datasourceConfiguration)) {
|
|
55
|
+
return [];
|
|
56
|
+
}
|
|
57
|
+
const requests = [];
|
|
58
|
+
for (const item of datasourceConfiguration) {
|
|
59
|
+
if (!item || !item.name) {
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
const name = String(item.name).trim();
|
|
63
|
+
const raw = item.value;
|
|
64
|
+
if (typeof raw !== 'string') {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const value = raw.trim();
|
|
68
|
+
if (!value || value.startsWith('kv://') || value.includes('{{')) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
requests.push({ name, value });
|
|
72
|
+
}
|
|
73
|
+
return requests;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Upserts system-scoped and datasource-scoped configuration values after publish.
|
|
78
|
+
*
|
|
79
|
+
* @param {string} dataplaneUrl
|
|
80
|
+
* @param {Object} authConfig
|
|
81
|
+
* @param {string} systemKey
|
|
82
|
+
* @param {{ application?: { configuration?: unknown[] }, dataSources?: Array<{ key?: string, configuration?: unknown[] }> }} payload
|
|
83
|
+
* @returns {Promise<{ pushed: number, names: string[] }>}
|
|
84
|
+
*/
|
|
85
|
+
async function pushRuntimeConfigurationValues(dataplaneUrl, authConfig, systemKey, payload) {
|
|
86
|
+
const { envMap } = await buildResolvedEnvMapForIntegration(systemKey);
|
|
87
|
+
const names = [];
|
|
88
|
+
let pushed = 0;
|
|
89
|
+
|
|
90
|
+
const systemRequests = collectSystemVariablePutRequests(
|
|
91
|
+
payload?.application?.configuration,
|
|
92
|
+
envMap
|
|
93
|
+
);
|
|
94
|
+
for (const body of systemRequests) {
|
|
95
|
+
await putExternalSystemConfiguration(dataplaneUrl, systemKey, authConfig, body);
|
|
96
|
+
names.push(body.name);
|
|
97
|
+
pushed += 1;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
for (const ds of payload?.dataSources || []) {
|
|
101
|
+
if (!ds?.key) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const dsRequests = collectDatasourceOverridePutRequests(ds.configuration);
|
|
105
|
+
for (const body of dsRequests) {
|
|
106
|
+
await putExternalDataSourceConfiguration(dataplaneUrl, ds.key, authConfig, body);
|
|
107
|
+
names.push(`${ds.key}:${body.name}`);
|
|
108
|
+
pushed += 1;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return { pushed, names };
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
module.exports = {
|
|
116
|
+
collectSystemVariablePutRequests,
|
|
117
|
+
collectDatasourceOverridePutRequests,
|
|
118
|
+
pushRuntimeConfigurationValues
|
|
119
|
+
};
|
|
@@ -28,6 +28,23 @@ function resetValidators() {
|
|
|
28
28
|
externalDataSourceValidator = null;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
/**
|
|
32
|
+
* Register AJV schemas required to compile or validate external-datasource manifests.
|
|
33
|
+
* Includes type schemas and external-system (for $defs/subscriptionFilter cross-ref).
|
|
34
|
+
*
|
|
35
|
+
* @function registerExternalDatasourceAjvDependencies
|
|
36
|
+
* @param {import('ajv').default} ajv - AJV instance
|
|
37
|
+
*/
|
|
38
|
+
function registerExternalDatasourceAjvDependencies(ajv) {
|
|
39
|
+
ajv.addSchema(require('../schema/type/document-storage.json'));
|
|
40
|
+
ajv.addSchema(require('../schema/type/message-service.json'));
|
|
41
|
+
ajv.addSchema(require('../schema/type/vector-store.json'));
|
|
42
|
+
const externalSystemSchema = require('../schema/external-system.schema.json');
|
|
43
|
+
if (!ajv.getSchema(externalSystemSchema.$id)) {
|
|
44
|
+
ajv.addSchema(externalSystemSchema, externalSystemSchema.$id);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
31
48
|
/**
|
|
32
49
|
* Loads and compiles external-system schema
|
|
33
50
|
* Caches the compiled validator for performance
|
|
@@ -115,10 +132,7 @@ function loadExternalDataSourceSchema() {
|
|
|
115
132
|
|
|
116
133
|
const ajv = new Ajv({ allErrors: true, strict: false, strictSchema: false });
|
|
117
134
|
addFormats(ajv);
|
|
118
|
-
|
|
119
|
-
ajv.addSchema(require('../schema/type/document-storage.json'));
|
|
120
|
-
ajv.addSchema(require('../schema/type/message-service.json'));
|
|
121
|
-
ajv.addSchema(require('../schema/type/vector-store.json'));
|
|
135
|
+
registerExternalDatasourceAjvDependencies(ajv);
|
|
122
136
|
externalDataSourceValidator = ajv.compile(schemaToCompile);
|
|
123
137
|
|
|
124
138
|
return externalDataSourceValidator;
|
|
@@ -333,6 +347,7 @@ function detectSchemaType(filePath, content) {
|
|
|
333
347
|
module.exports = {
|
|
334
348
|
loadExternalSystemSchema,
|
|
335
349
|
loadExternalDataSourceSchema,
|
|
350
|
+
registerExternalDatasourceAjvDependencies,
|
|
336
351
|
detectSchemaType,
|
|
337
352
|
detectSchemaTypeFromParsed,
|
|
338
353
|
resetValidators
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Worker sidecar resolution from application.yaml build settings.
|
|
3
|
+
*
|
|
4
|
+
* @fileoverview Generic worker/beat companions driven by build.worker and imageRun* fields
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const { buildDefaultLocalContainerName } = require('./environment-scoped-resources');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {object|null|undefined} build
|
|
13
|
+
* @param {string} field
|
|
14
|
+
* @returns {string|null}
|
|
15
|
+
*/
|
|
16
|
+
function readImageRunCommand(build, field) {
|
|
17
|
+
if (!build || typeof build !== 'object') {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const raw = build[field];
|
|
21
|
+
if (typeof raw !== 'string') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
const trimmed = raw.trim();
|
|
25
|
+
return trimmed ? trimmed : null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* @param {object|null|undefined} appConfig
|
|
30
|
+
* @returns {boolean}
|
|
31
|
+
*/
|
|
32
|
+
function isWorkerStackEnabled(appConfig) {
|
|
33
|
+
if (!appConfig || typeof appConfig !== 'object') {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return appConfig.build?.worker === true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* @param {string} appKey
|
|
41
|
+
* @param {object|null|undefined} appConfig
|
|
42
|
+
* @returns {{
|
|
43
|
+
* enabled: boolean,
|
|
44
|
+
* worker: { key: string, command: string }|null,
|
|
45
|
+
* beat: { key: string, command: string }|null,
|
|
46
|
+
* companions: Array<{ role: string, key: string, command: string }>
|
|
47
|
+
* }}
|
|
48
|
+
*/
|
|
49
|
+
function resolveWorkerSidecars(appKey, appConfig) {
|
|
50
|
+
const empty = { enabled: false, worker: null, beat: null, companions: [] };
|
|
51
|
+
if (!isWorkerStackEnabled(appConfig)) {
|
|
52
|
+
return empty;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const build = appConfig.build && typeof appConfig.build === 'object' ? appConfig.build : {};
|
|
56
|
+
const workerCommand = readImageRunCommand(build, 'imageRunWorker');
|
|
57
|
+
const beatCommand = readImageRunCommand(build, 'imageRunBeat');
|
|
58
|
+
const companions = [];
|
|
59
|
+
|
|
60
|
+
if (workerCommand) {
|
|
61
|
+
companions.push({ role: 'worker', key: `${appKey}-worker`, command: workerCommand });
|
|
62
|
+
}
|
|
63
|
+
if (beatCommand) {
|
|
64
|
+
companions.push({ role: 'beat', key: `${appKey}-beat`, command: beatCommand });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (companions.length === 0) {
|
|
68
|
+
return empty;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const worker = companions.find((entry) => entry.role === 'worker') || null;
|
|
72
|
+
const beat = companions.find((entry) => entry.role === 'beat') || null;
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
enabled: true,
|
|
76
|
+
worker,
|
|
77
|
+
beat,
|
|
78
|
+
companions
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* @param {string} appKey
|
|
84
|
+
* @param {object|null|undefined} appConfig
|
|
85
|
+
* @returns {string[]}
|
|
86
|
+
*/
|
|
87
|
+
function getWorkerCompanionAppKeys(appKey, appConfig) {
|
|
88
|
+
return resolveWorkerSidecars(appKey, appConfig).companions.map((entry) => entry.key);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* @param {string} appKey
|
|
93
|
+
* @param {object} appConfig
|
|
94
|
+
* @param {{ devId: string|number, idNum: number }} ids
|
|
95
|
+
* @returns {{
|
|
96
|
+
* enabled: boolean,
|
|
97
|
+
* worker?: { key: string, containerName: string, command: string },
|
|
98
|
+
* beat?: { key: string, containerName: string, command: string }
|
|
99
|
+
* }}
|
|
100
|
+
*/
|
|
101
|
+
function buildWorkerSidecarComposeContext(appKey, appConfig, ids) {
|
|
102
|
+
const sidecars = resolveWorkerSidecars(appKey, appConfig);
|
|
103
|
+
if (!sidecars.enabled) {
|
|
104
|
+
return { enabled: false };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const context = { enabled: true };
|
|
108
|
+
if (sidecars.worker) {
|
|
109
|
+
context.worker = {
|
|
110
|
+
key: sidecars.worker.key,
|
|
111
|
+
containerName: buildDefaultLocalContainerName(sidecars.worker.key, ids.devId, ids.idNum),
|
|
112
|
+
command: sidecars.worker.command
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
if (sidecars.beat) {
|
|
116
|
+
context.beat = {
|
|
117
|
+
key: sidecars.beat.key,
|
|
118
|
+
containerName: buildDefaultLocalContainerName(sidecars.beat.key, ids.devId, ids.idNum),
|
|
119
|
+
command: sidecars.beat.command
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
return context;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Azure startupCommand from compose imageRun (drops leading exec).
|
|
127
|
+
*
|
|
128
|
+
* @param {string} imageRun
|
|
129
|
+
* @returns {string}
|
|
130
|
+
*/
|
|
131
|
+
function imageRunToStartupCommand(imageRun) {
|
|
132
|
+
return imageRun.replace(/^exec\s+/i, '').trim();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
module.exports = {
|
|
136
|
+
readImageRunCommand,
|
|
137
|
+
isWorkerStackEnabled,
|
|
138
|
+
resolveWorkerSidecars,
|
|
139
|
+
getWorkerCompanionAppKeys,
|
|
140
|
+
buildWorkerSidecarComposeContext,
|
|
141
|
+
imageRunToStartupCommand
|
|
142
|
+
};
|
|
@@ -16,6 +16,7 @@ const path = require('path');
|
|
|
16
16
|
const { formatValidationErrors } = require('../utils/error-formatter');
|
|
17
17
|
const { validateFieldReferences } = require('../datasource/field-reference-validator');
|
|
18
18
|
const { validateAbac } = require('../datasource/abac-validator');
|
|
19
|
+
const { validateManifestRuntimeConfiguration } = require('./runtime-configuration-rules');
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Load and normalize external-system + external-datasource schema objects for manifest AJV.
|
|
@@ -247,6 +248,7 @@ async function validateControllerManifest(manifest) {
|
|
|
247
248
|
validateInlineSystem(manifest, ajv, externalSystemSchema, errors);
|
|
248
249
|
validateDatasources(manifest, ajv, externalDatasourceSchema, errors, warnings);
|
|
249
250
|
validateDatasourceSystemKeyAlignment(manifest, errors);
|
|
251
|
+
errors.push(...validateManifestRuntimeConfiguration(manifest));
|
|
250
252
|
validateConditionalRequirements(manifest, errors, warnings);
|
|
251
253
|
validateRequiredFields(manifest, errors);
|
|
252
254
|
|