@contrail/cli 3.6.0-alpha-8-alpha.2c2e640 → 3.6.0-alpha-8-alpha.f16d816

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 CHANGED
@@ -17,7 +17,7 @@ $ npm install -g @contrail/cli
17
17
  $ contrail COMMAND
18
18
  running command...
19
19
  $ contrail (--version)
20
- @contrail/cli/3.6.0-alpha-8-alpha.2c2e640 linux-x64 node-v24.21.0
20
+ @contrail/cli/3.6.0-alpha-8-alpha.f16d816 linux-x64 node-v24.21.0
21
21
  $ contrail --help [COMMAND]
22
22
  USAGE
23
23
  $ contrail COMMAND
@@ -161,7 +161,7 @@ async function refreshCurrentUserOrg() {
161
161
  const currentUser = await (0, sdk_1.getCurrentUser)().catch((e) => {
162
162
  console.error('error getting current user', e.message);
163
163
  if (isExpiredTokenError(e)) {
164
- console.log('try frefreshing');
164
+ console.error('access token expired; attempting refresh');
165
165
  return;
166
166
  }
167
167
  throw e;
@@ -176,7 +176,7 @@ async function refreshCurrentUserOrg() {
176
176
  apiGateway: config.apiGateway,
177
177
  orgSlug: config.orgSlug,
178
178
  };
179
- console.log('fetched new access token from refresh token', newVibeAccessToken);
179
+ (0, sdk_1.setConfig)(sdk_1.Auth.config);
180
180
  }
181
181
  catch (e) {
182
182
  throw Error(`Could not get refresh token: ${e}`);
@@ -215,9 +215,11 @@ async function requestRefreshedAccessToken(vibeRefreshToken, apiGateway) {
215
215
  },
216
216
  body: JSON.stringify({ refreshToken: vibeRefreshToken }),
217
217
  });
218
- return await response.json().then((data) => {
219
- return data.accessToken;
220
- });
218
+ const data = await response.json();
219
+ if (!response.ok || !data.accessToken) {
220
+ throw new Error(`jwt_refresh returned ${response.status} with no access token`);
221
+ }
222
+ return data.accessToken;
221
223
  }
222
224
  function getVersionFromPackageJson() {
223
225
  // Get the path to the package.json file
@@ -35,7 +35,7 @@ class GetAPIKeyApp extends basecommand_1.BaseCommand {
35
35
  },
36
36
  ];
37
37
  const answers = await inquirer_1.default.prompt(questions);
38
- logger_1.default.info(`App API key: (app:${answers.appApiKey})`);
38
+ this.log(`App API key: (app:${answers.appApiKey})`);
39
39
  }
40
40
  else {
41
41
  const appFound = installedApps.find((x) => x.app.identifier === this.flags.appIdentifier);
@@ -43,7 +43,7 @@ class GetAPIKeyApp extends basecommand_1.BaseCommand {
43
43
  logger_1.default.info('You do not have such an app installed');
44
44
  return;
45
45
  }
46
- logger_1.default.info(`App API key: (app:${appFound.apiKey.apiKey})`);
46
+ this.log(`App API key: (app:${appFound.apiKey.apiKey})`);
47
47
  }
48
48
  }
49
49
  }
@@ -23,6 +23,7 @@ export default class CreateEntity extends BaseCommand {
23
23
  path: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
24
24
  };
25
25
  static strict: boolean;
26
+ init(): Promise<void>;
26
27
  run(): Promise<void>;
27
28
  }
28
29
  export type CreateSummary = {
@@ -218,8 +218,11 @@ class CreateEntity extends basecommand_1.BaseCommand {
218
218
  }),
219
219
  };
220
220
  static strict = false;
