@aifabrix/builder 2.46.0 → 2.47.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.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 +18 -4
- package/lib/cli/infra-guided-auth.js +36 -12
- 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-npm.js +59 -0
- package/lib/cli/setup-platform.js +1 -1
- package/lib/cli/setup-secrets.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/login-device.js +11 -3
- package/lib/commands/login.js +8 -3
- package/lib/commands/npm-config.js +103 -0
- 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/api.js +2 -1
- 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/controller-url.js +4 -1
- 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/dev-platform-tls.js +148 -0
- 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/health-check-request.js +114 -0
- package/lib/utils/health-check-url.js +3 -1
- package/lib/utils/health-check.js +1 -113
- package/lib/utils/help-builder.js +3 -0
- package/lib/utils/keycloak-realm-ready.js +5 -1
- package/lib/utils/localhost-public-host.js +31 -0
- package/lib/utils/npm-user-config.js +145 -0
- package/lib/utils/paths.js +25 -0
- package/lib/utils/platform-controller-url.js +58 -4
- 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/url-declarative-public-base.js +33 -25
- 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
|
@@ -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
|
};
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const path = require('path');
|
|
10
|
+
const { readDatasourceConfigFile } = require('./run-capability-copy');
|
|
11
11
|
const { resolveValidateInputPath } = require('../validate');
|
|
12
12
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
13
13
|
const { extractCapabilitySliceForDiff } = require('./capability-diff-slice');
|
|
@@ -108,8 +108,8 @@ function resolveProfileKeys(opts) {
|
|
|
108
108
|
function runCapabilityDiff(opts) {
|
|
109
109
|
const pathA = resolveValidateInputPath(opts.fileA.trim());
|
|
110
110
|
const pathB = resolveValidateInputPath(opts.fileB.trim());
|
|
111
|
-
const docA =
|
|
112
|
-
const docB =
|
|
111
|
+
const docA = readDatasourceConfigFile(pathA);
|
|
112
|
+
const docB = readDatasourceConfigFile(pathB);
|
|
113
113
|
|
|
114
114
|
const { capA, capB } = resolveCapabilityKeys(opts);
|
|
115
115
|
const { profA, profB } = resolveProfileKeys(opts);
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
|
|
9
9
|
'use strict';
|
|
10
10
|
|
|
11
|
-
const fs = require('fs');
|
|
12
11
|
const { resolveControllerUrl } = require('../../utils/controller-url');
|
|
13
12
|
const { normalizeControllerUrl } = require('../../core/config');
|
|
14
13
|
const { getOrRefreshDeviceToken } = require('../../utils/token-manager');
|
|
@@ -19,7 +18,7 @@ const {
|
|
|
19
18
|
} = require('../validate');
|
|
20
19
|
const { applyCapabilityDimension } = require('./dimension-operations');
|
|
21
20
|
const { validateDimensionSemantics } = require('./dimension-validate');
|
|
22
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
21
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
23
22
|
const { tryResolveDatasourceKeyToLocalPath, readJsonFile } = require('../../resolvers/datasource-resolver');
|
|
24
23
|
const { tryFetchDatasourceConfig } = require('../../resolvers/manifest-resolver');
|
|
25
24
|
|
|
@@ -231,8 +230,7 @@ function applyBindingAndValidateSchema({ parsed, opts, semanticWarnings, remoteF
|
|
|
231
230
|
async function runCapabilityDimension(rawOpts) {
|
|
232
231
|
const opts = normalizeRunOptions(rawOpts);
|
|
233
232
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey);
|
|
234
|
-
const
|
|
235
|
-
const parsed = JSON.parse(raw);
|
|
233
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
236
234
|
|
|
237
235
|
const systemKeyForAuth = resolveSystemKeyForAuth(parsed);
|
|
238
236
|
const { remoteTargetsByKey, remoteFetchMeta } = await loadRemoteTargetsByKey({
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const { execSync } = require('child_process');
|
|
11
10
|
const inquirer = require('inquirer');
|
|
12
11
|
const {
|
|
@@ -19,7 +18,8 @@ const {
|
|
|
19
18
|
resolveSingleOpsKey,
|
|
20
19
|
resolveProfileKeyForLogical
|
|
21
20
|
} = require('./capability-resolve');
|
|
22
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
21
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
22
|
+
const { listCapabilityKeys } = require('./capability-manifest');
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* @typedef {object} RunCapabilityEditOpts
|
|
@@ -35,10 +35,7 @@ const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
|
35
35
|
* @returns {string[]}
|
|
36
36
|
*/
|
|
37
37
|
function collectCapabilityKeys(doc) {
|
|
38
|
-
const s = new Set();
|
|
39
|
-
if (Array.isArray(doc.capabilities)) {
|
|
40
|
-
doc.capabilities.forEach((c) => s.add(String(c)));
|
|
41
|
-
}
|
|
38
|
+
const s = new Set(listCapabilityKeys(doc.capabilities));
|
|
42
39
|
if (doc.openapi?.operations) {
|
|
43
40
|
Object.keys(doc.openapi.operations).forEach((k) => s.add(k));
|
|
44
41
|
}
|
|
@@ -351,7 +348,7 @@ async function runCapabilityEdit(opts) {
|
|
|
351
348
|
throw new Error('capability edit requires an interactive terminal (TTY). Use a terminal or SSH with -t.');
|
|
352
349
|
}
|
|
353
350
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
354
|
-
const doc =
|
|
351
|
+
const doc = readDatasourceConfigFile(resolvedPath);
|
|
355
352
|
const { capKey, section, profileKey } = await resolveEditTargets(doc, opts);
|
|
356
353
|
const initial = getEditableJson(doc, capKey, section, profileKey);
|
|
357
354
|
const body = await promptEditorJson(initial);
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const {
|
|
11
10
|
resolveValidateInputPath,
|
|
12
11
|
validateDatasourceParsed
|
|
13
12
|
} = require('../validate');
|
|
14
13
|
const { applyCapabilityRelate } = require('./relate-operations');
|
|
15
14
|
const { validateRelateSemantics } = require('./relate-validate');
|
|
16
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
15
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
17
16
|
const { tryResolveDatasourceKeyToLocalPath, readJsonFile } = require('../../resolvers/datasource-resolver');
|
|
18
17
|
const { tryFetchDatasourceConfig } = require('../../resolvers/manifest-resolver');
|
|
19
18
|
|
|
@@ -134,8 +133,7 @@ function applyRelateAndValidateSchema(parsed, opts, semanticWarnings, remoteVali
|
|
|
134
133
|
*/
|
|
135
134
|
async function runCapabilityRelate(opts) {
|
|
136
135
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
137
|
-
const
|
|
138
|
-
const parsed = JSON.parse(raw);
|
|
136
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
139
137
|
|
|
140
138
|
const targetDocLocal = loadTargetDocLocal(opts.targetDatasource);
|
|
141
139
|
const systemKeyForAuth = resolveSystemKeyForAuth(parsed);
|
|
@@ -6,14 +6,13 @@
|
|
|
6
6
|
* @version 2.0.0
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
const fs = require('fs');
|
|
10
9
|
const {
|
|
11
10
|
resolveValidateInputPath,
|
|
12
11
|
validateDatasourceParsed
|
|
13
12
|
} = require('../validate');
|
|
14
13
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
15
14
|
const { applyCapabilityRemove } = require('./remove-operations');
|
|
16
|
-
const { writeBackup, atomicWriteJson } = require('./run-capability-copy');
|
|
15
|
+
const { writeBackup, atomicWriteJson, readDatasourceConfigFile } = require('./run-capability-copy');
|
|
17
16
|
|
|
18
17
|
/**
|
|
19
18
|
* @param {{ valid: boolean, errors: string[] }} validation
|
|
@@ -67,8 +66,7 @@ function makeRemoveResult(resolvedPath, capability, result, validation, dryRun,
|
|
|
67
66
|
*/
|
|
68
67
|
async function runCapabilityRemove(opts) {
|
|
69
68
|
const resolvedPath = resolveValidateInputPath(opts.fileOrKey.trim());
|
|
70
|
-
const
|
|
71
|
-
const parsed = JSON.parse(raw);
|
|
69
|
+
const parsed = readDatasourceConfigFile(resolvedPath);
|
|
72
70
|
|
|
73
71
|
const capability = normalizeCapabilityKey(opts.capability, 'Capability (--capability)');
|
|
74
72
|
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
const { normalizeCapabilityKey } = require('./capability-key');
|
|
10
|
+
const { capabilitiesIncludes } = require('./capability-manifest');
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Lists structural locations where a capability key should appear.
|
|
@@ -18,7 +19,7 @@ const { normalizeCapabilityKey } = require('./capability-key');
|
|
|
18
19
|
function checkCapabilitySlices(parsed, rawKey) {
|
|
19
20
|
const key = normalizeCapabilityKey(rawKey, 'capability');
|
|
20
21
|
const missing = [];
|
|
21
|
-
if (!
|
|
22
|
+
if (!capabilitiesIncludes(parsed.capabilities, key)) {
|
|
22
23
|
missing.push(`capabilities[] (missing "${key}")`);
|
|
23
24
|
}
|
|
24
25
|
if (!parsed.openapi?.operations?.[key]) {
|
|
@@ -38,7 +38,8 @@ function datasourceIdentifierMatchesFile(identifier, fileRef, parsed) {
|
|
|
38
38
|
if (stem === id) {
|
|
39
39
|
return true;
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
const lowerId = id.toLowerCase();
|
|
42
|
+
if (`${stem}.json` === lowerId || `${stem}.yaml` === lowerId || `${stem}.yml` === lowerId) {
|
|
42
43
|
return true;
|
|
43
44
|
}
|
|
44
45
|
return false;
|
|
@@ -30,7 +30,7 @@ function logHeaderAndIdentity(result, trimmed, showMapping) {
|
|
|
30
30
|
const { resolvedPath, summary } = result;
|
|
31
31
|
logger.log('');
|
|
32
32
|
logger.log(sectionTitle('Datasource validation'));
|
|
33
|
-
logger.log(metadata('Offline — JSON schema and integration wiring'));
|
|
33
|
+
logger.log(metadata('Offline — YAML/JSON schema and integration wiring'));
|
|
34
34
|
logger.log('');
|
|
35
35
|
if (summary) {
|
|
36
36
|
logger.log(` ${headerKeyValue('Key:', summary.key)}`);
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* @version 2.0.0
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
const { validateOrphanExposedProfiles } = require('./orphan-profiles-validator');
|
|
14
|
+
|
|
13
15
|
/**
|
|
14
16
|
* Set of attribute names plus root dimension keys valid for field references.
|
|
15
17
|
* Used for primaryKey (schema allows dimension keys or attributes) and other paths (attributes only).
|
|
@@ -40,16 +42,34 @@ function checkPrimaryKey(parsed, attributesAndDimensions, errors) {
|
|
|
40
42
|
});
|
|
41
43
|
}
|
|
42
44
|
|
|
45
|
+
/** @returns {Set<string>} */
|
|
46
|
+
function profileReferenceSet(parsed) {
|
|
47
|
+
if (parsed?.entityType === 'serviceContract') {
|
|
48
|
+
const schema = parsed?.exposed?.schema;
|
|
49
|
+
if (schema && typeof schema === 'object' && !Array.isArray(schema)) {
|
|
50
|
+
return new Set(
|
|
51
|
+
Object.keys(schema).filter(key => typeof key === 'string' && key !== '')
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return new Set(Object.keys(parsed?.fieldMappings?.attributes ?? {}));
|
|
56
|
+
}
|
|
57
|
+
|
|
43
58
|
/** @param {string[]} errors */
|
|
44
|
-
function checkExposedProfiles(parsed,
|
|
59
|
+
function checkExposedProfiles(parsed, _attrSet, errors) {
|
|
45
60
|
const profiles = parsed?.exposed?.profiles;
|
|
46
61
|
if (!profiles || typeof profiles !== 'object' || Array.isArray(profiles)) return;
|
|
62
|
+
const profileRefSet = profileReferenceSet(parsed);
|
|
63
|
+
const referenceLabel =
|
|
64
|
+
parsed?.entityType === 'serviceContract'
|
|
65
|
+
? 'exposed.schema'
|
|
66
|
+
: 'fieldMappings.attributes';
|
|
47
67
|
Object.entries(profiles).forEach(([profileName, fields]) => {
|
|
48
68
|
if (!Array.isArray(fields)) return;
|
|
49
69
|
fields.forEach((field, idx) => {
|
|
50
|
-
if (typeof field === 'string' && !
|
|
70
|
+
if (typeof field === 'string' && !profileRefSet.has(field)) {
|
|
51
71
|
errors.push(
|
|
52
|
-
`exposed.profiles.${profileName}[${idx}]: field '${field}' does not exist in
|
|
72
|
+
`exposed.profiles.${profileName}[${idx}]: field '${field}' does not exist in ${referenceLabel}. Add the attribute or remove the reference.`
|
|
53
73
|
);
|
|
54
74
|
}
|
|
55
75
|
});
|
|
@@ -121,6 +141,7 @@ function validateFieldReferences(parsed) {
|
|
|
121
141
|
|
|
122
142
|
checkPrimaryKey(parsed, attributesAndDimensions, errors);
|
|
123
143
|
checkExposedProfiles(parsed, attrSet, errors);
|
|
144
|
+
errors.push(...validateOrphanExposedProfiles(parsed));
|
|
124
145
|
if (normalizedAttributes.length === 0) return errors;
|
|
125
146
|
|
|
126
147
|
checkIndexingAndValidation(parsed, normalizedAttributes, errors);
|