@aifabrix/builder 2.44.2 → 2.44.4

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.
Files changed (62) hide show
  1. package/.npmrc.token +1 -1
  2. package/integration/roundtrip-test-local/README.md +1 -2
  3. package/integration/roundtrip-test-local2/README.md +1 -2
  4. package/jest.projects.js +12 -1
  5. package/lib/api/certificates.api.js +21 -3
  6. package/lib/api/types/certificates.types.js +1 -1
  7. package/lib/app/show-display.js +60 -16
  8. package/lib/certification/merge-certification-from-artifact.js +46 -16
  9. package/lib/certification/post-unified-cert-sync.js +13 -2
  10. package/lib/certification/sync-after-external-command.js +6 -3
  11. package/lib/certification/sync-system-certification.js +60 -14
  12. package/lib/cli/setup-app.test-commands.js +67 -35
  13. package/lib/cli/setup-utility.js +1 -1
  14. package/lib/commands/datasource-unified-test-cli.js +81 -46
  15. package/lib/commands/datasource-unified-test-cli.options.js +4 -2
  16. package/lib/commands/datasource.js +3 -31
  17. package/lib/commands/repair-datasource-keys.js +1 -1
  18. package/lib/commands/repair-datasource-openapi.js +57 -0
  19. package/lib/commands/repair-datasource.js +5 -0
  20. package/lib/commands/repair-internal.js +2 -4
  21. package/lib/commands/repair.js +1 -2
  22. package/lib/commands/test-e2e-external.js +5 -6
  23. package/lib/commands/upload.js +18 -4
  24. package/lib/commands/wizard-dataplane.js +14 -6
  25. package/lib/datasource/datasource-validate-display.js +162 -0
  26. package/lib/datasource/datasource-validate-summary.js +194 -0
  27. package/lib/datasource/test-e2e.js +65 -37
  28. package/lib/datasource/unified-validation-run-body.js +1 -2
  29. package/lib/datasource/validate.js +14 -6
  30. package/lib/external-system/test.js +12 -8
  31. package/lib/generator/external-controller-manifest.js +12 -2
  32. package/lib/schema/cip-capacity-display.fallback.json +7 -0
  33. package/lib/schema/datasource-test-run.schema.json +79 -1
  34. package/lib/schema/external-datasource.schema.json +94 -2
  35. package/lib/schema/external-system.schema.json +29 -6
  36. package/lib/schema/flag-map-validation-run.json +1 -2
  37. package/lib/schema/type/document-storage.json +83 -3
  38. package/lib/utils/configuration-env-resolver.js +38 -0
  39. package/lib/utils/dataplane-resolver.js +3 -2
  40. package/lib/utils/datasource-test-run-capacity-operations.js +149 -0
  41. package/lib/utils/datasource-test-run-debug-display.js +143 -1
  42. package/lib/utils/datasource-test-run-display.js +46 -33
  43. package/lib/utils/datasource-test-run-tty-log.js +6 -2
  44. package/lib/utils/datasource-test-run-tty-meta-lines.js +123 -0
  45. package/lib/utils/error-formatter.js +32 -2
  46. package/lib/utils/external-system-readiness-core.js +39 -0
  47. package/lib/utils/external-system-readiness-deploy-display.js +2 -3
  48. package/lib/utils/external-system-readiness-display-internals.js +3 -2
  49. package/lib/utils/external-system-system-test-tty.js +33 -9
  50. package/lib/utils/external-system-validators.js +62 -5
  51. package/lib/utils/load-cip-capacity-display-config.js +130 -0
  52. package/lib/utils/paths.js +10 -3
  53. package/lib/utils/schema-resolver.js +98 -2
  54. package/lib/utils/validation-run-poll.js +15 -4
  55. package/lib/utils/validation-run-request.js +4 -6
  56. package/lib/validation/dimension-display-helpers.js +60 -0
  57. package/lib/validation/external-manifest-validator.js +22 -15
  58. package/lib/validation/validate-display-log-helpers.js +39 -0
  59. package/lib/validation/validate-display.js +89 -83
  60. package/package.json +1 -1
  61. package/templates/applications/dataplane/env.template +2 -1
  62. package/templates/external-system/README.md.hbs +1 -2
@@ -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.1.0"
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
- "version":"2.4.5",
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-07T00:00:00Z",
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":[
@@ -7,12 +7,12 @@
7
7
  "key":"external-system-schema",
8
8
  "name":"External System Configuration Schema",
9
9
  "description":"JSON schema for validating ExternalSystem configuration files",
10
- "version":"1.6.0",
10
+ "version":"1.6.2",
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-09T00:00:00Z",
15
+ "updatedAt":"2026-04-23T00:00:00Z",
16
16
  "compatibility":{
17
17
  "minVersion":"1.4.0",
18
18
  "maxVersion":"2.0.0",
@@ -29,6 +29,20 @@
29
29
 
30
30
  ],
31
31
  "changelog":[
32
+ {
33
+ "version":"1.6.2",
34
+ "date":"2026-04-23T00:00:00Z",
35
+ "changes":[
36
+ "certification.algorithm: RS256 only (removed HS256 from enum)"
37
+ ]
38
+ },
39
+ {
40
+ "version":"1.6.1",
41
+ "date":"2026-04-22T00:00:00Z",
42
+ "changes":[
43
+ "Optional certification.publicKeyFingerprint (sha256: hex of SPKI DER) for RS256 public key verification"
44
+ ]
45
+ },
32
46
  {
33
47
  "version":"1.6.0",
34
48
  "date":"2026-04-09T00:00:00Z",
@@ -679,15 +693,24 @@
679
693
  "publicKey":{
680
694
  "type":"string",
681
695
  "minLength":1,
682
- "description":"Public verification material (SPKI PEM for RS256; dev placeholder for HS256). Private keys must never appear in config."
696
+ "description":"Public verification material (SPKI PEM for RS256). Private keys must never appear in config."
697
+ },
698
+ "publicKeyFingerprint":{
699
+ "type":"string",
700
+ "pattern":"^sha256:[0-9a-f]{64}$",
701
+ "description":"SHA-256 fingerprint of the SubjectPublicKeyInfo DER (same convention as integration certificate publicKeyFingerprint); must match embedded publicKey."
702
+ },
703
+ "contractHash":{
704
+ "type":"string",
705
+ "pattern":"^sha256:[0-9a-f]{64}$",
706
+ "description":"Optional copy of the active integration certificate contractHash (certification contract material digest) for drift checks; should match the dataplane active trusted certificate when present."
683
707
  },
684
708
  "algorithm":{
685
709
  "type":"string",
686
710
  "enum":[
687
- "RS256",
688
- "HS256"
711
+ "RS256"
689
712
  ],
690
- "description":"Signing algorithm for certificate verification (RS256 in production; HS256 only for local dev when the dataplane uses the dev HMAC signer)."
713
+ "description":"Signing algorithm for integration certificate verification (RS256 only)."
691
714
  },
692
715
  "issuer":{
693
716
  "type":"string",
@@ -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": "--test-crud", "requestField": "e2eOptions.testCrud", "runType": "e2e" },
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.3.0",
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-04-22T00:00:00Z",
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 so vector search returns hits immediately. When false, ingestion runs later (e.g. Celery task or on approval). Set true for E2E tests that validate vector step."
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
+ };