221
- async run() {
221
+ async init() {
222
222
  (0, common_1.routeConsoleLogToStderr)();
223
+ await super.init();
224
+ }
225
+ async run() {
223
226
  await (0, login_1.authUser)();
224
227
  const { flags, argv, args } = await this.parse(CreateEntity);
225
228
  const { count, dryRun: isDryRun, inputFile: inputFilename, outputFile: outputFilename, generateValues: shouldGenerateMissingValues, readableIds: shouldUseReadableIds, skipHydrateRelationships, suffix, apiVersion, } = flags;
@@ -371,8 +374,8 @@ function createEntityWithPopulatedValues(type, typeReferencesCache, objectRefere
371
374
  // Handle property specifications
372
375
  for (const [propertySlug, specifiedValue] of propertySpecificationBySlug.entries()) {
373
376
  const correspondingProperty = type.typeProperties.find((prop) => getPropertySlug(prop) === propertySlug);
374
- if (!specifiedValue) {
375
- throw new Error(`Value for property ${propertySlug} is required`);
377
+ if (specifiedValue === undefined) {
378
+ continue;
376
379
  }
377
380
  entity[propertySlug] = castValueToPropertyType(specifiedValue, correspondingProperty?.propertyType || types_1.PropertyType.String);
378
381
  }
@@ -521,6 +524,9 @@ function generateRandomDateString() {
521
524
  return new Date().toISOString();
522
525
  }
523
526
  function castValueToPropertyType(value, propertyType) {
527
+ if (Array.isArray(value) && propertyType !== types_1.PropertyType.MultiSelect) {
528
+ return value.map((element) => castValueToPropertyType(element, propertyType));
529
+ }
524
530
  switch (propertyType) {
525
531
  case types_1.PropertyType.Boolean:
526
532
  return value.toString().toLowerCase() === 'true';
@@ -553,7 +559,7 @@ async function createEntity(entityName, entity, routing = {}) {
553
559
  const skipHydrateRelationships = SHOULD_SKIP_HYDRATE_RELATIONSHIPS;
554
560
  const { suffix, apiVersion } = routing;
555
561
  if (entityName === 'assortment-item' && !suffix)
556
- return (0, entities_1.createAssortmentItem)(entity, { skipHydrateRelationships }); // special case
562
+ return (0, entities_1.createAssortmentItem)(entity, { skipHydrateRelationships, apiVersion }); // special case
557
563
  const response = await client.create({
558
564
  entityName,
559
565
  object: entity,
@@ -532,6 +532,10 @@ describe('castValueToPropertyType array coercion', () => {
532
532
  expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('slug=option slug=family'));
533
533
  consoleError.mockRestore();
534
534
  });
535
+ it('should cast each element of a repeated-key array on scalar property types', () => {
536
+ expect((0, create_1.castValueToPropertyType)(['1', '2'], types_1.PropertyType.Number)).toEqual([1, 2]);
537
+ expect((0, create_1.castValueToPropertyType)(['true', 'false'], types_1.PropertyType.Boolean)).toEqual([true, false]);
538
+ });
535
539
  it('should keep commas literal on string properties without warning', () => {
536
540
  const consoleError = jest.spyOn(console, 'error').mockImplementation(() => undefined);
537
541
  expect((0, create_1.castValueToPropertyType)('my,name', types_1.PropertyType.String)).toBe('my,name');
@@ -15,5 +15,6 @@ export default class DeleteEntity extends BaseCommand {
15
15
  ids: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
16
16
  };
17
17
  static strict: boolean;
18
+ init(): Promise<void>;
18
19
  run(): Promise<void>;
19
20
  }
@@ -51,8 +51,11 @@ class DeleteEntity extends basecommand_1.BaseCommand {
51
51
  }),
52
52
  };
53
53
  static strict = false;
54
- async run() {
54
+ async init() {
55
55
  (0, common_1.routeConsoleLogToStderr)();
56
+ await super.init();
57
+ }
58
+ async run() {
56
59
  await (0, login_1.authUser)();
57
60
  const { args, flags, argv } = await this.parse(DeleteEntity);
58
61
  const { entityName } = args;
@@ -91,8 +94,8 @@ class DeleteEntity extends basecommand_1.BaseCommand {
91
94
  console.error('deleted entities:');
92
95
  }
93
96
  this.log(JSON.stringify(response, null, 2));
94
- if (response.idsErrored.length > 0) {
95
- console.error(`${response.idsErrored.length} of ${ids.length} deletes failed.`);
97
+ if (response.failed.length > 0) {
98
+ console.error(`${response.failed.length} of ${ids.length} deletes failed.`);
96
99
  process.exitCode = 1;
97
100
  }
98
101
  }
@@ -103,54 +106,32 @@ class DeleteEntity extends basecommand_1.BaseCommand {
103
106
  }
104
107
  exports.default = DeleteEntity;
105
108
  async function deleteEntityByIds(entityName, ids, routing = {}) {
106
- const idsDeleted = new Set();
107
- const idsNotFound = new Set();
108
- const idsErrored = new Set();
109
+ const deletedIds = [];
110
+ const notFoundIds = [];
111
+ const failed = [];
109
112
  const limit = (0, p_limit_1.default)(10);
110
113
  const deletePromises = ids.map((id) => limit(() => deleteEntityById(entityName, id, routing).then((entity) => {
111
114
  if (!entity) {
112
- idsNotFound.add(id);
113
- return null;
115
+ notFoundIds.push(id);
116
+ return;
114
117
  }
115
- idsDeleted.add(id);
116
- return entity;
118
+ deletedIds.push(id);
117
119
  }, (error) => {
118
- if (error.message.includes('not found')) {
119
- idsNotFound.add(id);
120
+ if (error.message?.includes('not found')) {
121
+ notFoundIds.push(id);
120
122
  }
121
123
  else {
122
- idsErrored.add(id);
124
+ failed.push({ id, error: (0, common_1.sdkErrorMessage)(error) });
123
125
  }
124
- return null;
125
126
  })));
126
127
  await Promise.all(deletePromises);
127
- return {
128
- idsDeleted: Array.from(idsDeleted),
129
- idsNotFound: Array.from(idsNotFound),
130
- idsErrored: Array.from(idsErrored),
131
- };
128
+ return { deletedIds, notFoundIds, failed };
132
129
  }
133
130
  async function deleteEntityById(entityName, id, routing = {}) {
134
131
  const client = new sdk_1.Entities();
135
132
  if (IS_DRY_RUN) {
136
- return client.get({ entityName, id, ignore404: true }).catch(throwIfNot404);
133
+ return client.get({ entityName, id, ignore404: true });
137
134
  }
138
135
  const { suffix, apiVersion } = routing;
139
- return client
140
- .delete({ entityName, id, ignore404: true, suffix, apiVersion })
141
- .catch(throwIfNot404);
142
- }
143
- function throwIfNot404(e) {
144
- const { statusCode } = parseSDKErrorMessage(e);
145
- if (statusCode === 404) {
146
- return null;
147
- }
148
- throw e;
149
- }
150
- function parseSDKErrorMessage(e) {
151
- const parsed = JSON.parse(e.details);
152
- return {
153
- statusCode: parsed.statusCode,
154
- message: parsed.message,
155
- };
136
+ return client.delete({ entityName, id, ignore404: true, suffix, apiVersion });
156
137
  }
@@ -20,5 +20,6 @@ export default class GetEntity extends BaseCommand {
20
20
  ids: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
21
21
  };
22
22
  static strict: boolean;
23
+ init(): Promise<void>;
23
24
  run(): Promise<void>;
24
25
  }
@@ -83,8 +83,11 @@ class GetEntity extends basecommand_1.BaseCommand {
83
83
  }),
84
84
  };
85
85
  static strict = false;
86
- async run() {
86
+ async init() {
87
87
  (0, common_1.routeConsoleLogToStderr)();
88
+ await super.init();
89
+ }
90
+ async run() {
88
91
  await (0, login_1.authUser)();
89
92
  const { args, flags, argv } = await this.parse(GetEntity);
90
93
  const { typePath } = args;
@@ -224,8 +227,9 @@ async function find(entityName, options = {}) {
224
227
  queryOptions.customParams = { propertySlugs: propertySlugs.join(',') };
225
228
  }
226
229
  const payload = id ? { id, ...queryOptions } : { criteria, ...queryOptions };
227
- // a suffix names a specific sub-route, so it always goes through the plain client
228
- if ((0, batchFetch_1.canBatchFetchEntity)(entityName) && !suffix) {
230
+ // a suffix names a specific sub-route and an id names one entity; both always go
231
+ // through the plain client (batch-fetch only understands criteria)
232
+ if ((0, batchFetch_1.canBatchFetchEntity)(entityName) && !suffix && !id) {
229
233
  return (0, batchFetch_1.batchFetch)(entityName, payload);
230
234
  }
231
235
  else {
@@ -16,6 +16,7 @@ export default class UpdateEntity extends BaseCommand {
16
16
  ids: import("@oclif/core/lib/interfaces/parser").Arg<string, Record<string, unknown>>;
17
17
  };
18
18
  static strict: boolean;
19
+ init(): Promise<void>;
19
20
  run(): Promise<void>;
20
21
  }
21
22
  export type UpdateSummary = {
@@ -57,8 +57,11 @@ class UpdateEntity extends basecommand_1.BaseCommand {
57
57
  }),
58
58
  };
59
59
  static strict = false;
60
- async run() {
60
+ async init() {
61
61
  (0, common_1.routeConsoleLogToStderr)();
62
+ await super.init();
63
+ }
64
+ async run() {
62
65
  await (0, login_1.authUser)();
63
66
  const { args, argv } = await this.parse(UpdateEntity);
64
67
  const { entityName } = args;
@@ -1,10 +1,12 @@
1
1
  import { Item } from '@contrail/entity-types';
2
+ import { API_VERSION } from '@contrail/sdk';
2
3
  export declare function throwIfInvalidAssortmentId(assortmentId: string): Promise<void>;
3
4
  export declare function createAssortmentItem(assortmentItem: {
4
5
  assortmentId: string;
5
6
  itemId: string;
6
7
  [key: string]: any;
7
- }, { skipHydrateRelationships }?: {
8
- skipHydrateRelationships: boolean;
8
+ }, options?: {
9
+ skipHydrateRelationships?: boolean;
10
+ apiVersion?: API_VERSION;
9
11
  }): Promise<any>;
10
12
  export declare function findItemsNotInAssortment(assortmentId: string, count?: number): Promise<Item[]>;
@@ -15,15 +15,17 @@ async function doesAssortmentExistById(id) {
15
15
  const assortment = await client.get({ entityName: 'assortment', id });
16
16
  return !!assortment;
17
17
  }
18
- async function createAssortmentItem(assortmentItem, { skipHydrateRelationships } = { skipHydrateRelationships: false }) {
18
+ async function createAssortmentItem(assortmentItem, options = {}) {
19
19
  const client = new sdk_1.Entities();
20
20
  const { assortmentId, itemId } = assortmentItem;
21
+ const { skipHydrateRelationships = false, apiVersion } = options;
21
22
  // add item to assortment
22
23
  await client.create({
23
24
  entityName: 'assortment',
24
25
  id: assortmentId,
25
26
  relation: 'items',
26
27
  object: { itemIds: [itemId] },
28
+ apiVersion,
27
29
  });
28
30
  // Update assortment item with properties
29
31
  const updated = await client.update({
@@ -31,6 +33,7 @@ async function createAssortmentItem(assortmentItem, { skipHydrateRelationships }
31
33
  id: `${assortmentId}:${itemId}`,
32
34
  object: assortmentItem,
33
35
  skipHydrateRelationships,
36
+ apiVersion,
34
37
  });
35
38
  return updated;
36
39
  }
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "3.6.0-alpha-8-alpha.2c2e640",
2
+ "version": "3.6.0-alpha-8-alpha.f16d816",
3
3
  "commands": {
4
4
  "app:create": {
5
5
  "id": "app:create",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contrail/cli",
3
- "version": "3.6.0-alpha-8-alpha.2c2e640",
3
+ "version": "3.6.0-alpha-8-alpha.f16d816",
4
4
  "description": "VibeIQ's Contrail Platform CLI.",
5
5
  "bin": {
6
6
  "contrail-cli": "./bin/run",