auth0-deploy-cli 8.43.0 → 8.45.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 (50) hide show
  1. package/CHANGELOG.md +53 -1
  2. package/README.md +1 -1
  3. package/lib/context/defaults.d.ts +7 -0
  4. package/lib/context/defaults.js +74 -30
  5. package/lib/context/directory/handlers/attackProtection.js +1 -1
  6. package/lib/context/directory/handlers/branding.js +9 -1
  7. package/lib/context/directory/handlers/clients.js +9 -3
  8. package/lib/context/directory/handlers/connections.js +10 -4
  9. package/lib/context/directory/handlers/emailTemplates.js +9 -0
  10. package/lib/context/directory/handlers/index.js +2 -0
  11. package/lib/context/directory/handlers/networkACLKeys.d.ts +6 -0
  12. package/lib/context/directory/handlers/networkACLKeys.js +54 -0
  13. package/lib/context/directory/handlers/prompts.js +11 -3
  14. package/lib/context/yaml/handlers/attackProtection.js +1 -1
  15. package/lib/context/yaml/handlers/branding.js +8 -1
  16. package/lib/context/yaml/handlers/clients.js +4 -1
  17. package/lib/context/yaml/handlers/connections.js +3 -1
  18. package/lib/context/yaml/handlers/flows.js +7 -0
  19. package/lib/context/yaml/handlers/forms.js +7 -0
  20. package/lib/context/yaml/handlers/index.js +2 -0
  21. package/lib/context/yaml/handlers/networkACLKeys.d.ts +6 -0
  22. package/lib/context/yaml/handlers/networkACLKeys.js +42 -0
  23. package/lib/context/yaml/handlers/prompts.js +7 -1
  24. package/lib/keywordPreservation.d.ts +1 -1
  25. package/lib/keywordPreservation.js +2 -1
  26. package/lib/readonly.js +5 -0
  27. package/lib/tools/auth0/handlers/attackProtection.js +3 -1
  28. package/lib/tools/auth0/handlers/clients.d.ts +40 -0
  29. package/lib/tools/auth0/handlers/clients.js +58 -1
  30. package/lib/tools/auth0/handlers/connectionProfiles.d.ts +27 -0
  31. package/lib/tools/auth0/handlers/connectionProfiles.js +30 -0
  32. package/lib/tools/auth0/handlers/connections.js +10 -3
  33. package/lib/tools/auth0/handlers/databases.d.ts +28 -0
  34. package/lib/tools/auth0/handlers/databases.js +47 -22
  35. package/lib/tools/auth0/handlers/default.d.ts +23 -0
  36. package/lib/tools/auth0/handlers/default.js +21 -10
  37. package/lib/tools/auth0/handlers/index.js +2 -0
  38. package/lib/tools/auth0/handlers/networkACLKeys.d.ts +45 -0
  39. package/lib/tools/auth0/handlers/networkACLKeys.js +177 -0
  40. package/lib/tools/auth0/handlers/networkACLs.d.ts +114 -2
  41. package/lib/tools/auth0/handlers/networkACLs.js +91 -16
  42. package/lib/tools/auth0/handlers/organizations.d.ts +1 -1
  43. package/lib/tools/auth0/handlers/organizations.js +49 -20
  44. package/lib/tools/auth0/handlers/phoneProvider.js +10 -2
  45. package/lib/tools/calculateDryRunChanges.js +12 -8
  46. package/lib/tools/constants.d.ts +1 -0
  47. package/lib/tools/constants.js +1 -0
  48. package/lib/types.d.ts +3 -1
  49. package/lib/utils.js +5 -2
  50. package/package.json +2 -2
package/lib/readonly.js CHANGED
@@ -28,6 +28,11 @@ const readOnlyFields = {
28
28
  'config_route',
29
29
  'owners',
30
30
  ],
31
+ attackProtection: [
32
+ // Returned by GET but rejected by PATCH with "Additional properties not allowed"
33
+ 'bruteForceProtection.form_submission_mode',
34
+ 'bruteForceProtection.form_submission_behavior',
35
+ ],
31
36
  };
