@contrail/cli 3.4.10 → 3.4.11-alpha.11e1d43
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/README.md +1 -1
- package/dist/templates/typescript/package-lock.json +7756 -10815
- package/dist/templates/typescript/package.json +1 -1
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.d.ts +6 -0
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.js +31 -0
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.spec.d.ts +1 -0
- package/node_modules/@contrail/loader/lib/common/chunk-by-url-length.spec.js +70 -0
- package/node_modules/@contrail/loader/lib/common/data-transformer-functions.d.ts +9 -1
- package/node_modules/@contrail/loader/lib/common/data-transformer-functions.js +53 -8
- package/node_modules/@contrail/loader/lib/common/data-transformer.spec.js +128 -0
- package/node_modules/@contrail/loader/lib/common/entities-helper.js +2 -1
- package/node_modules/@contrail/loader/lib/constants.d.ts +2 -0
- package/node_modules/@contrail/loader/lib/constants.js +3 -1
- package/node_modules/@contrail/loader/lib/entities-v2/entities-helper.js +2 -1
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.js +2 -2
- package/node_modules/@contrail/loader/lib/entities-v2/entity-processor-v2.spec.js +8 -10
- package/node_modules/@contrail/loader/lib/entities-v2/file-preprocessor-v2.js +2 -1
- package/node_modules/@contrail/loader/lib/entities-v2/linesheet-v2/item-helper.js +2 -1
- package/node_modules/@contrail/loader/lib/entity-processor.js +2 -2
- package/node_modules/@contrail/loader/lib/entity-processor.spec.js +8 -10
- package/node_modules/@contrail/loader/lib/pipeline/item-execute-helpers.js +2 -1
- package/node_modules/@contrail/loader/lib/pipeline/project-item-execute-helpers.js +3 -2
- package/node_modules/@contrail/loader/lib/pipeline/transform.js +32 -6
- package/node_modules/@contrail/loader/lib/pipeline/transform.spec.js +64 -1
- package/node_modules/@contrail/loader/package.json +1 -1
- package/oclif.manifest.json +1 -1
- package/package.json +2 -2
|
@@ -6,7 +6,7 @@ const entity_builder_helpers_1 = require("./common/entity-builder-helpers");
|
|
|
6
6
|
const types_1 = require("@contrail/types");
|
|
7
7
|
const entity_types_1 = require("@contrail/entity-types");
|
|
8
8
|
const processor_registry_1 = require("./processor-registry");
|
|
9
|
-
const
|
|
9
|
+
const chunk_by_url_length_1 = require("./common/chunk-by-url-length");
|
|
10
10
|
const util_1 = require("./common/util");
|
|
11
11
|
const constants_1 = require("./constants");
|
|
12
12
|
jest.mock('./common/entity-builder-helpers');
|
|
@@ -14,9 +14,7 @@ jest.mock('./processor-registry');
|
|
|
14
14
|
jest.mock('@contrail/entity-types');
|
|
15
15
|
jest.mock('./common/entities-helper');
|
|
16
16
|
jest.mock('./common/type-helper');
|
|
17
|
-
jest.mock('
|
|
18
|
-
chunk: jest.fn(),
|
|
19
|
-
}));
|
|
17
|
+
jest.mock('./common/chunk-by-url-length');
|
|
20
18
|
describe('EntityProcessor', () => {
|
|
21
19
|
const mockTypesByPath = {
|
|
22
20
|
color: {
|
|
@@ -203,7 +201,7 @@ describe('EntityProcessor', () => {
|
|
|
203
201
|
['1', '2'],
|
|
204
202
|
['3', '4'],
|
|
205
203
|
];
|
|
206
|
-
|
|
204
|
+
chunk_by_url_length_1.chunkByUrlLength.mockReturnValue(chunks);
|
|
207
205
|
const mockEntities = [
|
|
208
206
|
{ federatedId: '1', name: 'Entity 1' },
|
|
209
207
|
{ federatedId: '2', name: 'Entity 2' },
|
|
@@ -214,12 +212,12 @@ describe('EntityProcessor', () => {
|
|
|
214
212
|
'1': { federatedId: '1', name: 'Entity 1' },
|
|
215
213
|
'2': { federatedId: '2', name: 'Entity 2' },
|
|
216
214
|
});
|
|
217
|
-
expect(
|
|
215
|
+
expect(chunk_by_url_length_1.chunkByUrlLength).toHaveBeenCalledWith(federatedIds);
|
|
218
216
|
expect(entities_helper_1.retryOnTimeout).toHaveBeenCalledTimes(2);
|
|
219
217
|
});
|
|
220
218
|
it('should handle empty federatedIds array', async () => {
|
|
221
219
|
const federatedIds = [];
|
|
222
|
-
|
|
220
|
+
chunk_by_url_length_1.chunkByUrlLength.mockReturnValue([]);
|
|
223
221
|
const result = await entity_processor_1.EntityProcessor.fetchCurrentEntities(client, entity_types_1.EntityType.COLOR, federatedIds);
|
|
224
222
|
expect(result).toEqual({});
|
|
225
223
|
expect(entities_helper_1.retryOnTimeout).not.toHaveBeenCalled();
|
|
@@ -227,7 +225,7 @@ describe('EntityProcessor', () => {
|
|
|
227
225
|
it('should handle API errors and rethrow', async () => {
|
|
228
226
|
const federatedIds = ['1'];
|
|
229
227
|
const chunks = [['1']];
|
|
230
|
-
|
|
228
|
+
chunk_by_url_length_1.chunkByUrlLength.mockReturnValue(chunks);
|
|
231
229
|
const error = new Error('API Error');
|
|
232
230
|
entities_helper_1.retryOnTimeout.mockRejectedValue(error);
|
|
233
231
|
await expect(entity_processor_1.EntityProcessor.fetchCurrentEntities(client, entity_types_1.EntityType.COLOR, federatedIds)).rejects.toThrow('API Error');
|
|
@@ -236,7 +234,7 @@ describe('EntityProcessor', () => {
|
|
|
236
234
|
it('should handle empty response from API', async () => {
|
|
237
235
|
const federatedIds = ['1'];
|
|
238
236
|
const chunks = [['1']];
|
|
239
|
-
|
|
237
|
+
chunk_by_url_length_1.chunkByUrlLength.mockReturnValue(chunks);
|
|
240
238
|
entities_helper_1.retryOnTimeout.mockResolvedValue([]);
|
|
241
239
|
const result = await entity_processor_1.EntityProcessor.fetchCurrentEntities(client, entity_types_1.EntityType.COLOR, federatedIds);
|
|
242
240
|
expect(result).toEqual({});
|
|
@@ -248,7 +246,7 @@ describe('EntityProcessor', () => {
|
|
|
248
246
|
['1', '2'],
|
|
249
247
|
['3', '4'],
|
|
250
248
|
];
|
|
251
|
-
|
|
249
|
+
chunk_by_url_length_1.chunkByUrlLength.mockReturnValue(chunks);
|
|
252
250
|
const mockEntities1 = [
|
|
253
251
|
{ federatedId: '1', name: 'Entity 1' },
|
|
254
252
|
{ federatedId: '2', name: 'Entity 2' },
|
|
@@ -4,6 +4,7 @@ exports.executeItemEntities = exports.previewItemEntities = exports.splitIntoFam
|
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const util_1 = require("@contrail/util");
|
|
6
6
|
const lodash_1 = require("lodash");
|
|
7
|
+
const chunk_by_url_length_1 = require("../common/chunk-by-url-length");
|
|
7
8
|
const entities_helper_1 = require("../entities-v2/entities-helper");
|
|
8
9
|
const type_helper_1 = require("../common/type-helper");
|
|
9
10
|
const pLimit = require('p-limit');
|
|
@@ -461,7 +462,7 @@ async function batchUpdateEntities(client, entities, entityName, batchSize, limi
|
|
|
461
462
|
return { updated, failures };
|
|
462
463
|
}
|
|
463
464
|
async function refreshEntityCache(client, federatedIds, cache) {
|
|
464
|
-
const chunks = (0,
|
|
465
|
+
const chunks = (0, chunk_by_url_length_1.chunkByUrlLength)(federatedIds);
|
|
465
466
|
const pLimitFetch = pLimit(5);
|
|
466
467
|
const promises = chunks.map((batch) => pLimitFetch(async () => {
|
|
467
468
|
try {
|
|
@@ -4,6 +4,7 @@ exports.applyAddedFromSource = exports.executeProjectItemEntities = exports.prev
|
|
|
4
4
|
const types_1 = require("./types");
|
|
5
5
|
const util_1 = require("@contrail/util");
|
|
6
6
|
const lodash_1 = require("lodash");
|
|
7
|
+
const chunk_by_url_length_1 = require("../common/chunk-by-url-length");
|
|
7
8
|
const entities_helper_1 = require("../entities-v2/entities-helper");
|
|
8
9
|
const type_helper_1 = require("../common/type-helper");
|
|
9
10
|
const item_execute_helpers_1 = require("./item-execute-helpers");
|
|
@@ -492,7 +493,7 @@ async function resolveItemsByFederatedId(client, incomingEntities, maxRetries) {
|
|
|
492
493
|
federatedIds.add(entity.itemOptionFederatedId);
|
|
493
494
|
}
|
|
494
495
|
const result = {};
|
|
495
|
-
const chunks = (0,
|
|
496
|
+
const chunks = (0, chunk_by_url_length_1.chunkByUrlLength)(Array.from(federatedIds));
|
|
496
497
|
const limit = pLimit(5);
|
|
497
498
|
const promises = chunks.map((batch) => limit(async () => {
|
|
498
499
|
try {
|
|
@@ -527,7 +528,7 @@ async function fetchCurrentProjectItemsByItemId(client, projectId, itemIds, maxR
|
|
|
527
528
|
const result = {};
|
|
528
529
|
if (!itemIds.length)
|
|
529
530
|
return result;
|
|
530
|
-
const chunks = (0,
|
|
531
|
+
const chunks = (0, chunk_by_url_length_1.chunkByUrlLength)(itemIds);
|
|
531
532
|
const limit = pLimit(5);
|
|
532
533
|
const promises = chunks.map((batch) => limit(async () => {
|
|
533
534
|
try {
|
|
@@ -192,10 +192,10 @@ function analyzeColumns(rows, typePropertyMaps, config) {
|
|
|
192
192
|
if (!rows?.length)
|
|
193
193
|
return { columns: [], unmappedTypeProperties: [] };
|
|
194
194
|
const entityTypes = (0, types_2.loadTypeToEntityTypes)(config.loadType);
|
|
195
|
-
const { typePropertiesBySlug, typePropertiesByLabel } = typePropertyMaps;
|
|
195
|
+
const { typePropertiesBySlug, typePropertiesByLabel, typePathStateBySlug } = typePropertyMaps;
|
|
196
196
|
const optionSetUsingTypePropertiesBySlug = typePropertyMaps.optionSetUsingTypePropertiesBySlug;
|
|
197
197
|
const csvHeaders = extractUniqueHeaders(rows);
|
|
198
|
-
const columns = csvHeaders.map((header) => classifyColumn(header, typePropertiesBySlug, typePropertiesByLabel, optionSetUsingTypePropertiesBySlug, entityTypes));
|
|
198
|
+
const columns = csvHeaders.map((header) => classifyColumn(header, typePropertiesBySlug, typePropertiesByLabel, optionSetUsingTypePropertiesBySlug, entityTypes, typePathStateBySlug));
|
|
199
199
|
const coveredSlugs = new Set();
|
|
200
200
|
for (const column of columns) {
|
|
201
201
|
if (column.matchedSlug) {
|
|
@@ -220,7 +220,15 @@ function analyzeColumns(rows, typePropertyMaps, config) {
|
|
|
220
220
|
}
|
|
221
221
|
}
|
|
222
222
|
const unmappedTypeProperties = Object.entries(typePropertiesBySlug)
|
|
223
|
-
.filter(([slug, prop]) =>
|
|
223
|
+
.filter(([slug, prop]) => {
|
|
224
|
+
const trimmedSlug = slug.trim();
|
|
225
|
+
if (coveredSlugs.has(trimmedSlug))
|
|
226
|
+
return false;
|
|
227
|
+
if (typePathStateBySlug) {
|
|
228
|
+
return !isArchivedAcrossAllSubtypes(trimmedSlug, typePathStateBySlug);
|
|
229
|
+
}
|
|
230
|
+
return !prop.isArchived;
|
|
231
|
+
})
|
|
224
232
|
.map(([slug, prop]) => ({
|
|
225
233
|
slug: slug.trim(),
|
|
226
234
|
label: prop.label,
|
|
@@ -243,7 +251,7 @@ function extractUniqueHeaders(rows) {
|
|
|
243
251
|
}
|
|
244
252
|
return headers;
|
|
245
253
|
}
|
|
246
|
-
function classifyColumn(header, typePropertiesBySlug, typePropertiesByLabel, optionSetProps, entityTypes) {
|
|
254
|
+
function classifyColumn(header, typePropertiesBySlug, typePropertiesByLabel, optionSetProps, entityTypes, typePathStateBySlug) {
|
|
247
255
|
const isItemLoad = entityTypes.includes(types_1.EntityType.ITEM) || entityTypes.includes(types_1.EntityType.PROJECT_ITEM);
|
|
248
256
|
const isEntityTypeSystemProp = entityTypes.some((et) => ENTITY_TYPE_SYSTEM_PROPERTIES[et]?.has(header));
|
|
249
257
|
const isSystemProp = SYSTEM_PROPERTIES.has(header) || isEntityTypeSystemProp;
|
|
@@ -253,7 +261,14 @@ function classifyColumn(header, typePropertiesBySlug, typePropertiesByLabel, opt
|
|
|
253
261
|
const baseSlugMatch = baseName !== header ? typePropertiesBySlug[baseName] : undefined;
|
|
254
262
|
const matchedProp = slugMatch || labelMatch || baseSlugMatch;
|
|
255
263
|
const isMapped = !!matchedProp || isSystemProp;
|
|
256
|
-
|
|
264
|
+
let isArchived;
|
|
265
|
+
if (matchedProp && typePathStateBySlug) {
|
|
266
|
+
const matchedSlug = (matchedProp.slug || '').trim();
|
|
267
|
+
isArchived = isArchivedAcrossAllSubtypes(matchedSlug, typePathStateBySlug);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
isArchived = matchedProp?.isArchived === true;
|
|
271
|
+
}
|
|
257
272
|
const hasOptionSet = !!(optionSetProps[header] || optionSetProps[baseName]);
|
|
258
273
|
let isRequired;
|
|
259
274
|
let requiredNote;
|
|
@@ -292,6 +307,16 @@ function stripLevelSuffix(name) {
|
|
|
292
307
|
return name.slice(0, -6);
|
|
293
308
|
return name;
|
|
294
309
|
}
|
|
310
|
+
function isArchivedAcrossAllSubtypes(slug, typePathStateBySlug) {
|
|
311
|
+
const states = typePathStateBySlug[slug];
|
|
312
|
+
if (!states || states.size === 0)
|
|
313
|
+
return false;
|
|
314
|
+
for (const state of states.values()) {
|
|
315
|
+
if (!state.isDisabled)
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
return true;
|
|
319
|
+
}
|
|
295
320
|
const SUBTYPE_ENTITY_TYPES = new Set([types_1.EntityType.ITEM, types_1.EntityType.CUSTOM_ENTITY]);
|
|
296
321
|
const SUBTYPE_PREFIX = {
|
|
297
322
|
[types_1.EntityType.ITEM]: 'item',
|
|
@@ -344,12 +369,13 @@ async function fetchTypeDefinitions(client, rows, config) {
|
|
|
344
369
|
}
|
|
345
370
|
const typeRoots = (0, types_2.entityTypesToTypeRoots)(entityTypes);
|
|
346
371
|
const reducedTypes = await (0, data_transformer_functions_1.getReducedTypes)(typeRoots, client);
|
|
347
|
-
const { typePropertiesBySlug, typePropertiesByLabel } = (0, data_transformer_functions_1.getPropertiesBySlugAndLabel)(reducedTypes);
|
|
372
|
+
const { typePropertiesBySlug, typePropertiesByLabel, typePathStateBySlug } = (0, data_transformer_functions_1.getPropertiesBySlugAndLabel)(reducedTypes);
|
|
348
373
|
const optionSetUsingTypePropertiesBySlug = (0, data_transformer_functions_1.getOptionSetsUsingTypePropertiesBySlug)(reducedTypes);
|
|
349
374
|
const typePropertyMaps = {
|
|
350
375
|
typePropertiesBySlug,
|
|
351
376
|
typePropertiesByLabel,
|
|
352
377
|
optionSetUsingTypePropertiesBySlug,
|
|
378
|
+
typePathStateBySlug,
|
|
353
379
|
};
|
|
354
380
|
const typesByPath = await (0, type_helper_1.buildTypesByPathForPipeline)(client, Array.from(typePaths));
|
|
355
381
|
return { typePropertyMaps, typesByPath, generalErrors };
|
|
@@ -49,7 +49,11 @@ describe('transform', () => {
|
|
|
49
49
|
getReducedTypesSpy = jest.spyOn(dataTransformerFunctions, 'getReducedTypes')
|
|
50
50
|
.mockResolvedValue([]);
|
|
51
51
|
getPropertiesBySlugAndLabelSpy = jest.spyOn(dataTransformerFunctions, 'getPropertiesBySlugAndLabel')
|
|
52
|
-
.mockReturnValue({
|
|
52
|
+
.mockReturnValue({
|
|
53
|
+
typePropertiesBySlug: {},
|
|
54
|
+
typePropertiesByLabel: {},
|
|
55
|
+
typePathStateBySlug: {},
|
|
56
|
+
});
|
|
53
57
|
getOptionSetsUsingTypePropertiesBySlugSpy = jest.spyOn(dataTransformerFunctions, 'getOptionSetsUsingTypePropertiesBySlug')
|
|
54
58
|
.mockReturnValue({});
|
|
55
59
|
});
|
|
@@ -170,6 +174,7 @@ describe('transform', () => {
|
|
|
170
174
|
active: { slug: 'active', propertyType: 'boolean' },
|
|
171
175
|
},
|
|
172
176
|
typePropertiesByLabel: {},
|
|
177
|
+
typePathStateBySlug: {},
|
|
173
178
|
});
|
|
174
179
|
const rows = [{ active: 'true', unmappedField: 'true' }];
|
|
175
180
|
const result = await (0, transform_1.transform)(mockClient, rows, baseConfig);
|
|
@@ -294,6 +299,11 @@ describe('transform', () => {
|
|
|
294
299
|
getPropertiesBySlugAndLabelSpy.mockReturnValue({
|
|
295
300
|
typePropertiesBySlug: columnAnalysisTypeMaps.typePropertiesBySlug,
|
|
296
301
|
typePropertiesByLabel: columnAnalysisTypeMaps.typePropertiesByLabel,
|
|
302
|
+
typePathStateBySlug: {
|
|
303
|
+
oldProp: new Map([['color', { isDisabled: true }]]),
|
|
304
|
+
color: new Map([['color', { isDisabled: false }]]),
|
|
305
|
+
size: new Map([['color', { isDisabled: false }]]),
|
|
306
|
+
},
|
|
297
307
|
});
|
|
298
308
|
getOptionSetsUsingTypePropertiesBySlugSpy.mockReturnValue(columnAnalysisTypeMaps.optionSetUsingTypePropertiesBySlug);
|
|
299
309
|
}
|
|
@@ -328,6 +338,59 @@ describe('transform', () => {
|
|
|
328
338
|
expect(archivedCol.isArchived).toBe(true);
|
|
329
339
|
expect(archivedCol.isMapped).toBe(true);
|
|
330
340
|
});
|
|
341
|
+
it('should not mark a column as archived when the property is active in any subtype', async () => {
|
|
342
|
+
getPropertiesBySlugAndLabelSpy.mockReturnValue({
|
|
343
|
+
typePropertiesBySlug: {
|
|
344
|
+
season: { slug: 'season', label: 'Season', propertyType: 'string', isArchived: false },
|
|
345
|
+
},
|
|
346
|
+
typePropertiesByLabel: {
|
|
347
|
+
Season: { slug: 'season', label: 'Season', propertyType: 'string', isArchived: false },
|
|
348
|
+
},
|
|
349
|
+
typePathStateBySlug: {
|
|
350
|
+
season: new Map([
|
|
351
|
+
['item:product', { isDisabled: false }],
|
|
352
|
+
['item:material', { isDisabled: true }],
|
|
353
|
+
]),
|
|
354
|
+
},
|
|
355
|
+
});
|
|
356
|
+
getOptionSetsUsingTypePropertiesBySlugSpy.mockReturnValue({});
|
|
357
|
+
const config = {
|
|
358
|
+
loadType: [types_1.LoadType.ITEM],
|
|
359
|
+
conditionalColumns: [{ toProperty: 'typePath', default: 'item:product' }],
|
|
360
|
+
};
|
|
361
|
+
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'Test', season: 'SS25' }];
|
|
362
|
+
const result = await (0, transform_1.transform)(mockClient, rows, config);
|
|
363
|
+
const seasonCol = result.columns.find((c) => c.csvHeader === 'season');
|
|
364
|
+
expect(seasonCol).toBeDefined();
|
|
365
|
+
expect(seasonCol.isArchived).toBe(false);
|
|
366
|
+
expect(seasonCol.isMapped).toBe(true);
|
|
367
|
+
});
|
|
368
|
+
it('should mark a column as archived only when archived in every subtype that defines it', async () => {
|
|
369
|
+
getPropertiesBySlugAndLabelSpy.mockReturnValue({
|
|
370
|
+
typePropertiesBySlug: {
|
|
371
|
+
legacyProp: { slug: 'legacyProp', label: 'Legacy Prop', propertyType: 'string', isArchived: true },
|
|
372
|
+
},
|
|
373
|
+
typePropertiesByLabel: {
|
|
374
|
+
'Legacy Prop': { slug: 'legacyProp', label: 'Legacy Prop', propertyType: 'string', isArchived: true },
|
|
375
|
+
},
|
|
376
|
+
typePathStateBySlug: {
|
|
377
|
+
legacyProp: new Map([
|
|
378
|
+
['item:product', { isDisabled: true }],
|
|
379
|
+
['item:material', { isDisabled: true }],
|
|
380
|
+
]),
|
|
381
|
+
},
|
|
382
|
+
});
|
|
383
|
+
getOptionSetsUsingTypePropertiesBySlugSpy.mockReturnValue({});
|
|
384
|
+
const config = {
|
|
385
|
+
loadType: [types_1.LoadType.ITEM],
|
|
386
|
+
conditionalColumns: [{ toProperty: 'typePath', default: 'item:product' }],
|
|
387
|
+
};
|
|
388
|
+
const rows = [{ itemFamilyFederatedId: 'fam-1', name: 'Test', legacyProp: 'value' }];
|
|
389
|
+
const result = await (0, transform_1.transform)(mockClient, rows, config);
|
|
390
|
+
const legacyCol = result.columns.find((c) => c.csvHeader === 'legacyProp');
|
|
391
|
+
expect(legacyCol).toBeDefined();
|
|
392
|
+
expect(legacyCol.isArchived).toBe(true);
|
|
393
|
+
});
|
|
331
394
|
it('should mark system properties as required for non-item loads', async () => {
|
|
332
395
|
setupColumnAnalysisMocks();
|
|
333
396
|
const config = { loadType: [types_1.LoadType.COLOR] };
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contrail/cli",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.11-alpha.11e1d43",
|
|
4
4
|
"description": "VibeIQ's Contrail Platform CLI.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"contrail-cli": "./bin/run",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@contrail/entity-types": "^1.6.1",
|
|
34
|
-
"@contrail/loader": "^2.0.
|
|
34
|
+
"@contrail/loader": "^2.0.6",
|
|
35
35
|
"@contrail/org-config-migration": "^1.1.13",
|
|
36
36
|
"@contrail/sdk": "^1.5.5",
|
|
37
37
|
"@contrail/types": "^3.1.5",
|