@celonis/content-cli 1.5.0 → 1.7.0

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
@@ -9,10 +9,11 @@ teams and execute commands in a profile's context.
9
9
 
10
10
  1. [Getting Started](#getting-started)
11
11
  2. [About the Project](#about-the-project)
12
- 3. [Building the Project](#building-the-project)
13
- 4. [Release Process](#release-process)
14
- 5. [Contributing](#contributing)
15
- 6. [License](#license)
12
+ 3. [Building the Project](#building-and-using-the-project-locally)
13
+ 4. [Troubleshooting](#troubleshooting)
14
+ 5. [Release Process](#release-process)
15
+ 6. [Contributing](#contributing)
16
+ 7. [License](#license)
16
17
 
17
18
  ## Getting Started
18
19
 
@@ -85,16 +86,65 @@ content-cli pull package -h
85
86
  ## Building and Using the Project locally
86
87
 
87
88
  This tool is tightly connected with the Celonis Platform and all capabilities require to have access to a Celonis Platform Team.
88
- After cloning the project, the next step is to install the project dependencies. We use `yarn` as our package manager,
89
- so running `yarn install` on the project root folder should install all the necessary dependencies. After installing
90
- the project dependencies, you can run `yarn build` to build the project artifact. To use the built artifact, you can
91
- run `node content-cli.js` in the generated `dist` folder.
92
-
93
- If we want to use a specific local build of the tool globally, we can do this by:
94
- - Move to the root directory of the project.
95
- - Execute `cd dist`, to move to the `dist` directory.
96
- - Execute the `npm link` command.
97
- This will create a symbolic link in the global `node_modules` directory, allowing you to run the CLI from anywhere on your machine.
89
+
90
+ ### Prerequisites
91
+
92
+ - **Node.js** `>=18.20.5` (LTS recommended). Check with `node -v`.
93
+ - **yarn** package manager. Install with `npm install -g yarn` if not already available.
94
+
95
+ ### Build steps
96
+
97
+ ```bash
98
+ git clone https://github.com/celonis/content-cli.git
99
+ cd content-cli
100
+ yarn install
101
+ yarn build
102
+ ```
103
+
104
+ The build compiles TypeScript into the `dist/` folder and copies `package.json` there.
105
+
106
+ ### Running the built CLI
107
+
108
+ You can run the built artifact directly from the `dist` folder:
109
+
110
+ ```bash
111
+ node dist/content-cli.js -h
112
+ ```
113
+
114
+ ### Installing the local build globally
115
+
116
+ To use your local build as the global `content-cli` command:
117
+
118
+ ```bash
119
+ cd dist
120
+ npm link
121
+ ```
122
+
123
+ This creates a symbolic link in the global `node_modules` directory, allowing you to run `content-cli` from anywhere on your machine. To unlink later, run `npm unlink -g @celonis/content-cli`.
124
+
125
+ ## Troubleshooting
126
+
127
+ ### `Error: Cannot find module '...'`
128
+
129
+ If you see a `Cannot find module` error when running `content-cli`, dependencies may not be installed correctly:
130
+
131
+ - **Global install:** Try updating to the latest version: `npm install -g @celonis/content-cli@latest`.
132
+ - **Local development:** Run `yarn install` from the project root before building.
133
+
134
+ ### `content-cli: command not found`
135
+
136
+ - Ensure Node.js is installed and on your `PATH` (`node -v`).
137
+ - If installed via `npm install -g`, check that npm's global `bin` directory is in your `PATH`. You can find it with `npm bin -g`.
138
+ - If using `npm link`, make sure you ran it from the `dist/` directory (not the project root).
139
+
140
+ ### Node.js version errors
141
+
142
+ Content CLI requires Node.js `>=18.20.5`. If you see compatibility errors, upgrade your Node.js installation. We recommend using [nvm](https://github.com/nvm-sh/nvm) to manage Node.js versions:
143
+
144
+ ```bash
145
+ nvm install --lts
146
+ nvm use --lts
147
+ ```
98
148
 
99
149
  ## Release Process
100
150
 
@@ -57,6 +57,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
57
57
  });
58
58
  });
59
59
  }
60
+ findPackagesByKeysAndVersion(packageKeysWithVersion, withDependencies = false) {
61
+ return __awaiter(this, void 0, void 0, function* () {
62
+ const queryParams = new URLSearchParams();
63
+ packageKeysWithVersion.forEach(keyWithVersion => queryParams.append("packageKeysWithVersion", keyWithVersion));
64
+ queryParams.set("withDependencies", withDependencies.toString());
65
+ return this.httpClient().get(`/package-manager/api/core/packages/versions/export/list?${queryParams.toString()}`).catch(e => {
66
+ throw new logger_1.FatalError(`Problem getting packages by keys and versions: ${e}`);
67
+ });
68
+ });
69
+ }
60
70
  exportPackages(packageKeys, withDependencies) {
61
71
  return __awaiter(this, void 0, void 0, function* () {
62
72
  const queryParams = new URLSearchParams();
@@ -47,10 +47,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
47
47
  });
48
48
  });
49
49
  }
50
- findAndExportListOfActivePackages(flavors, packageKeys, withDependencies) {
50
+ findAndExportListOfPackages(flavors, packageKeys, keysByVersion, withDependencies) {
51
51
  return __awaiter(this, void 0, void 0, function* () {
52
52
  let packagesToExport;
53
- if (packageKeys.length) {
53
+ if (keysByVersion.length) {
54
+ packagesToExport = yield this.batchImportExportApi.findPackagesByKeysAndVersion(keysByVersion, withDependencies);
55
+ }
56
+ else if (packageKeys.length) {
54
57
  packagesToExport = yield this.batchImportExportApi.findActivePackagesByKeys(packageKeys, withDependencies);
55
58
  }
56
59
  else {
@@ -60,6 +63,14 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
60
63
  this.exportListOfPackages(packagesToExport);
61
64
  });
62
65
  }
66
+ listPackagesByKeysWithVersion(keysByVersion, withDependencies) {
67
+ return __awaiter(this, void 0, void 0, function* () {
68
+ const exportedPackages = yield this.batchImportExportApi.findPackagesByKeysAndVersion(keysByVersion, withDependencies);
69
+ exportedPackages.forEach(pkg => {
70
+ logger_1.logger.info(`${pkg.name} - Key: "${pkg.key}"`);
71
+ });
72
+ });
73
+ }
63
74
  batchExportPackages(packageKeys, packageKeysByVersion, withDependencies, gitBranch, unzip) {
64
75
  return __awaiter(this, void 0, void 0, function* () {
65
76
  let exportedPackagesData;
@@ -130,7 +141,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
130
141
  const variablesManifests = this.parseEntryData(configs, batch_export_import_constants_1.BatchExportImportConstants.VARIABLES_FILE_NAME);
131
142
  configs = yield this.studioService.mapSpaces(configs, studioManifests);
132
143
  const existingStudioPackages = yield this.studioPackageApi.findAllPackages();
133
- const formData = this.buildBodyForImport(configs, variablesManifests);
144
+ const formData = this.buildBodyForImport(configs, sourceToBeImported, variablesManifests);
134
145
  const postPackageImportData = yield this.batchImportExportApi.importPackages(formData, overwrite);
135
146
  yield this.studioService.processImportedPackages(configs, existingStudioPackages, studioManifests);
136
147
  if (gitBranch) {
@@ -185,8 +196,9 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
185
196
  file_service_1.fileService.writeToFileWithGivenName(JSON.stringify(packagesMetadata), filename);
186
197
  logger_1.logger.info(file_service_1.FileService.fileDownloadedMessage + filename);
187
198
  }
188
- buildBodyForImport(configs, variablesManifests) {
199
+ buildBodyForImport(configs, sourcePath, variablesManifests) {
189
200
  const formData = new FormData();
201
+ this.assertUncompressedSizeWithinLimit(configs, sourcePath);
190
202
  const readableStream = this.getReadableStream(configs);
191
203
  formData.append("file", readableStream, { filename: "configs.zip" });
192
204
  if (variablesManifests) {
@@ -196,6 +208,13 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
196
208
  }
197
209
  return formData;
198
210
  }
211
+ assertUncompressedSizeWithinLimit(configs, sourcePath) {
212
+ const MAX_ZIP_SIZE = 4 * 1024 * 1024 * 1024;
213
+ const totalUncompressedBytes = configs.getEntries().reduce((sum, entry) => sum + entry.header.size, 0);
214
+ if (totalUncompressedBytes > MAX_ZIP_SIZE) {
215
+ throw new Error(`Failed to handle zip file "${sourcePath}": uncompressed size ${(totalUncompressedBytes / (Math.pow(1024, 3))).toFixed(2)} GB exceeds the 4 GB limit.`);
216
+ }
217
+ }
199
218
  getReadableStream(configs) {
200
219
  return new stream_1.Readable({
201
220
  read() {
@@ -29,14 +29,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
29
29
  this.variableService = new variable_service_1.VariableService(context);
30
30
  this.diffService = new diff_service_1.DiffService(context);
31
31
  }
32
- listActivePackages(jsonResponse, flavors, withDependencies, packageKeys, variableValue, variableType) {
32
+ listPackages(jsonResponse, flavors, withDependencies, packageKeys, keysByVersion, variableValue, variableType) {
33
33
  return __awaiter(this, void 0, void 0, function* () {
34
34
  if (variableValue) {
35
35
  yield this.listPackagesByVariableValue(jsonResponse, flavors, variableValue, variableType);
36
36
  return;
37
37
  }
38
38
  if (jsonResponse) {
39
- yield this.batchImportExportService.findAndExportListOfActivePackages(flavors !== null && flavors !== void 0 ? flavors : [], packageKeys !== null && packageKeys !== void 0 ? packageKeys : [], withDependencies);
39
+ yield this.batchImportExportService.findAndExportListOfPackages(flavors !== null && flavors !== void 0 ? flavors : [], packageKeys !== null && packageKeys !== void 0 ? packageKeys : [], keysByVersion !== null && keysByVersion !== void 0 ? keysByVersion : [], withDependencies);
40
+ }
41
+ else if (keysByVersion) {
42
+ yield this.batchImportExportService.listPackagesByKeysWithVersion(keysByVersion, withDependencies);
40
43
  }
41
44
  else {
42
45
  yield this.batchImportExportService.listActivePackages(flavors !== null && flavors !== void 0 ? flavors : []);
@@ -31,14 +31,15 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
31
31
  register(context, configurator) {
32
32
  const configCommand = configurator.command("config");
33
33
  configCommand.command("list")
34
- .description("Command to list active packages that can be exported")
34
+ .description("Command to list packages")
35
35
  .option("--json", "Return response as json type", "")
36
36
  .option("--flavors <flavors...>", "Lists only active packages of the given flavors")
37
37
  .option("--withDependencies", "Include dependencies", "")
38
- .option("--packageKeys <packageKeys...>", "Lists only given package keys")
38
+ .option("--packageKeys <packageKeys...>", "Lists only active versions of given package keys")
39
+ .option("--keysByVersion <keysByVersion...>", "Lists packages by given key and version [packageKey.version]")
39
40
  .option("--variableValue <variableValue>", "Variable value for filtering packages by.")
40
41
  .option("--variableType <variableType>", "Variable type for filtering packages by.")
41
- .action(this.listActivePackages);
42
+ .action(this.listPackages);
42
43
  configCommand.command("export")
43
44
  .description("Command to export package configs")
44
45
  .option("--packageKeys <packageKeys...>", "Keys of packages to export. Exports the latest deployed version only")
@@ -130,9 +131,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
130
131
  .option("--params <params>", "Variable query params")
131
132
  .action(this.listAssignments);
132
133
  }
133
- listActivePackages(context, command, options) {
134
+ listPackages(context, command, options) {
134
135
  return __awaiter(this, void 0, void 0, function* () {
135
- yield new config_command_service_1.ConfigCommandService(context).listActivePackages(options.json, options.flavors, options.withDependencies, options.packageKeys, options.variableValue, options.variableType);
136
+ if (options.packageKeys && options.keysByVersion) {
137
+ throw new Error("Please provide either --packageKeys or --keysByVersion, but not both.");
138
+ }
139
+ yield new config_command_service_1.ConfigCommandService(context).listPackages(options.json, options.flavors, options.withDependencies, options.packageKeys, options.keysByVersion, options.variableValue, options.variableType);
136
140
  });
137
141
  }
138
142
  batchExportPackages(context, command, options) {
@@ -30,8 +30,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
30
30
  const homedir = os.homedir();
31
31
  // use 5 seconds buffer to avoid rare cases when accessToken is just about to expire before the command is sent
32
32
  const expiryBuffer = 5000;
33
- const deviceCodeScopes = ["studio", "package-manager", "integration.data-pools", "action-engine.projects"];
34
- const clientCredentialsScopes = ["studio", "integration.data-pools", "action-engine.projects", "package-manager"];
33
+ /** All OAuth scopes; used for both device code and client credentials. */
34
+ const OAUTH_SCOPES = ["studio", "package-manager", "integration.data-pools", "action-engine.projects"];
35
+ /** Device code fallback: try without action-engine.projects if all 4 scopes fail. */
36
+ const DEVICE_CODE_SCOPES_WITHOUT_ACTION_ENGINE = ["studio", "package-manager", "integration.data-pools"];
35
37
  class ProfileService {
36
38
  constructor() {
37
39
  this.profileContainerPath = path.resolve(homedir, ".celonis-content-cli-profiles");
@@ -165,65 +167,56 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
165
167
  }
166
168
  break;
167
169
  case profile_interface_1.ProfileType.DEVICE_CODE:
168
- try {
169
- const deviceCodeIssuer = yield openid_client_1.Issuer.discover(profile.team);
170
- const deviceCodeOAuthClient = new deviceCodeIssuer.Client({
171
- client_id: "content-cli",
172
- token_endpoint_auth_method: "none",
173
- });
174
- const deviceCodeHandle = yield deviceCodeOAuthClient.deviceAuthorization({
175
- scope: deviceCodeScopes.join(" ")
176
- });
177
- logger_1.logger.info(`Continue authorization here: ${deviceCodeHandle.verification_uri_complete}`);
178
- const deviceCodeTokenSet = yield deviceCodeHandle.poll();
179
- profile.apiToken = deviceCodeTokenSet.access_token;
180
- profile.refreshToken = deviceCodeTokenSet.refresh_token;
181
- profile.expiresAt = deviceCodeTokenSet.expires_at;
170
+ const deviceCodeIssuer = yield openid_client_1.Issuer.discover(profile.team);
171
+ const deviceCodeOAuthClient = new deviceCodeIssuer.Client({
172
+ client_id: "content-cli",
173
+ token_endpoint_auth_method: "none",
174
+ });
175
+ const deviceCodeScopeAttempts = [OAUTH_SCOPES, DEVICE_CODE_SCOPES_WITHOUT_ACTION_ENGINE];
176
+ let deviceCodeSuccess = false;
177
+ for (const scopeList of deviceCodeScopeAttempts) {
178
+ try {
179
+ const deviceCodeHandle = yield deviceCodeOAuthClient.deviceAuthorization({
180
+ scope: scopeList.join(" "),
181
+ });
182
+ logger_1.logger.info(`Continue authorization here: ${deviceCodeHandle.verification_uri_complete}`);
183
+ const deviceCodeTokenSet = yield deviceCodeHandle.poll();
184
+ profile.apiToken = deviceCodeTokenSet.access_token;
185
+ profile.refreshToken = deviceCodeTokenSet.refresh_token;
186
+ profile.expiresAt = deviceCodeTokenSet.expires_at;
187
+ deviceCodeSuccess = true;
188
+ break;
189
+ }
190
+ catch (err) {
191
+ // This scope set failed; try next or fail below
192
+ }
182
193
  }
183
- catch (err) {
184
- logger_1.logger.error(new logger_1.FatalError("The provided team is wrong."));
185
- logger_1.logger.error(err);
194
+ if (!deviceCodeSuccess) {
195
+ throw new logger_1.FatalError("Device code authorization failed. The provided team or requested scopes may be invalid.");
186
196
  }
187
197
  break;
188
198
  case profile_interface_1.ProfileType.CLIENT_CREDENTIALS:
189
199
  const clientCredentialsIssuer = yield openid_client_1.Issuer.discover(profile.team);
190
- try {
191
- // try with client secret basic
192
- const clientCredentialsOAuthClient = new clientCredentialsIssuer.Client({
193
- client_id: profile.clientId,
194
- client_secret: profile.clientSecret,
195
- token_endpoint_auth_method: profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_BASIC,
196
- });
197
- const clientCredentialsTokenSet = yield clientCredentialsOAuthClient.grant({
198
- grant_type: "client_credentials",
199
- scope: clientCredentialsScopes.join(" ")
200
- });
200
+ const basicResult = yield this.tryClientCredentialsGrant(clientCredentialsIssuer, profile, profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_BASIC);
201
+ if (basicResult) {
201
202
  profile.clientAuthenticationMethod = profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_BASIC;
202
- profile.apiToken = clientCredentialsTokenSet.access_token;
203
- profile.expiresAt = clientCredentialsTokenSet.expires_at;
203
+ profile.apiToken = basicResult.tokenSet.access_token;
204
+ profile.expiresAt = basicResult.tokenSet.expires_at;
205
+ profile.scopes = basicResult.scopes;
204
206
  }
205
- catch (e) {
206
- try {
207
- // try with client secret post
208
- const clientCredentialsOAuthClient = new clientCredentialsIssuer.Client({
209
- client_id: profile.clientId,
210
- client_secret: profile.clientSecret,
211
- token_endpoint_auth_method: profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_POST,
212
- });
213
- const clientCredentialsTokenSet = yield clientCredentialsOAuthClient.grant({
214
- grant_type: "client_credentials",
215
- scope: clientCredentialsScopes.join(" ")
216
- });
207
+ else {
208
+ const postResult = yield this.tryClientCredentialsGrant(clientCredentialsIssuer, profile, profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_POST);
209
+ if (postResult) {
217
210
  profile.clientAuthenticationMethod = profile_interface_1.ClientAuthenticationMethod.CLIENT_SECRET_POST;
218
- profile.apiToken = clientCredentialsTokenSet.access_token;
219
- profile.expiresAt = clientCredentialsTokenSet.expires_at;
211
+ profile.apiToken = postResult.tokenSet.access_token;
212
+ profile.expiresAt = postResult.tokenSet.expires_at;
213
+ profile.scopes = postResult.scopes;
220
214
  }
221
- catch (err) {
222
- logger_1.logger.error(new logger_1.FatalError("The OAuth client configuration is incorrect. " +
223
- "Check the id, secret and scopes for correctness."));
215
+ else {
216
+ throw new logger_1.FatalError("The OAuth client configuration is incorrect. " +
217
+ "Check the id, secret and allowed scopes for this client.");
224
218
  }
225
219
  }
226
- profile.scopes = [...clientCredentialsScopes];
227
220
  break;
228
221
  default:
229
222
  logger_1.logger.error(new logger_1.FatalError("Unsupported profile type"));
@@ -330,6 +323,75 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
330
323
  delete process.env.API_TOKEN;
331
324
  }
332
325
  }
326
+ /**
327
+ * Returns all non-empty combinations of scopes, ordered by size descending (4, then 3, 2, 1).
328
+ * Order within a combination does not matter; each set is tried once.
329
+ */
330
+ getScopeCombinationsOrderedBySize(scopes) {
331
+ function combinations(arr, k) {
332
+ if (k === 0)
333
+ return [[]];
334
+ if (k > arr.length)
335
+ return [];
336
+ const result = [];
337
+ for (let i = 0; i <= arr.length - k; i++) {
338
+ const rest = combinations(arr.slice(i + 1), k - 1);
339
+ rest.forEach(r => result.push([arr[i], ...r]));
340
+ }
341
+ return result;
342
+ }
343
+ return [
344
+ ...combinations(scopes, 4),
345
+ ...combinations(scopes, 3),
346
+ ...combinations(scopes, 2),
347
+ ...combinations(scopes, 1),
348
+ ];
349
+ }
350
+ /**
351
+ * Tries to obtain a client_credentials token. First tries with all scopes (including
352
+ * action-engine.projects); if no token is returned, tries again without action-engine.projects.
353
+ * Returns { tokenSet, scopes } or null if no grant succeeded.
354
+ */
355
+ tryClientCredentialsGrant(issuer, profile, tokenEndpointAuthMethod) {
356
+ return __awaiter(this, void 0, void 0, function* () {
357
+ const Client = issuer.Client;
358
+ const client = new Client({
359
+ client_id: profile.clientId,
360
+ client_secret: profile.clientSecret,
361
+ token_endpoint_auth_method: tokenEndpointAuthMethod,
362
+ });
363
+ const scopeAttempts = this.getScopeCombinationsOrderedBySize(OAUTH_SCOPES);
364
+ for (const scopeList of scopeAttempts) {
365
+ try {
366
+ const tokenSet = yield client.grant({
367
+ grant_type: "client_credentials",
368
+ scope: scopeList.join(" "),
369
+ });
370
+ if (tokenSet && tokenSet.access_token) {
371
+ const scopes = this.extractScopesFromTokenSet(tokenSet, scopeList);
372
+ return { tokenSet, scopes };
373
+ }
374
+ }
375
+ catch (_e) {
376
+ // This scope set failed (e.g. invalid_scope); try next
377
+ }
378
+ }
379
+ return null;
380
+ });
381
+ }
382
+ /**
383
+ * Extracts granted scopes from the token response (OAuth 2.0 scope parameter).
384
+ * Used at profile creation so we store the scopes the server actually granted for this client.
385
+ */
386
+ extractScopesFromTokenSet(tokenSet, fallbackScopes) {
387
+ if (tokenSet.scope && typeof tokenSet.scope === "string") {
388
+ const scopes = tokenSet.scope.trim().split(/\s+/).filter(Boolean);
389
+ if (scopes.length > 0) {
390
+ return scopes;
391
+ }
392
+ }
393
+ return [...fallbackScopes];
394
+ }
333
395
  }
334
396
  exports.ProfileService = ProfileService;
335
397
  exports.profileService = new ProfileService();
@@ -8,6 +8,7 @@ export declare class BatchImportExportApi {
8
8
  findAllActivePackages(flavors: string[], withDependencies?: boolean): Promise<PackageExportTransport[]>;
9
9
  findActivePackagesByVariableValue(flavors: string[], variableValue: string, variableType: string): Promise<PackageExportTransport[]>;
10
10
  findActivePackagesByKeys(packageKeys: string[], withDependencies?: boolean): Promise<PackageExportTransport[]>;
11
+ findPackagesByKeysAndVersion(packageKeysWithVersion: string[], withDependencies?: boolean): Promise<PackageExportTransport[]>;
11
12
  exportPackages(packageKeys: string[], withDependencies: boolean): Promise<Buffer>;
12
13
  exportPackagesByVersions(packageKeysWithVersion: string[], withDependencies: boolean): Promise<Buffer>;
13
14
  batchExportPackagesMetadata(packageKeys: string[]): Promise<PackageMetadataExportTransport[]>;
@@ -6,7 +6,8 @@ export declare class BatchImportExportService {
6
6
  private gitService;
7
7
  constructor(context: Context);
8
8
  listActivePackages(flavors: string[]): Promise<void>;
9
- findAndExportListOfActivePackages(flavors: string[], packageKeys: string[], withDependencies: boolean): Promise<void>;
9
+ findAndExportListOfPackages(flavors: string[], packageKeys: string[], keysByVersion: string[], withDependencies: boolean): Promise<void>;
10
+ listPackagesByKeysWithVersion(keysByVersion: string[], withDependencies: boolean): Promise<void>;
10
11
  batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean): Promise<void>;
11
12
  batchExportPackagesMetadata(packageKeys: string[], jsonResponse: boolean): Promise<void>;
12
13
  batchImportPackages(sourcePath: string, overwrite: boolean, gitBranch: string): Promise<void>;
@@ -17,6 +18,7 @@ export declare class BatchImportExportService {
17
18
  private getVersionedVariablesForPackagesWithKeys;
18
19
  private exportListOfPackagesMetadata;
19
20
  private buildBodyForImport;
21
+ private assertUncompressedSizeWithinLimit;
20
22
  private getReadableStream;
21
23
  private parseEntryData;
22
24
  private downloadZip;
@@ -4,7 +4,7 @@ export declare class ConfigCommandService {
4
4
  private variableService;
5
5
  private diffService;
6
6
  constructor(context: Context);
7
- listActivePackages(jsonResponse: boolean, flavors: string[], withDependencies: boolean, packageKeys: string[], variableValue: string, variableType: string): Promise<void>;
7
+ listPackages(jsonResponse: boolean, flavors: string[], withDependencies: boolean, packageKeys: string[], keysByVersion: string[], variableValue: string, variableType: string): Promise<void>;
8
8
  listVariables(jsonResponse: boolean, keysByVersion: string[], keysByVersionFile: string): Promise<void>;
9
9
  batchExportPackages(packageKeys: string[], packageKeysByVersion: string[], withDependencies: boolean, gitBranch: string, unzip: boolean): Promise<void>;
10
10
  batchExportPackagesMetadata(packageKeys: string[], jsonResponse: boolean): Promise<void>;
@@ -5,7 +5,7 @@ import { Configurator, IModule } from "../../core/command/module-handler";
5
5
  import { Context } from "../../core/command/cli-context";
6
6
  declare class Module extends IModule {
7
7
  register(context: Context, configurator: Configurator): void;
8
- private listActivePackages;
8
+ private listPackages;
9
9
  private batchExportPackages;
10
10
  private batchExportPackagesMetadata;
11
11
  private getPackageVersion;
@@ -23,5 +23,21 @@ export declare class ProfileService {
23
23
  private tryKeyAuthentication;
24
24
  private checkIfMissingProfile;
25
25
  private mapCelonisEnvProfile;
26
+ /**
27
+ * Returns all non-empty combinations of scopes, ordered by size descending (4, then 3, 2, 1).
28
+ * Order within a combination does not matter; each set is tried once.
29
+ */
30
+ private getScopeCombinationsOrderedBySize;
31
+ /**
32
+ * Tries to obtain a client_credentials token. First tries with all scopes (including
33
+ * action-engine.projects); if no token is returned, tries again without action-engine.projects.
34
+ * Returns { tokenSet, scopes } or null if no grant succeeded.
35
+ */
36
+ private tryClientCredentialsGrant;
37
+ /**
38
+ * Extracts granted scopes from the token response (OAuth 2.0 scope parameter).
39
+ * Used at profile creation so we store the scopes the server actually granted for this client.
40
+ */
41
+ private extractScopesFromTokenSet;
26
42
  }
27
43
  export declare const profileService: ProfileService;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celonis/content-cli",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "CLI Tool to help manage content in Celonis Platform",
5
5
  "main": "content-cli.js",
6
6
  "bin": {
@@ -18,9 +18,10 @@
18
18
  "node": ">=18.20.5"
19
19
  },
20
20
  "dependencies": {
21
- "@datadog/datadog-ci": "2.48.0",
22
21
  "adm-zip": "0.5.14",
23
- "axios": "1.8.4",
22
+ "chalk": "4.1.2",
23
+ "uuid": "9.0.1",
24
+ "axios": "1.13.5",
24
25
  "commander": "13.1.0",
25
26
  "form-data": "4.0.4",
26
27
  "openid-client": "5.6.1",