32
37
  function getExcludedFields(config) {
33
38
  const strippedFields = { ...readOnlyFields };
@@ -314,7 +314,9 @@ class AttackProtectionHandler extends default_1.default {
314
314
  updates.push(this.client.attackProtection.captcha.update(attackProtection.captcha));
315
315
  }
316
316
  if (attackProtection.bruteForceProtection) {
317
- updates.push(this.client.attackProtection.bruteForceProtection.update(attackProtection.bruteForceProtection));
317
+ // Strip fields returned by GET but rejected by PATCH
318
+ const { form_submission_mode, form_submission_behavior, ...bruteForcePayload } = attackProtection.bruteForceProtection;
319
+ updates.push(this.client.attackProtection.bruteForceProtection.update(bruteForcePayload));
318
320
  }
319
321
  if (attackProtection.suspiciousIpThrottling) {
320
322
  updates.push(this.client.attackProtection.suspiciousIpThrottling.update(attackProtection.suspiciousIpThrottling));
@@ -209,6 +209,25 @@ export declare const schema: {
209
209
  type: string;
210
210
  description: string;
211
211
  };
212
+ b2b_integration_configuration: {
213
+ type: string[];
214
+ description: string;
215
+ properties: {
216
+ integration_type: {
217
+ type: string;
218
+ enum: string[];
219
+ description: string;
220
+ };
221
+ sso_profiles: {
222
+ type: string;
223
+ description: string;
224
+ items: {
225
+ type: string;
226
+ };
227
+ };
228
+ };
229
+ additionalProperties: boolean;
230
+ };
212
231
  resource_server_identifier: {
213
232
  type: string;
214
233
  description: string;
@@ -254,6 +273,27 @@ export declare const schema: {
254
273
  enum: ("allow" | "allow_if_empty")[];
255
274
  description: string;
256
275
  };
276
+ third_party_client_access: {
277
+ type: string;
278
+ description: string;
279
+ properties: {
280
+ default_value: {
281
+ type: string;
282
+ enum: "block"[];
283
+ description: string;
284
+ };
285
+ allowed_values: {
286
+ type: string;
287
+ items: {
288
+ type: string;
289
+ enum: ("allow" | "block")[];
290
+ };
291
+ uniqueItems: boolean;
292
+ description: string;
293
+ };
294
+ };
295
+ required: string[];
296
+ };
257
297
  invitation_landing_client_id: {
258
298
  type: string;
259
299
  description: string;
@@ -59,6 +59,27 @@ const myOrganizationConfigurationSchema = {
59
59
  enum: Object.values(auth0_1.Management.ClientMyOrganizationDeletionBehaviorEnum),
60
60
  description: 'The deletion behavior for My Organization connections created by this client',
61
61
  },
62
+ third_party_client_access: {
63
+ type: 'object',
64
+ description: 'Controls whether third-party clients can access the organization via the My Organization API.',
65
+ properties: {
66
+ default_value: {
67
+ type: 'string',
68
+ enum: Object.values(auth0_1.Management.ClientMyOrganizationConfigurationThirdPartyClientAccessDefaultValueEnum),
69
+ description: 'The default third-party client access value.',
70
+ },
71
+ allowed_values: {
72
+ type: 'array',
73
+ items: {
74
+ type: 'string',
75
+ enum: Object.values(auth0_1.Management.ClientMyOrganizationConfigurationThirdPartyClientAccessAllowedValuesEnum),
76
+ },
77
+ uniqueItems: true,
78
+ description: 'The allowed third-party client access values.',
79
+ },
80
+ },
81
+ required: ['default_value', 'allowed_values'],
82
+ },
62
83
  invitation_landing_client_id: {
63
84
  type: 'string',
64
85
  description: 'The client ID of the invitation landing client for the My Organization configuration',
@@ -271,6 +292,23 @@ exports.schema = {
271
292
  type: 'string',
272
293
  description: 'The type of application this client represents',
273
294
  },
295
+ b2b_integration_configuration: {
296
+ type: ['object', 'null'],
297
+ description: 'B2B integration configuration. Early Access. Required feature flag: enterprise_connect_entitled.',
298
+ properties: {
299
+ integration_type: {
300
+ type: 'string',
301
+ enum: ['custom_auth_server', 'third_party', 'application'],
302
+ description: 'The type of integration used to connect to this B2B integration client.',
303
+ },
304
+ sso_profiles: {
305
+ type: 'array',
306
+ description: 'List of SSO profile IDs linked to this B2B integration client. Maximum 1 entry.',
307
+ items: { type: 'string' },
308
+ },
309
+ },
310
+ additionalProperties: false,
311
+ },
274
312
  resource_server_identifier: {
275
313
  type: 'string',
276
314
  description: 'The identifier of a resource server in your tenant. This property links a client to a resource server indicating that the client IS that resource server. Can only be set when app_type=resource_server.',
@@ -563,6 +601,9 @@ class ClientHandler extends default_1.default {
563
601
  'jwks_uri',
564
602
  // third_party_security_mode is immutable after creation; PATCH returns 400
565
603
  'third_party_security_mode',
604
+ // API-generated timestamps; PATCH returns 400 if present
605
+ 'created_at',
606
+ 'updated_at',
566
607
  ],
567
608
  functions: {
568
609
  create: (client) => this.createClient(client),
@@ -752,7 +793,23 @@ class ClientHandler extends default_1.default {
752
793
  async updateClient(clientId, client) {
753
794
  // For non-CIMD clients
754
795
  if (!this.isCimdClient(client)) {
755
- return this.client.clients.update(clientId, client);
796
+ const payload = { ...client };
797
+ // b2b_integration_configuration: PATCH only allowed if client already has the object.
798
+ // Sending it to a client that lacks it returns 400 invalid_body.
799
+ // null clears the object — but only for clients that already have it; stripping
800
+ // null for a client without the field is a safe no-op.
801
+ if ('b2b_integration_configuration' in payload) {
802
+ const existing = (this.existing || []).find((c) => c.client_id === (client.client_id || clientId));
803
+ if (!existing?.b2b_integration_configuration) {
804
+ if (payload.b2b_integration_configuration !== null) {
805
+ logger_1.default.warn(`b2b_integration_configuration cannot be added to an existing client via PATCH ` +
806
+ `(client: ${client.name || clientId}). Skipping field. ` +
807
+ `Re-create the client to set this field.`);
808
+ }
809
+ delete payload.b2b_integration_configuration;
810
+ }
811
+ }
812
+ return this.client.clients.update(clientId, payload);
756
813
  }
757
814
  const updatePayload = this.getCIMDEditableFields(client);
758
815
  const registrationClientId = client.client_id || clientId;
@@ -36,6 +36,33 @@ export declare const schema: {
36
36
  connection_config: {
37
37
  type: string[];
38
38
  };
39
+ cross_app_access_resource_app: {
40
+ type: string;
41
+ description: string;
42
+ properties: {
43
+ status: {
44
+ type: string;
45
+ properties: {
46
+ default_value: {
47
+ type: string;
48
+ enum: ("enabled" | "disabled")[];
49
+ description: string;
50
+ };
51
+ allowed_values: {
52
+ type: string;
53
+ items: {
54
+ type: string;
55
+ enum: ("enabled" | "disabled")[];
56
+ };
57
+ uniqueItems: boolean;
58
+ description: string;
59
+ };
60
+ };
61
+ required: string[];
62
+ };
63
+ };
64
+ required: string[];
65
+ };
39
66
  strategy_overrides: {
40
67
  type: string[];
41
68
  properties: {
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.getConnectionProfile = exports.schema = void 0;
7
+ const auth0_1 = require("auth0");
7
8
  const default_1 = __importDefault(require("./default"));
8
9
  const client_1 = require("../client");
9
10
  const logger_1 = __importDefault(require("../../../logger"));
@@ -42,6 +43,35 @@ exports.schema = {
42
43
  connection_config: {
43
44
  type: ['object', 'null'],
44
45
  },
46
+ cross_app_access_resource_app: {
47
+ type: 'object',
48
+ description: 'Controls whether organization admins may enable Cross App Access (XAA) on their Identity Providers.',
49
+ properties: {
50
+ status: {
51
+ type: 'object',
52
+ properties: {
53
+ default_value: {
54
+ type: 'string',
55
+ enum: Object.values(auth0_1.Management.ConnectionProfileCrossAppAccessResourceAppStatusDefaultValueEnum),
56
+ description: 'The default Cross App Access resource app status.',
57
+ },
58
+ allowed_values: {
59
+ type: 'array',
60
+ items: {
61
+ type: 'string',
62
+ enum: Object.values(auth0_1.Management.ConnectionProfileCrossAppAccessResourceAppStatusValueEnum),
63
+ },
64
+ uniqueItems: true,
65
+ description: 'The allowed Cross App Access resource app status values.',
66
+ },
67
+ },
68
+ // allowed_values is optional per the SDK type (unlike the client's
69
+ // third_party_client_access, which requires both fields).
70
+ required: ['default_value'],
71
+ },
72
+ },
73
+ required: ['status'],
74
+ },
45
75
  strategy_overrides: {
46
76
  type: ['object', 'null'],
47
77
  properties: {
@@ -380,12 +380,15 @@ class ConnectionsHandler extends default_1.default {
380
380
  }
381
381
  getFormattedOptions(connection, clients) {
382
382
  try {
383
+ const { idpinitiated } = connection.options;
383
384
  return {
384
385
  options: {
385
386
  ...connection.options,
386
387
  idpinitiated: {
387
- ...connection.options.idpinitiated,
388
- client_id: (0, utils_1.convertClientNameToId)(connection.options.idpinitiated.client_id, clients),
388
+ ...idpinitiated,
389
+ ...(idpinitiated.client_id && {
390
+ client_id: (0, utils_1.convertClientNameToId)(idpinitiated.client_id, clients),
391
+ }),
389
392
  },
390
393
  },
391
394
  };
@@ -744,7 +747,11 @@ class ConnectionsHandler extends default_1.default {
744
747
  ...(enabledClients !== undefined && { enabled_clients: enabledClients }),
745
748
  };
746
749
  });
747
- const proposedChanges = await super.dryRunChanges({ ...assets, connections: formatted });
750
+ let proposedChanges = await super.dryRunChanges({ ...assets, connections: formatted });
751
+ const includedConnections = (assets.include && assets.include.connections) || [];
752
+ const excludedConnections = (assets.exclude && assets.exclude.connections) || [];
753
+ proposedChanges = (0, utils_1.filterExcluded)(proposedChanges, excludedConnections);
754
+ proposedChanges = (0, utils_1.filterIncluded)(proposedChanges, includedConnections);
748
755
  return (0, exports.addExcludedConnectionPropertiesToChanges)({
749
756
  proposedChanges,
750
757
  existingConnections,
@@ -195,6 +195,33 @@ export declare const schema: {
195
195
  };
196
196
  };
197
197
  };
198
+ otp_settings: {
199
+ type: string;
200
+ properties: {
201
+ email: {
202
+ type: string;
203
+ properties: {
204
+ otp_length: {
205
+ type: string;
206
+ };
207
+ otp_expiry: {
208
+ type: string;
209
+ };
210
+ };
211
+ };
212
+ phone: {
213
+ type: string;
214
+ properties: {
215
+ otp_length: {
216
+ type: string;
217
+ };
218
+ otp_expiry: {
219
+ type: string;
220
+ };
221
+ };
222
+ };
223
+ };
224
+ };
198
225
  password_options: {
199
226
  type: string;
200
227
  properties: {
@@ -295,6 +322,7 @@ export default class DatabaseHandler extends DefaultAPIHandler {
295
322
  private validatePasswordlessSettings;
296
323
  private validateEmailUniqueConstraints;
297
324
  getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
325
+ private enrichConnectionsWithEnabledClients;
298
326
  getType(): Promise<Connection[]>;
299
327
  calcChanges(assets: Assets): Promise<CalculatedChanges>;
300
328
  dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
@@ -181,6 +181,25 @@ exports.schema = {
181
181
  action_id: { type: 'string' },
182
182
  },
183
183
  },
184
+ otp_settings: {
185
+ type: 'object',
186
+ properties: {
187
+ email: {
188
+ type: 'object',
189
+ properties: {
190
+ otp_length: { type: 'integer' },
191
+ otp_expiry: { type: 'integer' },
192
+ },
193
+ },
194
+ phone: {
195
+ type: 'object',
196
+ properties: {
197
+ otp_length: { type: 'integer' },
198
+ otp_expiry: { type: 'integer' },
199
+ },
200
+ },
201
+ },
202
+ },
184
203
  password_options: {
185
204
  type: 'object',
186
205
  properties: {
@@ -419,6 +438,22 @@ class DatabaseHandler extends default_1.default {
419
438
  }
420
439
  return this.client.connections[fn].bind(this.client.connections);
421
440
  }
441
+ // `enabled_clients` is no longer returned by connections.list; it must be fetched from the
442
+ // dedicated enabled-clients endpoint. Enriching the remote connections keeps the diff and the
443
+ // excluded-client preservation in `getEnabledClients` correct. Without it the dry-run diff
444
+ // reports a false "found in localObj but not in remoteObj" and a real import can silently
445
+ // disable an excluded-but-enabled client.
446
+ async enrichConnectionsWithEnabledClients(connections) {
447
+ return Promise.all(connections.map(async (con) => {
448
+ if (!con?.id)
449
+ return con;
450
+ const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
451
+ if (enabledClients?.length) {
452
+ return { ...con, enabled_clients: enabledClients };
453
+ }
454
+ return con;
455
+ }));
456
+ }
422
457
  async getType() {
423
458
  if (this.existing)
424
459
  return this.existing;
@@ -433,16 +468,7 @@ class DatabaseHandler extends default_1.default {
433
468
  include_totals: true,
434
469
  }),
435
470
  ]);
436
- const dbConnectionsWithEnabledClients = await Promise.all(connections.map(async (con) => {
437
- if (!con?.id)
438
- return con;
439
- const enabledClients = await (0, connections_1.getConnectionEnabledClients)(this.client, con.id);
440
- const connection = { ...con };
441
- if (enabledClients && enabledClients?.length) {
442
- connection.enabled_clients = enabledClients;
443
- }
444
- return connection;
445
- }));
471
+ const dbConnectionsWithEnabledClients = await this.enrichConnectionsWithEnabledClients(connections);
446
472
  // Convert action ID back to action name for export
447
473
  const dbConnectionsWithActionNames = dbConnectionsWithEnabledClients.map((connection) => {
448
474
  if (connection.options && 'custom_password_hash' in connection.options) {
@@ -489,28 +515,26 @@ class DatabaseHandler extends default_1.default {
489
515
  update: [],
490
516
  conflicts: [],
491
517
  };
492
- // Convert enabled_clients by name to the id
493
- // Fetch clients, connections, and actions concurrently
494
- const [clients, existingDatabasesConnections, actions] = await Promise.all([
518
+ // Convert enabled_clients by name to the id. `getType()` fetches and enriches the existing
519
+ // connections with `enabled_clients` and caches the result in `this.existing`, so the
520
+ // `super.calcChanges()` call below reuses it instead of fetching again.
521
+ const [clients, actions, existingWithEnabledClients] = await Promise.all([
495
522
  (0, client_1.paginate)(this.client.clients.list, {
496
523
  paginate: true,
497
524
  }),
498
- (0, client_1.paginate)(this.client.connections.list, {
499
- strategy: [auth0_1.Management.ConnectionStrategyEnum.Auth0],
500
- checkpoint: true,
501
- include_totals: true,
502
- }),
503
525
  (0, client_1.paginate)(this.client.actions.list, {
504
526
  paginate: true,
505
527
  include_totals: true,
506
528
  }),
529
+ this.getType(),
507
530
  ]);
531
+ const existingConnections = existingWithEnabledClients || [];
508
532
  const formatted = databases.map((db) => {
509
533
  const { options, ...rest } = db;
510
534
  const formattedOptions = this.getFormattedOptions(options, actions);
511
535
  const formattedDb = { ...rest, options: formattedOptions };
512
536
  if (db.enabled_clients) {
513
- formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients);
537
+ formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingConnections, clients);
514
538
  }
515
539
  return formattedDb;
516
540
  });
@@ -540,21 +564,22 @@ class DatabaseHandler extends default_1.default {
540
564
  include_totals: true,
541
565
  }),
542
566
  ]);
567
+ const existingWithEnabledClients = await this.enrichConnectionsWithEnabledClients(existingDatabasesConnections);
543
568
  const formatted = databases.map((db) => {
544
569
  const { options, ...rest } = db;
545
570
  const formattedOptions = this.getFormattedOptions(options, actions);
546
571
  const formattedDb = { ...rest, options: formattedOptions };
547
572
  if (db.enabled_clients) {
548
- formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingDatabasesConnections, clients);
573
+ formattedDb.enabled_clients = (0, utils_1.getEnabledClients)(assets, db, existingWithEnabledClients, clients);
549
574
  }
550
575
  return formattedDb;
551
576
  });
552
577
  return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
553
578
  type: this.type,
554
579
  assets: formatted,
555
- existing: existingDatabasesConnections,
580
+ existing: existingWithEnabledClients,
556
581
  identifiers: this.identifiers,
557
- ignoreDryRunFields: this.ignoreDryRunFields,
582
+ ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
558
583
  });
559
584
  }
560
585
  // Run after clients are updated so we can convert all the enabled_clients names to id's
@@ -1,6 +1,20 @@
1
1
  import { Asset, Assets, Auth0APIClient, CalculatedChanges } from '../../../types';
2
2
  import { ConfigFunction } from '../../../configFactory';
3
3
  export declare function order(value: any): (t: any, n: any, descriptor: any) => any;
4
+ export interface RetryOptions {
5
+ maxRetries?: number;
6
+ initialDelay?: number;
7
+ maxDelay?: number;
8
+ onRetry?: (error: any, attempt: number, delay: number) => void;
9
+ }
10
+ /**
11
+ * Executes a function with exponential backoff retry logic for rate limit errors (429).
12
+ *
13
+ * @param fn - The function to execute with retry logic
14
+ * @param options - Configuration options for retry behavior
15
+ * @returns Promise that resolves with the function result or rejects after max retries
16
+ */
17
+ export declare function retryWithExponentialBackoff<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
4
18
  type ApiMethodOverride = string | Function;
5
19
  export default class APIHandler {
6
20
  config: ConfigFunction;
@@ -50,6 +64,15 @@ export default class APIHandler {
50
64
  */
51
65
  getEffectiveIgnoreDryRunFields(): string[];
52
66
  getClientFN(fn: ApiMethodOverride): Function;
67
+ /**
68
+ * Builds the exponential-backoff retry configuration for this handler from the
69
+ * shared `AUTH0_MAX_RETRIES` / `AUTH0_RETRY_INITIAL_DELAY_MS` /
70
+ * `AUTH0_RETRY_MAX_DELAY_MS` config keys. Exposed so that handlers which issue
71
+ * writes outside the default `processChanges` flow (e.g. organizations, which
72
+ * writes nested connections/grants directly) can wrap those calls in the same
73
+ * 429 backoff behaviour as the base handler.
74
+ */
75
+ getRetryConfig(): RetryOptions;
53
76
  didDelete(item: Asset): void;
54
77
  didCreate(item: Asset): void;
55
78
  didUpdate(item: Asset): void;
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.order = order;
7
+ exports.retryWithExponentialBackoff = retryWithExponentialBackoff;
7
8
  const auth0_1 = require("auth0");
8
9
  const validationError_1 = __importDefault(require("../../validationError"));
9
10
  const utils_1 = require("../../utils");
@@ -114,6 +115,25 @@ class APIHandler {
114
115
  }
115
116
  return fn;
116
117
  }
118
+ /**
119
+ * Builds the exponential-backoff retry configuration for this handler from the
120
+ * shared `AUTH0_MAX_RETRIES` / `AUTH0_RETRY_INITIAL_DELAY_MS` /
121
+ * `AUTH0_RETRY_MAX_DELAY_MS` config keys. Exposed so that handlers which issue
122
+ * writes outside the default `processChanges` flow (e.g. organizations, which
123
+ * writes nested connections/grants directly) can wrap those calls in the same
124
+ * 429 backoff behaviour as the base handler.
125
+ */
126
+ getRetryConfig() {
127
+ const retryConfig = {
128
+ maxRetries: this.config('AUTH0_MAX_RETRIES') || DEFAULT_MAX_RETRIES,
129
+ initialDelay: this.config('AUTH0_RETRY_INITIAL_DELAY_MS') || DEFAULT_INITIAL_DELAY_MS,
130
+ maxDelay: this.config('AUTH0_RETRY_MAX_DELAY_MS') || DEFAULT_MAX_DELAY_MS,
131
+ onRetry: (error, attempt, delay) => {
132
+ logger_1.default.warn(`Rate limit hit for [${this.type}]. Retrying attempt ${attempt}/${retryConfig.maxRetries} after ${Math.round(delay / 1000)}s...`);
133
+ },
134
+ };
135
+ return retryConfig;
136
+ }
117
137
  didDelete(item) {
118
138
  logger_1.default.info(`Deleted [${this.type}]: ${this.objString(item)}`);
119
139
  }
@@ -210,7 +230,6 @@ class APIHandler {
210
230
  return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
211
231
  type: this.type,
212
232
  assets: typeAssets,
213
- // @ts-ignore TODO: investigate what happens when `existing` is null
214
233
  existing,
215
234
  identifiers: this.identifiers,
216
235
  ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
@@ -243,7 +262,6 @@ class APIHandler {
243
262
  return (0, calculateDryRunChanges_1.calculateDryRunChanges)({
244
263
  type: this.type,
245
264
  assets: typeAssets,
246
- // @ts-ignore TODO: investigate what happens when `existing` is null
247
265
  existing,
248
266
  identifiers: this.identifiers,
249
267
  ignoreDryRunFields: this.getEffectiveIgnoreDryRunFields(),
@@ -282,14 +300,7 @@ class APIHandler {
282
300
  const conflicts = changes.conflicts || [];
283
301
  logger_1.default.debug(`Start processChanges for ${this.type} [delete:${del.length}] [update:${update.length}], [create:${create.length}], [conflicts:${conflicts.length}]`);
284
302
  // Set retry configuration from config
285
- const retryConfig = {
286
- maxRetries: this.config('AUTH0_MAX_RETRIES') || DEFAULT_MAX_RETRIES,
287
- initialDelay: this.config('AUTH0_RETRY_INITIAL_DELAY_MS') || DEFAULT_INITIAL_DELAY_MS,
288
- maxDelay: this.config('AUTH0_RETRY_MAX_DELAY_MS') || DEFAULT_MAX_DELAY_MS,
289
- onRetry: (error, attempt, delay) => {
290
- logger_1.default.warn(`Rate limit hit for [${this.type}]. Retrying attempt ${attempt}/${retryConfig.maxRetries} after ${Math.round(delay / 1000)}s...`);
291
- },
292
- };
303
+ const retryConfig = this.getRetryConfig();
293
304
  // Process Deleted
294
305
  if (del.length > 0) {
295
306
  const allowDelete = this.config('AUTH0_ALLOW_DELETE') === 'true' || this.config('AUTH0_ALLOW_DELETE') === true;
@@ -69,6 +69,7 @@ const forms = __importStar(require("./forms"));
69
69
  const flows = __importStar(require("./flows"));
70
70
  const flowVaultConnections = __importStar(require("./flowVaultConnections"));
71
71
  const selfServiceProfiles = __importStar(require("./selfServiceProfiles"));
72
+ const networkACLKeys = __importStar(require("./networkACLKeys"));
72
73
  const networkACLs = __importStar(require("./networkACLs"));
73
74
  const userAttributeProfiles = __importStar(require("./userAttributeProfiles"));
74
75
  const connectionProfiles = __importStar(require("./connectionProfiles"));
@@ -116,6 +117,7 @@ const auth0ApiHandlers = {
116
117
  flows,
117
118
  flowVaultConnections,
118
119
  selfServiceProfiles,
120
+ networkACLKeys,
119
121
  networkACLs,
120
122
  userAttributeProfiles,
121
123
  connectionProfiles,
@@ -0,0 +1,45 @@
1
+ import { Management } from 'auth0';
2
+ import DefaultAPIHandler from './default';
3
+ import { Asset, Assets, CalculatedChanges } from '../../../types';
4
+ export type NetworkAclKey = Management.NetworkAclKey & {
5
+ value?: string;
6
+ };
7
+ export declare const schema: {
8
+ type: string;
9
+ description: string;
10
+ items: {
11
+ type: string;
12
+ required: string[];
13
+ properties: {
14
+ id: {
15
+ type: string;
16
+ };
17
+ name: {
18
+ type: string;
19
+ maxLength: number;
20
+ };
21
+ alg: {
22
+ type: string;
23
+ enum: string[];
24
+ };
25
+ value: {
26
+ type: string;
27
+ };
28
+ fingerprint: {
29
+ type: string;
30
+ };
31
+ };
32
+ additionalProperties: boolean;
33
+ };
34
+ };
35
+ export default class NetworkACLKeysHandler extends DefaultAPIHandler {
36
+ existing: NetworkAclKey[] | null;
37
+ constructor(config: DefaultAPIHandler);
38
+ objString(key: NetworkAclKey): string;
39
+ getType(): Promise<Asset | null>;
40
+ processChanges(assets: Assets): Promise<void>;
41
+ createNetworkACLKey(key: NetworkAclKey): Promise<void>;
42
+ createNetworkACLKeys(creates: CalculatedChanges['create']): Promise<void>;
43
+ deleteNetworkACLKey(key: NetworkAclKey): Promise<void>;
44
+ deleteNetworkACLKeys(data: Asset[]): Promise<void>;
45
+ }