auth0-deploy-cli 8.25.0 → 8.27.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.
Files changed (34) hide show
  1. package/.github/workflows/claude-code-review.yml +1 -4
  2. package/CHANGELOG.md +49 -1
  3. package/lib/tools/auth0/handlers/actions.js +1 -1
  4. package/lib/tools/auth0/handlers/clientGrants.d.ts +5 -0
  5. package/lib/tools/auth0/handlers/clientGrants.js +41 -8
  6. package/lib/tools/auth0/handlers/clients.d.ts +43 -8
  7. package/lib/tools/auth0/handlers/clients.js +109 -41
  8. package/lib/tools/auth0/handlers/connectionProfiles.js +0 -3
  9. package/lib/tools/auth0/handlers/connections.d.ts +7 -8
  10. package/lib/tools/auth0/handlers/connections.js +67 -59
  11. package/lib/tools/auth0/handlers/customDomains.d.ts +4 -0
  12. package/lib/tools/auth0/handlers/customDomains.js +6 -3
  13. package/lib/tools/auth0/handlers/databases.d.ts +71 -2
  14. package/lib/tools/auth0/handlers/databases.js +139 -25
  15. package/lib/tools/auth0/handlers/default.js +2 -4
  16. package/lib/tools/auth0/handlers/flowVaultConnections.js +6 -3
  17. package/lib/tools/auth0/handlers/flows.js +0 -3
  18. package/lib/tools/auth0/handlers/forms.js +0 -3
  19. package/lib/tools/auth0/handlers/logStreams.js +0 -3
  20. package/lib/tools/auth0/handlers/organizations.d.ts +4 -1
  21. package/lib/tools/auth0/handlers/organizations.js +61 -32
  22. package/lib/tools/auth0/handlers/prompts.d.ts +2 -2
  23. package/lib/tools/auth0/handlers/prompts.js +1 -0
  24. package/lib/tools/auth0/handlers/resourceServers.d.ts +1 -3
  25. package/lib/tools/auth0/handlers/resourceServers.js +4 -4
  26. package/lib/tools/auth0/handlers/roles.js +6 -3
  27. package/lib/tools/auth0/handlers/scimHandler.d.ts +5 -8
  28. package/lib/tools/auth0/handlers/scimHandler.js +19 -13
  29. package/lib/tools/auth0/handlers/selfServiceProfiles.d.ts +8 -0
  30. package/lib/tools/auth0/handlers/selfServiceProfiles.js +9 -0
  31. package/lib/tools/auth0/handlers/userAttributeProfiles.js +0 -3
  32. package/lib/tools/utils.d.ts +11 -0
  33. package/lib/tools/utils.js +24 -1
  34. package/package.json +8 -8
