@aifabrix/builder 2.44.3 → 2.44.5
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 -1
- package/integration/roundtrip-test-local/README.md +1 -2
- package/integration/roundtrip-test-local2/README.md +1 -2
- package/jest.projects.js +31 -15
- package/lib/api/certificates.api.js +21 -3
- package/lib/api/types/wizard.types.js +2 -1
- package/lib/certification/post-unified-cert-sync.js +13 -2
- package/lib/certification/sync-after-external-command.js +6 -3
- package/lib/certification/sync-system-certification.js +60 -14
- package/lib/cli/setup-app.help.js +1 -1
- package/lib/cli/setup-app.test-commands.js +75 -39
- package/lib/cli/setup-infra.js +6 -2
- package/lib/cli/setup-utility.js +20 -1
- package/lib/commands/datasource-unified-test-cli.js +81 -46
- package/lib/commands/datasource-unified-test-cli.options.js +4 -2
- package/lib/commands/datasource.js +3 -31
- package/lib/commands/repair-datasource-keys.js +1 -1
- package/lib/commands/repair-datasource-openapi.js +57 -0
- package/lib/commands/repair-datasource.js +5 -0
- package/lib/commands/repair-internal.js +2 -4
- package/lib/commands/repair-rbac.js +25 -2
- package/lib/commands/repair.js +2 -19
- package/lib/commands/test-e2e-external.js +9 -9
- package/lib/commands/up-common.js +25 -0
- package/lib/commands/upload.js +18 -4
- package/lib/commands/wizard-core.js +53 -11
- package/lib/commands/wizard-dataplane.js +14 -6
- package/lib/commands/wizard-entity-selection.js +71 -14
- package/lib/commands/wizard-headless.js +5 -2
- package/lib/commands/wizard-helpers.js +13 -1
- package/lib/commands/wizard.js +208 -60
- package/lib/datasource/datasource-validate-display.js +162 -0
- package/lib/datasource/datasource-validate-summary.js +194 -0
- package/lib/datasource/test-e2e.js +65 -37
- package/lib/datasource/unified-validation-run-body.js +1 -2
- package/lib/datasource/validate.js +14 -6
- package/lib/external-system/test.js +12 -8
- package/lib/generator/external-controller-manifest.js +12 -2
- package/lib/generator/wizard-prompts.js +7 -1
- package/lib/generator/wizard.js +34 -0
- package/lib/schema/cip-capacity-display.fallback.json +7 -0
- package/lib/schema/datasource-test-run.schema.json +79 -1
- package/lib/schema/external-datasource.schema.json +94 -2
- package/lib/schema/flag-map-validation-run.json +1 -2
- package/lib/schema/type/document-storage.json +83 -3
- package/lib/schema/wizard-config.schema.json +1 -1
- package/lib/utils/configuration-env-resolver.js +38 -0
- package/lib/utils/dataplane-resolver.js +3 -2
- package/lib/utils/datasource-test-run-capacity-operations.js +149 -0
- package/lib/utils/datasource-test-run-debug-display.js +143 -1
- package/lib/utils/datasource-test-run-display.js +46 -33
- package/lib/utils/datasource-test-run-tty-log.js +6 -2
- package/lib/utils/datasource-test-run-tty-meta-lines.js +123 -0
- package/lib/utils/error-formatter.js +32 -2
- package/lib/utils/external-readme.js +47 -3
- package/lib/utils/external-system-readiness-core.js +39 -0
- package/lib/utils/external-system-readiness-deploy-display.js +2 -3
- package/lib/utils/external-system-readiness-display-internals.js +3 -2
- package/lib/utils/external-system-system-test-tty.js +33 -9
- package/lib/utils/external-system-validators.js +62 -5
- package/lib/utils/load-cip-capacity-display-config.js +130 -0
- package/lib/utils/paths.js +10 -3
- package/lib/utils/schema-resolver.js +98 -2
- package/lib/utils/urls-local-registry.js +52 -10
- package/lib/utils/validation-run-poll.js +15 -4
- package/lib/utils/validation-run-request.js +4 -6
- package/lib/validation/dimension-display-helpers.js +60 -0
- package/lib/validation/validate-display-log-helpers.js +39 -0
- package/lib/validation/validate-display.js +89 -83
- package/package.json +1 -1
- package/templates/applications/miso-controller/env.template +6 -6
- package/templates/external-system/README.md.hbs +58 -32
package/lib/generator/wizard.js
CHANGED
|
@@ -32,6 +32,35 @@ function toKeySegment(str) {
|
|
|
32
32
|
return sanitized || 'default';
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Align authentication.security kv:// namespaces and credentialKey with the final system key.
|
|
37
|
+
* Dataplane normalizes this before respond; when appName overrides a spec-derived key (e.g.
|
|
38
|
+
* OpenAPI title "Companies"), the builder still must rewrite nested auth so it matches env.template.
|
|
39
|
+
*
|
|
40
|
+
* @param {Object|null|undefined} authentication - authentication block from dataplane
|
|
41
|
+
* @param {string} systemKey - Final external system key (integration app name)
|
|
42
|
+
* @param {string} [authDisplayName] - Credential display name (typically title-cased app name)
|
|
43
|
+
*/
|
|
44
|
+
function normalizeAuthenticationToSystemKey(authentication, systemKey, authDisplayName) {
|
|
45
|
+
if (!authentication || typeof authentication !== 'object') return;
|
|
46
|
+
authentication.credentialKey = `${systemKey}-cred`;
|
|
47
|
+
const security = authentication.security;
|
|
48
|
+
if (security && typeof security === 'object') {
|
|
49
|
+
for (const k of Object.keys(security)) {
|
|
50
|
+
const v = security[k];
|
|
51
|
+
if (typeof v === 'string' && v.startsWith('kv://')) {
|
|
52
|
+
const rest = v.slice(5);
|
|
53
|
+
const idx = rest.indexOf('/');
|
|
54
|
+
const suffix = idx >= 0 ? rest.slice(idx + 1) : '';
|
|
55
|
+
security[k] = suffix ? `kv://${systemKey}/${suffix}` : `kv://${systemKey}`;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (authDisplayName) {
|
|
60
|
+
authentication.displayName = authDisplayName;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
35
64
|
/**
|
|
36
65
|
* Generate files from dataplane-generated wizard configurations
|
|
37
66
|
* @async
|
|
@@ -182,6 +211,11 @@ async function prepareWizardContext(appName, systemConfig, datasourceConfigs) {
|
|
|
182
211
|
const originalSystemKey = systemConfig.key || finalSystemKey;
|
|
183
212
|
const appDisplayName = appName.replace(/-/g, ' ').replace(/\b\w/g, l => l.toUpperCase());
|
|
184
213
|
const updatedSystemConfig = { ...systemConfig, key: finalSystemKey, displayName: appDisplayName };
|
|
214
|
+
normalizeAuthenticationToSystemKey(
|
|
215
|
+
updatedSystemConfig.authentication,
|
|
216
|
+
finalSystemKey,
|
|
217
|
+
appDisplayName
|
|
218
|
+
);
|
|
185
219
|
const originalPrefix = `${originalSystemKey}-`;
|
|
186
220
|
const updatedDatasourceConfigs = datasourceConfigs.map(ds => {
|
|
187
221
|
let newKey;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$comment": "Used when external-datasource.schema.json is not on disk. standardOperationOrder must match $defs.cipDefinition.properties.operations.properties key order in dataplane app/schemas/json/external-datasource.schema.json.",
|
|
3
|
+
"standardOperationOrder": ["list", "get", "create", "update", "delete"],
|
|
4
|
+
"displayAliases": {
|
|
5
|
+
"create": "insert (create)"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"reportVersion": {
|
|
10
10
|
"type": "string",
|
|
11
11
|
"description": "Semver-style contract version for this envelope. Policy: additive fields => minor bump within same major; removed/renamed fields => major bump. Route migrations must cite target reportVersion.",
|
|
12
|
-
"example": "1.
|
|
12
|
+
"example": "1.3.0"
|
|
13
13
|
},
|
|
14
14
|
"runType": {
|
|
15
15
|
"type": "string",
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
"certificate": {
|
|
52
52
|
"$ref": "#/$defs/CertificateResult"
|
|
53
53
|
},
|
|
54
|
+
"certificateIssuance": {
|
|
55
|
+
"$ref": "#/$defs/CertificateIssuanceResult",
|
|
56
|
+
"description": "Integration-certificate auto-issue outcome for this datasource scope (VALIDATION_AUTO_ISSUE_INTEGRATION_CERTIFICATE)."
|
|
57
|
+
},
|
|
54
58
|
"capabilitySummary": {
|
|
55
59
|
"$ref": "#/$defs/CapabilitySummary"
|
|
56
60
|
},
|
|
@@ -69,9 +73,50 @@
|
|
|
69
73
|
},
|
|
70
74
|
"developer": {
|
|
71
75
|
"$ref": "#/$defs/DeveloperSummary"
|
|
76
|
+
},
|
|
77
|
+
"datasourceSummaries": {
|
|
78
|
+
"type": "array",
|
|
79
|
+
"description": "Optional per-datasource rollups when the underlying run evaluated multiple datasources (e.g. validationScope=externalSystem).",
|
|
80
|
+
"items": {
|
|
81
|
+
"$ref": "#/$defs/DatasourceSummary"
|
|
82
|
+
}
|
|
72
83
|
}
|
|
73
84
|
},
|
|
74
85
|
"$defs": {
|
|
86
|
+
"DatasourceSummary": {
|
|
87
|
+
"type": "object",
|
|
88
|
+
"required": ["datasourceKey", "status"],
|
|
89
|
+
"additionalProperties": false,
|
|
90
|
+
"description": "Lightweight per-datasource rollup for system-scoped runs.",
|
|
91
|
+
"properties": {
|
|
92
|
+
"datasourceKey": {
|
|
93
|
+
"type": "string",
|
|
94
|
+
"description": "Datasource key within the system."
|
|
95
|
+
},
|
|
96
|
+
"status": {
|
|
97
|
+
"type": "string",
|
|
98
|
+
"description": "Datasource rollup: ok | warn | fail | skipped.",
|
|
99
|
+
"enum": ["ok", "warn", "fail", "skipped"]
|
|
100
|
+
},
|
|
101
|
+
"validationStatus": {
|
|
102
|
+
"type": "string",
|
|
103
|
+
"description": "Validation layer rollup for this datasource.",
|
|
104
|
+
"enum": ["ok", "warn", "fail"]
|
|
105
|
+
},
|
|
106
|
+
"certificateStatus": {
|
|
107
|
+
"type": "string",
|
|
108
|
+
"description": "Certification rollup for this datasource.",
|
|
109
|
+
"enum": ["passed", "not_passed"]
|
|
110
|
+
},
|
|
111
|
+
"issues": {
|
|
112
|
+
"type": "array",
|
|
113
|
+
"description": "Blocking/warning issues for this datasource.",
|
|
114
|
+
"items": {
|
|
115
|
+
"$ref": "#/$defs/Issue"
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
75
120
|
"ValidationLayerResult": {
|
|
76
121
|
"type": "object",
|
|
77
122
|
"required": ["status"],
|
|
@@ -161,6 +206,39 @@
|
|
|
161
206
|
}
|
|
162
207
|
}
|
|
163
208
|
},
|
|
209
|
+
"CertificateIssuanceResult": {
|
|
210
|
+
"type": "object",
|
|
211
|
+
"additionalProperties": false,
|
|
212
|
+
"required": ["status", "systemKey", "datasourceKey"],
|
|
213
|
+
"description": "Structured result when the dataplane evaluates integration-certificate auto-issue (safe for clients and logs).",
|
|
214
|
+
"properties": {
|
|
215
|
+
"status": {
|
|
216
|
+
"type": "string",
|
|
217
|
+
"enum": ["issued", "reusedActive", "skipped", "failed"],
|
|
218
|
+
"description": "issued | reusedActive | skipped | failed."
|
|
219
|
+
},
|
|
220
|
+
"reasonCode": {
|
|
221
|
+
"type": "string",
|
|
222
|
+
"description": "Stable machine code when status is skipped or failed."
|
|
223
|
+
},
|
|
224
|
+
"message": {
|
|
225
|
+
"type": "string",
|
|
226
|
+
"description": "Human-readable summary."
|
|
227
|
+
},
|
|
228
|
+
"validationHint": {
|
|
229
|
+
"type": "string",
|
|
230
|
+
"description": "Optional remediation hint."
|
|
231
|
+
},
|
|
232
|
+
"systemKey": {
|
|
233
|
+
"type": "string",
|
|
234
|
+
"description": "External system key for this issuance scope."
|
|
235
|
+
},
|
|
236
|
+
"datasourceKey": {
|
|
237
|
+
"type": "string",
|
|
238
|
+
"description": "Datasource key for this issuance scope."
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
},
|
|
164
242
|
"CertificateResult": {
|
|
165
243
|
"type": "object",
|
|
166
244
|
"required": ["status"],
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"key":"external-datasource-schema",
|
|
8
8
|
"name":"External Data Source Configuration Schema",
|
|
9
9
|
"description":"JSON schema for validating ExternalDataSource configuration files",
|
|
10
|
-
|
|
10
|
+
"version":"2.4.6",
|
|
11
11
|
"type":"schema",
|
|
12
12
|
"category":"integration",
|
|
13
13
|
"author":"AI Fabrix Team",
|
|
14
14
|
"createdAt":"2024-01-01T00:00:00Z",
|
|
15
|
-
"updatedAt":"2026-04-
|
|
15
|
+
"updatedAt":"2026-04-20T00:00:00Z",
|
|
16
16
|
"compatibility":{
|
|
17
17
|
"minVersion":"1.0.0",
|
|
18
18
|
"maxVersion":"3.0.0",
|
|
@@ -175,6 +175,14 @@
|
|
|
175
175
|
"exposed.profiles object profiles: attributes may be an object map (property names = field keys; values ignored), matching runtime exposed_profile_field_names and CIP/ExposedFieldsValidator behavior."
|
|
176
176
|
],
|
|
177
177
|
"breaking":false
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
"version":"2.4.6",
|
|
181
|
+
"date":"2026-04-24T00:00:00Z",
|
|
182
|
+
"changes":[
|
|
183
|
+
"Added optional fetch.httpResponseNormalization for manifest-driven GET response shaping (302 Location follow, JSON redirect envelopes, nested JSON string URL follow-up)."
|
|
184
|
+
],
|
|
185
|
+
"breaking":false
|
|
178
186
|
}
|
|
179
187
|
]
|
|
180
188
|
},
|
|
@@ -705,6 +713,10 @@
|
|
|
705
713
|
"input":{
|
|
706
714
|
"type":"object",
|
|
707
715
|
"additionalProperties":true
|
|
716
|
+
},
|
|
717
|
+
"order":{
|
|
718
|
+
"type":"integer",
|
|
719
|
+
"description":"Optional stable sort hint for scenario execution / diagnostics."
|
|
708
720
|
}
|
|
709
721
|
},
|
|
710
722
|
"additionalProperties":false
|
|
@@ -950,6 +962,83 @@
|
|
|
950
962
|
}
|
|
951
963
|
],
|
|
952
964
|
"$defs":{
|
|
965
|
+
"httpResponseNormalization":{
|
|
966
|
+
"type":"object",
|
|
967
|
+
"description":"Optional GET response shaping for miso-client adapter dicts and native 302 Location follows. Omitted = disabled.",
|
|
968
|
+
"additionalProperties":false,
|
|
969
|
+
"properties":{
|
|
970
|
+
"applyWhenUrlContains":{
|
|
971
|
+
"type":"array",
|
|
972
|
+
"items":{
|
|
973
|
+
"type":"string",
|
|
974
|
+
"minLength":1
|
|
975
|
+
},
|
|
976
|
+
"description":"When non-empty, normalization applies only if the request URL (path plus query, lowercased) contains at least one substring (case-insensitive)."
|
|
977
|
+
},
|
|
978
|
+
"followRedirectJsonEnvelope":{
|
|
979
|
+
"type":"object",
|
|
980
|
+
"additionalProperties":false,
|
|
981
|
+
"properties":{
|
|
982
|
+
"enabled":{
|
|
983
|
+
"type":"boolean",
|
|
984
|
+
"default":false
|
|
985
|
+
},
|
|
986
|
+
"locationHostSuffixAllowlist":{
|
|
987
|
+
"type":"array",
|
|
988
|
+
"items":{
|
|
989
|
+
"type":"string",
|
|
990
|
+
"minLength":1
|
|
991
|
+
},
|
|
992
|
+
"description":"Location header URL must contain one of these substrings (case-insensitive) before an unauthenticated follow-up GET."
|
|
993
|
+
}
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
"followNestedJsonStringUrl":{
|
|
997
|
+
"type":"object",
|
|
998
|
+
"additionalProperties":false,
|
|
999
|
+
"properties":{
|
|
1000
|
+
"enabled":{
|
|
1001
|
+
"type":"boolean",
|
|
1002
|
+
"default":false
|
|
1003
|
+
},
|
|
1004
|
+
"jsonKeys":{
|
|
1005
|
+
"type":"array",
|
|
1006
|
+
"items":{
|
|
1007
|
+
"type":"string",
|
|
1008
|
+
"minLength":1
|
|
1009
|
+
},
|
|
1010
|
+
"description":"JSON object key names searched depth-first for a non-empty string URL."
|
|
1011
|
+
},
|
|
1012
|
+
"targetUrlHostSuffixAllowlist":{
|
|
1013
|
+
"type":"array",
|
|
1014
|
+
"items":{
|
|
1015
|
+
"type":"string",
|
|
1016
|
+
"minLength":1
|
|
1017
|
+
},
|
|
1018
|
+
"description":"Discovered URL must contain one of these substrings before an unauthenticated follow-up GET."
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
},
|
|
1022
|
+
"followNativeHttpRedirect302":{
|
|
1023
|
+
"type":"object",
|
|
1024
|
+
"additionalProperties":false,
|
|
1025
|
+
"properties":{
|
|
1026
|
+
"enabled":{
|
|
1027
|
+
"type":"boolean",
|
|
1028
|
+
"default":false
|
|
1029
|
+
},
|
|
1030
|
+
"locationHostSuffixAllowlist":{
|
|
1031
|
+
"type":"array",
|
|
1032
|
+
"items":{
|
|
1033
|
+
"type":"string",
|
|
1034
|
+
"minLength":1
|
|
1035
|
+
},
|
|
1036
|
+
"description":"Native httpx 302 Location URL must contain one of these substrings before follow-up GET."
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
},
|
|
953
1042
|
"metadataSchemaNode":{
|
|
954
1043
|
"type":"object",
|
|
955
1044
|
"description":"Strict supported subset of JSON Schema for metadataSchema.",
|
|
@@ -1829,6 +1918,9 @@
|
|
|
1829
1918
|
"additionalProperties":{
|
|
1830
1919
|
"type":"string"
|
|
1831
1920
|
}
|
|
1921
|
+
},
|
|
1922
|
+
"httpResponseNormalization":{
|
|
1923
|
+
"$ref":"#/$defs/httpResponseNormalization"
|
|
1832
1924
|
}
|
|
1833
1925
|
},
|
|
1834
1926
|
"allOf":[
|
|
@@ -11,8 +11,7 @@
|
|
|
11
11
|
{ "cliFlag": "--timeout <ms>", "requestField": null, "note": "Client aggregate HTTP budget (POST + polls)" },
|
|
12
12
|
{ "cliFlag": "--debug [level]", "requestField": "includeDebug", "default": false, "note": "summary|full|raw affects TTY appendix only; any presence sets includeDebug" },
|
|
13
13
|
{ "cliFlag": "--no-async", "requestField": "asyncRun", "note": "When true on CLI, omit asyncRun or set false; sync-only POST" },
|
|
14
|
-
{ "cliFlag": "--
|
|
15
|
-
{ "cliFlag": "--record-id", "requestField": "e2eOptions.recordId", "runType": "e2e" },
|
|
14
|
+
{ "cliFlag": "--no-run-scenarios", "requestField": "e2eOptions.runScenarios", "runType": "e2e" },
|
|
16
15
|
{ "cliFlag": "--no-cleanup", "requestField": "e2eOptions.cleanup", "runType": "e2e" },
|
|
17
16
|
{ "cliFlag": "--primary-key-value", "requestField": "e2eOptions.primaryKeyValue", "runType": "e2e" },
|
|
18
17
|
{ "cliFlag": "--capability <key>", "requestField": "e2eOptions.capabilityKeys", "runType": "e2e", "note": "Single key forwarded as capabilityKeys array in request body when set" },
|
|
@@ -7,12 +7,12 @@
|
|
|
7
7
|
"key": "document-storage-schema",
|
|
8
8
|
"name": "Document Storage Configuration Schema",
|
|
9
9
|
"description": "JSON schema for validating document storage configurations",
|
|
10
|
-
"version": "1.
|
|
10
|
+
"version": "1.7.0",
|
|
11
11
|
"type": "schema",
|
|
12
12
|
"category": "document-storage",
|
|
13
13
|
"author": "AI Fabrix Team",
|
|
14
14
|
"createdAt": "2026-01-02T00:00:00Z",
|
|
15
|
-
"updatedAt": "2026-
|
|
15
|
+
"updatedAt": "2026-05-01T00:00:00Z",
|
|
16
16
|
"compatibility": {
|
|
17
17
|
"minVersion": "1.0.0",
|
|
18
18
|
"maxVersion": "2.0.0",
|
|
@@ -71,6 +71,38 @@
|
|
|
71
71
|
"Added optional parameterLookupCoalesceNestedItemScope (boolean, default true) for manifest-controlled binary parameter lookup enrichment"
|
|
72
72
|
],
|
|
73
73
|
"breaking": false
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"version": "1.4.0",
|
|
77
|
+
"date": "2026-04-26T00:00:00Z",
|
|
78
|
+
"changes": [
|
|
79
|
+
"Added optional maxBinaryFetchesPerSync (integer >= 1) to cap binary fetch+store operations per sync run"
|
|
80
|
+
],
|
|
81
|
+
"breaking": false
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"version": "1.5.0",
|
|
85
|
+
"date": "2026-04-27T00:00:00Z",
|
|
86
|
+
"changes": [
|
|
87
|
+
"ingestAfterSync: post-sync chunk+embed no longer waits on trust (eligibility/schema gates unchanged)"
|
|
88
|
+
],
|
|
89
|
+
"breaking": false
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
"version": "1.6.0",
|
|
93
|
+
"date": "2026-04-28T00:00:00Z",
|
|
94
|
+
"changes": [
|
|
95
|
+
"Added documentStorage.changeDetection.ignoreMetadataKeys / ignoreMetadataPaths for stable contentHash when volatile metadata changes"
|
|
96
|
+
],
|
|
97
|
+
"breaking": false
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"version": "1.7.0",
|
|
101
|
+
"date": "2026-05-01T00:00:00Z",
|
|
102
|
+
"changes": [
|
|
103
|
+
"Added optional maxBinaryFetchConcurrency (integer >= 1, default 1) to bound parallel binary fetches in two-phase sync phase 3"
|
|
104
|
+
],
|
|
105
|
+
"breaking": false
|
|
74
106
|
}
|
|
75
107
|
]
|
|
76
108
|
},
|
|
@@ -95,7 +127,18 @@
|
|
|
95
127
|
"ingestAfterSync": {
|
|
96
128
|
"type": "boolean",
|
|
97
129
|
"default": false,
|
|
98
|
-
"description": "When true, chunk and embed each document after store during sync
|
|
130
|
+
"description": "When true, chunk and embed each document after store during sync without requiring trust promotion first; eligibility (validation/schema/dimensions) still enforced. When false, ingestion runs later."
|
|
131
|
+
},
|
|
132
|
+
"maxBinaryFetchesPerSync": {
|
|
133
|
+
"type": "integer",
|
|
134
|
+
"minimum": 1,
|
|
135
|
+
"description": "When set, caps binary fetch + store operations per sync run (metadata list may still return more rows). Optional for fast integration/E2E; omit in production for full sync."
|
|
136
|
+
},
|
|
137
|
+
"maxBinaryFetchConcurrency": {
|
|
138
|
+
"type": "integer",
|
|
139
|
+
"minimum": 1,
|
|
140
|
+
"default": 1,
|
|
141
|
+
"description": "Maximum concurrent binary CIP/HTTP fetches during two-phase sync phase 3. Default 1 (sequential). Increase cautiously; external APIs may throttle."
|
|
99
142
|
},
|
|
100
143
|
"binaryOperationRef": {
|
|
101
144
|
"type": "string",
|
|
@@ -133,6 +176,22 @@
|
|
|
133
176
|
"default": true,
|
|
134
177
|
"description": "When true, binary parameterMapping and HTTP path templates use a lookup view that merges metadata and coalesces storage-scope ids from a nested item parentReference when the row's parentReference omits them. Set false for strict manifest-only paths."
|
|
135
178
|
},
|
|
179
|
+
"jsonNestedDownloadUrlKeys": {
|
|
180
|
+
"type": "array",
|
|
181
|
+
"items": {
|
|
182
|
+
"type": "string",
|
|
183
|
+
"minLength": 1
|
|
184
|
+
},
|
|
185
|
+
"description": "Optional JSON object key names (exact match) searched depth-first when a binary GET returns JSON without bytes; requires preAuthenticatedDownloadUrlHostSuffixAllowlist. Merged into binaryOperation when using binaryOperationRef."
|
|
186
|
+
},
|
|
187
|
+
"preAuthenticatedDownloadUrlHostSuffixAllowlist": {
|
|
188
|
+
"type": "array",
|
|
189
|
+
"items": {
|
|
190
|
+
"type": "string",
|
|
191
|
+
"minLength": 1
|
|
192
|
+
},
|
|
193
|
+
"description": "Substrings the discovered follow-up URL must contain (case-insensitive) before an unauthenticated GET. Required when jsonNestedDownloadUrlKeys is set."
|
|
194
|
+
},
|
|
136
195
|
"processing": {
|
|
137
196
|
"type": "object",
|
|
138
197
|
"properties": {
|
|
@@ -219,6 +278,27 @@
|
|
|
219
278
|
}
|
|
220
279
|
},
|
|
221
280
|
"additionalProperties": false
|
|
281
|
+
},
|
|
282
|
+
"changeDetection": {
|
|
283
|
+
"type": "object",
|
|
284
|
+
"description": "Optional configuration to ignore volatile metadata keys/paths during contentHash / change detection only.",
|
|
285
|
+
"properties": {
|
|
286
|
+
"ignoreMetadataKeys": {
|
|
287
|
+
"type": "array",
|
|
288
|
+
"description": "Top-level metadata keys to ignore when computing contentHash / change detection.",
|
|
289
|
+
"items": { "type": "string", "minLength": 1 },
|
|
290
|
+
"uniqueItems": true,
|
|
291
|
+
"default": []
|
|
292
|
+
},
|
|
293
|
+
"ignoreMetadataPaths": {
|
|
294
|
+
"type": "array",
|
|
295
|
+
"description": "Optional dot-path patterns to ignore (e.g. 'analytics.*', 'versions').",
|
|
296
|
+
"items": { "type": "string", "minLength": 1 },
|
|
297
|
+
"uniqueItems": true,
|
|
298
|
+
"default": []
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
"additionalProperties": false
|
|
222
302
|
}
|
|
223
303
|
},
|
|
224
304
|
"additionalProperties": false
|
|
@@ -113,6 +113,43 @@ function resolveConfigurationValues(configArray, envMap, secrets, systemKey) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
+
/**
|
|
117
|
+
* Collects `configuration[]` entry names with `location: "variable"` whose values look
|
|
118
|
+
* resolved for publish (literal strings: no `{{`, not `kv://`, non-empty). Used after
|
|
119
|
+
* `resolveConfigurationValues` mutates the upload payload.
|
|
120
|
+
*
|
|
121
|
+
* @param {{ application?: { configuration?: unknown[] }, dataSources?: unknown[] }} payload - Pipeline upload payload
|
|
122
|
+
* @returns {string[]} Unique names in encounter order (application first, then dataSources)
|
|
123
|
+
*/
|
|
124
|
+
function collectResolvedVariableConfigurationNames(payload) {
|
|
125
|
+
const out = [];
|
|
126
|
+
const seen = new Set();
|
|
127
|
+
|
|
128
|
+
function consider(arr) {
|
|
129
|
+
if (!Array.isArray(arr)) return;
|
|
130
|
+
for (const item of arr) {
|
|
131
|
+
if (!item || typeof item !== 'object') continue;
|
|
132
|
+
if (String(item.location || '').toLowerCase() !== 'variable') continue;
|
|
133
|
+
const name = item.name && String(item.name).trim();
|
|
134
|
+
if (!name || seen.has(name)) continue;
|
|
135
|
+
const val = item.value;
|
|
136
|
+
if (typeof val !== 'string') continue;
|
|
137
|
+
const trimmed = val.trim();
|
|
138
|
+
if (!trimmed) continue;
|
|
139
|
+
if (trimmed.startsWith('kv://')) continue;
|
|
140
|
+
if (trimmed.includes('{{')) continue;
|
|
141
|
+
seen.add(name);
|
|
142
|
+
out.push(name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
consider(payload?.application?.configuration);
|
|
147
|
+
for (const ds of payload?.dataSources || []) {
|
|
148
|
+
consider(ds?.configuration);
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
|
|
116
153
|
/**
|
|
117
154
|
* Returns the set of variable names (keys) defined in env.template content.
|
|
118
155
|
*
|
|
@@ -175,6 +212,7 @@ async function retemplateConfigurationForDownload(systemKey, configArray) {
|
|
|
175
212
|
module.exports = {
|
|
176
213
|
buildResolvedEnvMapForIntegration,
|
|
177
214
|
resolveConfigurationValues,
|
|
215
|
+
collectResolvedVariableConfigurationNames,
|
|
178
216
|
getEnvTemplateVariableNames,
|
|
179
217
|
retemplateConfigurationFromEnvTemplate,
|
|
180
218
|
retemplateConfigurationForDownload,
|
|
@@ -17,11 +17,12 @@ const { discoverDataplaneUrl } = require('../commands/wizard-dataplane');
|
|
|
17
17
|
* @param {string} controllerUrl - Controller URL
|
|
18
18
|
* @param {string} environment - Environment key
|
|
19
19
|
* @param {Object} authConfig - Authentication configuration
|
|
20
|
+
* @param {{ silent?: boolean }} [opts] - Passed to discoverDataplaneUrl
|
|
20
21
|
* @returns {Promise<string>} Resolved dataplane URL
|
|
21
22
|
* @throws {Error} If dataplane URL cannot be resolved
|
|
22
23
|
*/
|
|
23
|
-
async function resolveDataplaneUrl(controllerUrl, environment, authConfig) {
|
|
24
|
-
return await discoverDataplaneUrl(controllerUrl, environment, authConfig);
|
|
24
|
+
async function resolveDataplaneUrl(controllerUrl, environment, authConfig, opts = {}) {
|
|
25
|
+
return await discoverDataplaneUrl(controllerUrl, environment, authConfig, opts);
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
module.exports = {
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Capacity scenario outcome lines for DatasourceTestRun TTY (shared by header + debug appendix).
|
|
3
|
+
* @author AI Fabrix Team
|
|
4
|
+
* @version 2.0.0
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
'use strict';
|
|
8
|
+
|
|
9
|
+
const chalk = require('chalk');
|
|
10
|
+
const { successGlyph, failureGlyph } = require('./cli-test-layout-chalk');
|
|
11
|
+
const {
|
|
12
|
+
getCipCapacityDisplayConfig,
|
|
13
|
+
standardOperationRank,
|
|
14
|
+
parseCapacityDetailKey
|
|
15
|
+
} = require('./load-cip-capacity-display-config');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @param {string} op
|
|
19
|
+
* @returns {string}
|
|
20
|
+
*/
|
|
21
|
+
function formatCapacityOperationLabel(op) {
|
|
22
|
+
const { aliases } = getCipCapacityDisplayConfig();
|
|
23
|
+
return (aliases && aliases[op]) || op;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @param {Object} envelope
|
|
28
|
+
* @returns {object|null}
|
|
29
|
+
*/
|
|
30
|
+
function findCapacityStep(envelope) {
|
|
31
|
+
const dbg = envelope && envelope.debug;
|
|
32
|
+
const e2e = dbg && dbg.e2eAsyncDebug;
|
|
33
|
+
const stepDebug = e2e && Array.isArray(e2e.stepDebug) ? e2e.stepDebug : [];
|
|
34
|
+
return stepDebug.find(s => s && String(s.name) === 'capacity') || null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* @param {object[]} rows
|
|
39
|
+
* @param {string} datasourceKey
|
|
40
|
+
* @returns {object[]}
|
|
41
|
+
*/
|
|
42
|
+
function filterCapacityDatasourceRows(rows, datasourceKey) {
|
|
43
|
+
if (!datasourceKey) return rows;
|
|
44
|
+
const matched = rows.filter(r => r && String(r.key) === datasourceKey);
|
|
45
|
+
return matched.length ? matched : rows;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @param {object[]} dsRows
|
|
50
|
+
* @returns {Map<string, { ok: boolean, error: string, minIndex: number }>}
|
|
51
|
+
*/
|
|
52
|
+
function mergeCapacityDetailsByOp(dsRows) {
|
|
53
|
+
/** @type {Map<string, { ok: boolean, error: string, minIndex: number }>} */
|
|
54
|
+
const byOp = new Map();
|
|
55
|
+
for (const ds of dsRows) {
|
|
56
|
+
const details = ds && Array.isArray(ds.capabilityDetails) ? ds.capabilityDetails : [];
|
|
57
|
+
for (const row of details) {
|
|
58
|
+
if (!row || row.key === undefined || row.key === null) continue;
|
|
59
|
+
const parsed = parseCapacityDetailKey(String(row.key));
|
|
60
|
+
if (!parsed) continue;
|
|
61
|
+
const { op, index } = parsed;
|
|
62
|
+
const ok = row.success !== false && !row.error;
|
|
63
|
+
const err = row.error ? String(row.error) : '';
|
|
64
|
+
const prev = byOp.get(op);
|
|
65
|
+
if (!prev) {
|
|
66
|
+
byOp.set(op, { ok, error: ok ? '' : err, minIndex: index });
|
|
67
|
+
} else {
|
|
68
|
+
byOp.set(op, {
|
|
69
|
+
ok: prev.ok && ok,
|
|
70
|
+
error: prev.error || err,
|
|
71
|
+
minIndex: Math.min(prev.minIndex, index)
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return byOp;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @param {string[]} standardOrder
|
|
81
|
+
* @param {Map<string, { minIndex: number }>} byOp
|
|
82
|
+
* @returns {(a: string, b: string) => number}
|
|
83
|
+
*/
|
|
84
|
+
function capacityOpComparator(standardOrder, byOp) {
|
|
85
|
+
return (a, b) => {
|
|
86
|
+
const ia = byOp.get(a).minIndex;
|
|
87
|
+
const ib = byOp.get(b).minIndex;
|
|
88
|
+
if (ia !== ib) return ia - ib;
|
|
89
|
+
const ra = standardOperationRank(standardOrder, a);
|
|
90
|
+
const rb = standardOperationRank(standardOrder, b);
|
|
91
|
+
if (ra !== rb) return ra - rb;
|
|
92
|
+
return a.localeCompare(b);
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @param {string[]} lines
|
|
98
|
+
* @param {Map<string, { ok: boolean, error: string }>} byOp
|
|
99
|
+
* @param {string[]} opsSorted
|
|
100
|
+
*/
|
|
101
|
+
function appendCapacityOperationsLines(lines, byOp, opsSorted) {
|
|
102
|
+
lines.push('');
|
|
103
|
+
lines.push(chalk.blue.bold('Capacity operations:'));
|
|
104
|
+
for (const op of opsSorted) {
|
|
105
|
+
const row = byOp.get(op);
|
|
106
|
+
const label = formatCapacityOperationLabel(op);
|
|
107
|
+
const sym = row.ok ? successGlyph() : failureGlyph();
|
|
108
|
+
const tail = row.ok ? '' : chalk.red(` — ${row.error || 'failed'}`);
|
|
109
|
+
lines.push(` ${sym} ${chalk.white(label)}${tail}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* List capacity scenario outcomes from the capacity step (order: scenario index `#`, then schema op order).
|
|
115
|
+
* @param {string[]} lines
|
|
116
|
+
* @param {Object} envelope
|
|
117
|
+
*/
|
|
118
|
+
function pushCapacityOperationsSummaryLines(lines, envelope) {
|
|
119
|
+
const capStep = findCapacityStep(envelope);
|
|
120
|
+
if (!capStep || !capStep.evidence || !Array.isArray(capStep.evidence.datasources)) return;
|
|
121
|
+
|
|
122
|
+
const dk =
|
|
123
|
+
envelope && envelope.datasourceKey !== undefined && envelope.datasourceKey !== null
|
|
124
|
+
? String(envelope.datasourceKey)
|
|
125
|
+
: '';
|
|
126
|
+
const dsRows = filterCapacityDatasourceRows(capStep.evidence.datasources, dk);
|
|
127
|
+
const byOp = mergeCapacityDetailsByOp(dsRows);
|
|
128
|
+
if (!byOp.size) return;
|
|
129
|
+
|
|
130
|
+
const { standardOrder } = getCipCapacityDisplayConfig();
|
|
131
|
+
const opsSorted = Array.from(byOp.keys()).sort(capacityOpComparator(standardOrder, byOp));
|
|
132
|
+
appendCapacityOperationsLines(lines, byOp, opsSorted);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @param {string} capacityKey
|
|
137
|
+
* @returns {string|null}
|
|
138
|
+
*/
|
|
139
|
+
function parseCapacityScenarioOp(capacityKey) {
|
|
140
|
+
const p = parseCapacityDetailKey(String(capacityKey));
|
|
141
|
+
return p ? p.op : null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
module.exports = {
|
|
145
|
+
pushCapacityOperationsSummaryLines,
|
|
146
|
+
formatCapacityOperationLabel,
|
|
147
|
+
parseCapacityScenarioOp,
|
|
148
|
+
parseCapacityDetailKey
|
|
149
|
+
};
|