@@ -168,16 +168,21 @@ const getConnectionEnabledClients = async (auth0Client, connectionId) => {
168
168
  try {
169
169
  const enabledClientsFormatted = [];
170
170
  let enabledClients = await auth0Client.connections.clients.get(connectionId);
171
- do {
172
- if (enabledClients && enabledClients.data?.length > 0) {
173
- enabledClients.data.forEach((client) => {
174
- if (client?.client_id) {
175
- enabledClientsFormatted.push(client.client_id);
176
- }
177
- });
171
+ // Process first page
172
+ enabledClients.data?.forEach((client) => {
173
+ if (client?.client_id) {
174
+ enabledClientsFormatted.push(client.client_id);
178
175
  }
176
+ });
177
+ // Fetch remaining pages
178
+ while (enabledClients.hasNextPage()) {
179
179
  enabledClients = await enabledClients.getNextPage();
180
- } while (enabledClients.hasNextPage());
180
+ enabledClients.data?.forEach((client) => {
181
+ if (client?.client_id) {
182
+ enabledClientsFormatted.push(client.client_id);
183
+ }
184
+ });
185
+ }
181
186
  return enabledClientsFormatted;
182
187
  }
183
188
  catch (error) {
@@ -195,13 +200,36 @@ exports.getConnectionEnabledClients = getConnectionEnabledClients;
195
200
  * @returns Promise that resolves to true if the update was successful, false otherwise
196
201
  *
197
202
  */
198
- const updateConnectionEnabledClients = async (auth0Client, typeName, connectionId, enabledClientIds) => {
203
+ const updateConnectionEnabledClients = async (auth0Client, typeName, connectionId, enabledClientIds, existingConnections) => {
199
204
  if (!connectionId || !Array.isArray(enabledClientIds) || !enabledClientIds.length)
200
205
  return false;
201
- const enabledClientUpdatePayloads = enabledClientIds.map((clientId) => ({
202
- client_id: clientId,
203
- status: true,
204
- }));
206
+ let existingEnabledClients = [];
207
+ if (Array.isArray(existingConnections)) {
208
+ const existingConnection = existingConnections.find((con) => con.id === connectionId);
209
+ existingEnabledClients = existingConnection?.enabled_clients ?? [];
210
+ }
211
+ // Determine which clients to enable vs. disable by comparing the incoming `enabledClientIds` with the `existingEnabledClients`.
212
+ const enabledClientIdSet = new Set(enabledClientIds);
213
+ const existingClientIdSet = new Set(existingEnabledClients);
214
+ // If both sets are identical, skip the update entirely.
215
+ if (enabledClientIdSet.size === existingClientIdSet.size &&
216
+ [...enabledClientIdSet].every((id) => existingClientIdSet.has(id))) {
217
+ logger_1.default.debug(`Enabled clients for ${typeName}: ${connectionId} are unchanged, skipping update`);
218
+ return true;
219
+ }
220
+ const clientsToEnable = enabledClientIds;
221
+ // Any client that exists on the tenant but not in the provided `enabledClientIds` should be disabled.
222
+ const clientsToDisable = existingEnabledClients.filter((clientId) => !enabledClientIdSet.has(clientId));
223
+ const enabledClientUpdatePayloads = [
224
+ ...clientsToEnable.map((clientId) => ({
225
+ client_id: clientId,
226
+ status: true,
227
+ })),
228
+ ...clientsToDisable.map((clientId) => ({
229
+ client_id: clientId,
230
+ status: false,
231
+ })),
232
+ ];
205
233
  const payloadChunks = (0, lodash_1.chunk)(enabledClientUpdatePayloads, 50);
206
234
  try {
207
235
  await Promise.all(payloadChunks.map((payload) => auth0Client.connections.clients.update(connectionId, payload)));
@@ -225,7 +253,7 @@ exports.updateConnectionEnabledClients = updateConnectionEnabledClients;
225
253
  *
226
254
  * @returns A Promise that resolves when all enabled client updates are complete
227
255
  */
228
- const processConnectionEnabledClients = async (auth0Client, typeName, changes, delayMs = 2500 // Default delay is 2.5 seconds
256
+ const processConnectionEnabledClients = async (auth0Client, typeName, existingConnections, changes, delayMs = 2500 // Default delay is 2.5 seconds
229
257
  ) => {
230
258
  const { create, update, conflicts } = changes;
231
259
  let createWithId = [];
@@ -262,9 +290,9 @@ const processConnectionEnabledClients = async (auth0Client, typeName, changes, d
262
290
  // Process enabled clients for each change type
263
291
  // Delete is handled by the `processChanges` method, removed connection completely
264
292
  await Promise.all([
265
- ...createWithId.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
266
- ...update.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
267
- ...conflicts.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients)),
293
+ ...createWithId.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
294
+ ...update.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
295
+ ...conflicts.map((conn) => (0, exports.updateConnectionEnabledClients)(auth0Client, typeName, conn.id, conn.enabled_clients, existingConnections)),
268
296
  ]);
269
297
  };
270
298
  exports.processConnectionEnabledClients = processConnectionEnabledClients;
@@ -277,7 +305,7 @@ class ConnectionsHandler extends default_1.default {
277
305
  functions: {
278
306
  // When `connections` is updated, it can result in `update`,`create` or `delete` action on SCIM.
279
307
  // Because, `scim_configuration` is inside `connections`.
280
- update: async (requestParams, bodyParams) => this.scimHandler.updateOverride(requestParams, bodyParams),
308
+ update: async (connectionId, bodyParams) => this.scimHandler.updateOverride(connectionId, bodyParams),
281
309
  // When a new `connection` is created. We can perform only `create` option on SCIM.
282
310
  // When a connection is `deleted`. `scim_configuration` is also deleted along with it; no action on SCIM is required.
283
311
  create: async (bodyParams) => this.scimHandler.createOverride(bodyParams),
@@ -306,45 +334,19 @@ class ConnectionsHandler extends default_1.default {
306
334
  }
307
335
  }
308
336
  /**
309
- * Retrieves directory provisioning configuration for a specific Auth0 connection.
310
- * @param connectionId - The unique identifier of the connection
311
- * @returns A promise that resolves to the configuration object, or null if not configured/supported
337
+ * Retrieves all directory provisioning configurations for all connections.
338
+ * @returns A promise that resolves to the configurations object, or null if not configured/supported
312
339
  */
313
- async getConnectionDirectoryProvisioning(connectionId) {
314
- if (!connectionId)
315
- return null;
316
- const creates = [connectionId];
317
- let config = null;
340
+ async getConnectionDirectoryProvisionings() {
341
+ let directoryProvisioningConfigs;
318
342
  try {
319
- await this.client.pool
320
- .addEachTask({
321
- data: creates || [],
322
- generator: async (id) => this.client.connections.directoryProvisioning
323
- .get(id)
324
- .then((resp) => {
325
- config = resp;
326
- })
327
- .catch((err) => {
328
- throw new auth0_1.ManagementError(err);
329
- }),
330
- })
331
- .promise();
332
- const stripKeysFromOutput = [
333
- 'connection_id',
334
- 'connection_name',
335
- 'strategy',
336
- 'created_at',
337
- 'updated_at',
338
- ];
339
- stripKeysFromOutput.forEach((key) => {
340
- if (config && key in config) {
341
- delete config[key];
342
- }
343
+ directoryProvisioningConfigs = await (0, client_1.paginate)(this.client.connections.directoryProvisioning.list, {
344
+ checkpoint: true,
343
345
  });
344
- return config;
346
+ return directoryProvisioningConfigs;
345
347
  }
346
348
  catch (error) {
347
- const errLog = `Unable to fetch directory provisioning for connection '${connectionId}'. `;
349
+ const errLog = `Unable to fetch directory provisioning for connections. `;
348
350
  if (error instanceof auth0_1.ManagementError) {
349
351
  const bodyMessage = error.body?.message;
350
352
  logger_1.default.warn(errLog + bodyMessage);
@@ -471,9 +473,12 @@ class ConnectionsHandler extends default_1.default {
471
473
  async getType() {
472
474
  if (this.existing)
473
475
  return this.existing;
474
- const connections = await (0, client_1.paginate)(this.client.connections.list, {
475
- checkpoint: true,
476
- });
476
+ const [connections, directoryProvisioningConfigs] = await Promise.all([
477
+ (0, client_1.paginate)(this.client.connections.list, {
478
+ checkpoint: true,
479
+ }),
480
+ this.getConnectionDirectoryProvisionings(),
481
+ ]);
477
482
  // Filter out database connections as we have separate handler for it
478
483
  const filteredConnections = connections.filter((c) => c.strategy !== 'auth0');
479
484
  // If options option is empty for all connection, log the missing options scope.
@@ -493,10 +498,13 @@ class ConnectionsHandler extends default_1.default {
493
498
  if (enabledClients && enabledClients?.length) {
494
499
  connection.enabled_clients = enabledClients;
495
500
  }
496
- if (connection.strategy === 'google-apps') {
497
- const dirProvConfig = await this.getConnectionDirectoryProvisioning(con.id);
501
+ if (connection.strategy === 'google-apps' && directoryProvisioningConfigs) {
502
+ const dirProvConfig = directoryProvisioningConfigs.find((congigCon) => congigCon.connection_id === con.id);
498
503
  if (dirProvConfig) {
499
- connection.directory_provisioning_configuration = dirProvConfig;
504
+ connection.directory_provisioning_configuration = {
505
+ mapping: dirProvConfig.mapping,
506
+ synchronize_automatically: dirProvConfig.synchronize_automatically,
507
+ };
500
508
  }
501
509
  }
502
510
  return connection;
@@ -558,7 +566,7 @@ class ConnectionsHandler extends default_1.default {
558
566
  changes = (0, utils_1.filterIncluded)(changes, includedConnections);
559
567
  await super.processChanges(assets, changes);
560
568
  // process enabled clients
561
- await (0, exports.processConnectionEnabledClients)(this.client, this.type, changes);
569
+ await (0, exports.processConnectionEnabledClients)(this.client, this.type, await this.existing, changes);
562
570
  // process directory provisioning
563
571
  await this.processConnectionDirectoryProvisioning(changes);
564
572
  }
@@ -46,6 +46,10 @@ export declare const schema: {
46
46
  description: string;
47
47
  defaultValue: string;
48
48
  };
49
+ relying_party_identifier: {
50
+ type: string[];
51
+ description: string;
52
+ };
49
53
  };
50
54
  required: string[];
51
55
  };
@@ -77,6 +77,10 @@ exports.schema = {
77
77
  description: 'Custom domain verification method. Must be `txt`.',
78
78
  defaultValue: 'txt',
79
79
  },
80
+ relying_party_identifier: {
81
+ type: ['string'],
82
+ description: 'Relying Party ID (rpId) to be used for Passkeys on this custom domain. If not provided or set to null, the full domain will be used.',
83
+ },
80
84
  },
81
85
  required: ['domain', 'type'],
82
86
  },
@@ -95,6 +99,7 @@ class CustomDomainsHadnler extends default_1.default {
95
99
  'certificate',
96
100
  'created_at',
97
101
  'updated_at',
102
+ 'is_default',
98
103
  ],
99
104
  stripUpdateFields: [
100
105
  'status',
@@ -106,10 +111,8 @@ class CustomDomainsHadnler extends default_1.default {
106
111
  'certificate',
107
112
  'created_at',
108
113
  'updated_at',
114
+ 'is_default',
109
115
  ],
110
- functions: {
111
- update: (args, data) => this.client.customDomains.update(args.custom_domain_id, data),
112
- },
113
116
  });
114
117
  }
115
118
  objString(item) {
@@ -1,5 +1,7 @@
1
1
  import DefaultAPIHandler from './default';
2
- import { CalculatedChanges, Assets, Asset } from '../../../types';
2
+ import { CalculatedChanges, Assets } from '../../../types';
3
+ import { Connection } from './connections';
4
+ import { Action } from './actions';
3
5
  export declare const schema: {
4
6
  type: string;
5
7
  items: {
@@ -16,6 +18,50 @@ export declare const schema: {
16
18
  options: {
17
19
  type: string;
18
20
  properties: {
21
+ authentication_methods: {
22
+ type: string;
23
+ properties: {
24
+ passkey: {
25
+ type: string;
26
+ properties: {
27
+ enabled: {
28
+ type: string;
29
+ };
30
+ };
31
+ };
32
+ password: {
33
+ type: string;
34
+ properties: {
35
+ enabled: {
36
+ type: string;
37
+ };
38
+ api_behavior: {
39
+ type: string;
40
+ };
41
+ };
42
+ };
43
+ email_otp: {
44
+ type: string;
45
+ properties: {
46
+ enabled: {
47
+ type: string;
48
+ };
49
+ };
50
+ };
51
+ phone_otp: {
52
+ type: string;
53
+ properties: {
54
+ enabled: {
55
+ type: string;
56
+ };
57
+ };
58
+ };
59
+ };
60
+ };
61
+ disable_self_service_change_password: {
62
+ type: string;
63
+ default: boolean;
64
+ };
19
65
  customScripts: {
20
66
  type: string;
21
67
  properties: {};
@@ -36,6 +82,10 @@ export declare const schema: {
36
82
  active: {
37
83
  type: string;
38
84
  };
85
+ default_method: {
86
+ type: string;
87
+ enum: string[];
88
+ };
39
89
  };
40
90
  };
41
91
  profile_required: {
@@ -73,6 +123,10 @@ export declare const schema: {
73
123
  active: {
74
124
  type: string;
75
125
  };
126
+ default_method: {
127
+ type: string;
128
+ enum: string[];
129
+ };
76
130
  };
77
131
  };
78
132
  profile_required: {
@@ -106,6 +160,10 @@ export declare const schema: {
106
160
  active: {
107
161
  type: string;
108
162
  };
163
+ default_method: {
164
+ type: string;
165
+ enum: string[];
166
+ };
109
167
  };
110
168
  };
111
169
  profile_required: {
@@ -124,6 +182,14 @@ export declare const schema: {
124
182
  };
125
183
  };
126
184
  };
185
+ custom_password_hash: {
186
+ type: string;
187
+ properties: {
188
+ action_id: {
189
+ type: string;
190
+ };
191
+ };
192
+ };
127
193
  };
128
194
  };
129
195
  };
@@ -131,12 +197,15 @@ export declare const schema: {
131
197
  };
132
198
  };
133
199
  export default class DatabaseHandler extends DefaultAPIHandler {
200
+ existing: Connection[] | null;
134
201
  constructor(config: DefaultAPIHandler);
135
202
  objString(db: any): string;
203
+ getFormattedOptions(options: any, actions?: Action[]): any;
136
204
  validate(assets: Assets): Promise<void>;
205
+ private validatePasswordlessSettings;
137
206
  private validateEmailUniqueConstraints;
138
207
  getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
139
- getType(): Promise<Asset | Asset[]>;
208
+ getType(): Promise<Connection[]>;
140
209
  calcChanges(assets: Assets): Promise<CalculatedChanges>;
141
210
  processChanges(assets: Assets): Promise<void>;
142
211
  }
@@ -60,6 +60,37 @@ exports.schema = {
60
60
  options: {
61
61
  type: 'object',
62
62
  properties: {
63
+ authentication_methods: {
64
+ type: 'object',
65
+ properties: {
66
+ passkey: {
67
+ type: 'object',
68
+ properties: {
69
+ enabled: { type: 'boolean' },
70
+ },
71
+ },
72
+ password: {
73
+ type: 'object',
74
+ properties: {
75
+ enabled: { type: 'boolean' },
76
+ api_behavior: { type: 'string' },
77
+ },
78
+ },
79
+ email_otp: {
80
+ type: 'object',
81
+ properties: {
82
+ enabled: { type: 'boolean' },
83
+ },
84
+ },
85
+ phone_otp: {
86
+ type: 'object',
87
+ properties: {
88
+ enabled: { type: 'boolean' },
89
+ },
90
+ },
91
+ },
92
+ },
93
+ disable_self_service_change_password: { type: 'boolean', default: false },
63
94
  customScripts: {
64
95
  type: 'object',
65
96
  properties: {
@@ -77,6 +108,7 @@ exports.schema = {
77
108
  type: 'object',
78
109
  properties: {
79
110
  active: { type: 'boolean' },
111
+ default_method: { type: 'string', enum: ['password', 'email_otp'] },
80
112
  },
81
113
  },
82
114
  profile_required: { type: 'boolean' },
@@ -102,6 +134,7 @@ exports.schema = {
102
134
  type: 'object',
103
135
  properties: {
104
136
  active: { type: 'boolean' },
137
+ default_method: { type: 'string', enum: ['password', 'phone_otp'] },
105
138
  },
106
139
  },
107
140
  profile_required: { type: 'boolean' },
@@ -126,6 +159,7 @@ exports.schema = {
126
159
  type: 'object',
127
160
  properties: {
128
161
  active: { type: 'boolean' },
162
+ default_method: { type: 'string', enum: ['password'] },
129
163
  },
130
164
  },
131
165
  profile_required: { type: 'boolean' },
@@ -139,6 +173,12 @@ exports.schema = {
139
173
  },
140
174
  },
141
175
  },
176
+ custom_password_hash: {
177
+ type: 'object',
178
+ properties: {
179
+ action_id: { type: 'string' },
180
+ },
181
+ },
142
182
  },
143
183
  },
144
184
  },
@@ -156,6 +196,22 @@ class DatabaseHandler extends default_1.default {
156
196
  objString(db) {
157
197
  return super.objString({ name: db.name, id: db.id });
158
198
  }
199
+ getFormattedOptions(options, actions = []) {
200
+ try {
201
+ const formattedOptions = { ...options };
202
+ // Handle custom_password_hash.action_id conversion
203
+ if (options?.custom_password_hash?.action_id) {
204
+ formattedOptions.custom_password_hash = {
205
+ ...options.custom_password_hash,
206
+ action_id: (0, utils_1.convertActionNameToId)(options.custom_password_hash.action_id, actions),
207
+ };
208
+ }
209
+ return formattedOptions;
210
+ }
211
+ catch (e) {
212
+ return {};
213
+ }
214
+ }
159
215
  async validate(assets) {
160
216
  const { databases } = assets;
161
217
  // Do nothing if not set
@@ -164,9 +220,25 @@ class DatabaseHandler extends default_1.default {
164
220
  // Validate each database
165
221
  databases.forEach((database) => {
166
222
  this.validateEmailUniqueConstraints(database);
223
+ // this.validatePasswordlessSettings(database); // Enable only the feature is GA PR:#1282
167
224
  });
168
225
  await super.validate(assets);
169
226
  }
227
+ validatePasswordlessSettings(payload) {
228
+ const options = payload?.options;
229
+ if (!options)
230
+ return;
231
+ const passwordEnabled = options?.authentication_methods?.password?.enabled;
232
+ const disableSelfServiceChangePassword = options?.disable_self_service_change_password;
233
+ if (passwordEnabled === undefined || disableSelfServiceChangePassword === undefined)
234
+ return;
235
+ if (passwordEnabled === false && disableSelfServiceChangePassword !== true) {
236
+ throw new Error(`Database "${payload.name}": When password authentication is disabled, disable_self_service_change_password must be true.`);
237
+ }
238
+ if (passwordEnabled === true && disableSelfServiceChangePassword === true) {
239
+ throw new Error(`Database "${payload.name}": disable_self_service_change_password must be false when password authentication is enabled.`);
240
+ }
241
+ }
170
242
  validateEmailUniqueConstraints(payload) {
171
243
  const attributes = payload?.options?.attributes;
172
244
  // Only validate if attributes are present
@@ -192,11 +264,16 @@ class DatabaseHandler extends default_1.default {
192
264
  getClientFN(fn) {
193
265
  // Override this as a database is actually a connection but we are treating them as a different object
194
266
  if (fn === 'create') {
195
- return (payload) => this.client.connections.create(payload);
267
+ return (payload) => {
268
+ // Remove deprecated enabled_clients field
269
+ if ('enabled_clients' in payload)
270
+ delete payload.enabled_clients;
271
+ return this.client.connections.create(payload);
272
+ };
196
273
  }
197
274
  // If we going to update database, we need to get current options first
198
275
  if (fn === 'update') {
199
- return (params, payload) => this.client.connections.get(params?.id).then((response) => {
276
+ return (id, payload) => this.client.connections.get(id).then((response) => {
200
277
  const connection = response;
201
278
  const attributes = payload?.options?.attributes;
202
279
  const requiresUsername = payload?.options?.requires_username;
@@ -215,7 +292,10 @@ class DatabaseHandler extends default_1.default {
215
292
  if (payload.options && Object.keys(payload.options).length === 0) {
216
293
  delete payload.options;
217
294
  }
218
- return this.client.connections.update(params.id, payload);
295
+ // Remove deprecated enabled_clients field
296
+ if ('enabled_clients' in payload)
297
+ delete payload.enabled_clients;
298
+ return this.client.connections.update(id, payload);
219
299
  });
220
300
  }
221
301
  return this.client.connections[fn].bind(this.client.connections);
@@ -223,25 +303,52 @@ class DatabaseHandler extends default_1.default {
223
303
  async getType() {
224
304
  if (this.existing)
225
305
  return this.existing;
226
- const connections = await (0, client_1.paginate)(this.client.connections.list, {
227
- strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
228
- checkpoint: true,
229
- });
306
+ // Fetch connections and actions concurrently
307
+ const [connections, actions] = await Promise.all([
308
+ (0, client_1.paginate)(this.client.connections.list, {
309
+ strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
310
+ checkpoint: true,
311
+ }),
312
+ (0, client_1.paginate)(this.client.actions.list, {
313
+ paginate: true,
314
+ include_totals: true,
315
+ }),
316
+ ]);
230
317
  const dbConnectionsWithEnabledClients = await Promise.all(connections.map(async (con) => {
231
318
  if (!con?.id)
232
319
  return con;
233
320
  const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
321
+ const connection = { ...con };
234
322
  if (enabledClients && enabledClients?.length) {
235
- return { ...con, enabled_clients: enabledClients };
323
+ connection.enabled_clients = enabledClients;
236
324
  }
237
- return con;
325
+ return connection;
238
326
  }));
327
+ // Convert action ID back to action name for export
328
+ const dbConnectionsWithActionNames = dbConnectionsWithEnabledClients.map((connection) => {
329
+ if (connection.options && 'custom_password_hash' in connection.options) {
330
+ const customPasswordHash = connection.options?.custom_password_hash;
331
+ if (customPasswordHash?.action_id) {
332
+ return {
333
+ ...connection,
334
+ options: {
335
+ ...connection.options,
336
+ custom_password_hash: {
337
+ ...customPasswordHash,
338
+ action_id: (0, utils_1.convertActionIdToName)(customPasswordHash.action_id, actions),
339
+ },
340
+ },
341
+ };
342
+ }
343
+ }
344
+ return connection;
345
+ });
239
346
  // If options option is empty for all connection, log the missing options scope.
240
- const isOptionExists = dbConnectionsWithEnabledClients.every((c) => c.options && Object.keys(c.options).length > 0);
347
+ const isOptionExists = dbConnectionsWithActionNames.every((c) => c.options && Object.keys(c.options).length > 0);
241
348
  if (!isOptionExists) {
242
349
  logger_1.default.warn(`Insufficient scope the read:connections_options scope is required to get ${this.type} options.`);
243
350
  }
244
- this.existing = dbConnectionsWithEnabledClients;
351
+ this.existing = dbConnectionsWithActionNames;
245
352
  return this.existing;
246
353
  }
247
354
  async calcChanges(assets) {
@@ -255,22 +362,29 @@ class DatabaseHandler extends default_1.default {
255
362
  conflicts: [],
256
363
  };
257
364
  // Convert enabled_clients by name to the id
258
- const clients = await (0, client_1.paginate)(this.client.clients.list, {
259
- paginate: true,
260
- });
261
- const existingDatabasesConnections = await (0, client_1.paginate)(this.client.connections.list, {
262
- strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
263
- checkpoint: true,
264
- include_totals: true,
265
- });
365
+ // Fetch clients, connections, and actions concurrently
366
+ const [clients, existingDatabasesConnections, actions] = await Promise.all([
367
+ (0, client_1.paginate)(this.client.clients.list, {
368
+ paginate: true,
369
+ }),
370
+ (0, client_1.paginate)(this.client.connections.list, {
371
+ strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
372
+ checkpoint: true,
373
+ include_totals: true,
374
+ }),
375
+ (0, client_1.paginate)(this.client.actions.list, {
376
+ paginate: true,
377
+ include_totals: true,
378
+ }),
379
+ ]);
266
380
  const formatted = databases.map((db) => {
381
+ const { options, ...rest } = db;
382
+ const formattedOptions = this.getFormattedOptions(options, actions);
383
+ const formattedDb = { ...rest, options: formattedOptions };
267
384
  if (db.enabled_clients) {
268
- return {
269
- ...db,
270
- enabled_clients: (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients),
271
- };
385
+ formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients);
272
386
  }
273
- return db;
387
+ return formattedDb;
274
388
  });
275
389
  return super.calcChanges({ ...assets, databases: formatted });
276
390
  }
@@ -289,7 +403,7 @@ class DatabaseHandler extends default_1.default {
289
403
  const changes = await this.calcChanges(assets);
290
404
  await super.processChanges(assets, (0, utils_1.filterExcluded)(changes, excludedConnections));
291
405
  // process enabled clients
292
- await (0, connections_1.processConnectionEnabledClients)(this.client, this.type, (0, utils_1.filterExcluded)(changes, excludedConnections));
406
+ await (0, connections_1.processConnectionEnabledClients)(this.client, this.type, await this.existing, (0, utils_1.filterExcluded)(changes, excludedConnections));
293
407
  }
294
408
  }
295
409
  exports.default = DatabaseHandler;
@@ -232,12 +232,11 @@ class APIHandler {
232
232
  data: conflicts || [],
233
233
  generator: (updateItem) => retryWithExponentialBackoff(() => {
234
234
  const updateFN = this.getClientFN(this.functions.update);
235
- const params = { [this.id]: updateItem[this.id] };
236
235
  const updatePayload = (() => {
237
236
  const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
238
237
  return (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
239
238
  })();
240
- return updateFN(params, updatePayload);
239
+ return updateFN(updateItem[this.id], updatePayload);
241
240
  }, retryConfig)
242
241
  .then((data) => this.didUpdate(data))
243
242
  .catch((err) => {
@@ -272,12 +271,11 @@ class APIHandler {
272
271
  data: update || [],
273
272
  generator: (updateItem) => retryWithExponentialBackoff(() => {
274
273
  const updateFN = this.getClientFN(this.functions.update);
275
- const params = { [this.id]: updateItem[this.id] };
276
274
  const updatePayload = (() => {
277
275
  const data = (0, utils_1.stripFields)({ ...updateItem }, this.stripUpdateFields);
278
276
  return (0, utils_1.stripObfuscatedFieldsFromPayload)(data, this.sensitiveFieldsToObfuscate);
279
277
  })();
280
- return updateFN(params, updatePayload);
278
+ return updateFN(updateItem[this.id], updatePayload);
281
279
  }, retryConfig)
282
280
  .then((data) => {
283
281
  this.didUpdate(data);