auth0-deploy-cli 8.30.0 → 8.32.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 (82) hide show
  1. package/.circleci/config.yml +17 -5
  2. package/AGENTS.md +21 -1
  3. package/CHANGELOG.md +48 -415
  4. package/CLAUDE.md +3 -0
  5. package/lib/args.d.ts +5 -0
  6. package/lib/args.js +23 -0
  7. package/lib/commands/export.js +5 -1
  8. package/lib/commands/import.js +40 -3
  9. package/lib/context/directory/handlers/actions.js +1 -2
  10. package/lib/context/directory/handlers/clients.js +14 -0
  11. package/lib/context/directory/handlers/connections.js +1 -0
  12. package/lib/context/directory/handlers/guardianFactors.js +8 -6
  13. package/lib/context/directory/handlers/tenant.d.ts +1 -6
  14. package/lib/context/directory/handlers/tenant.js +0 -1
  15. package/lib/context/directory/handlers/triggers.js +1 -3
  16. package/lib/context/index.js +5 -0
  17. package/lib/context/yaml/handlers/clients.js +12 -0
  18. package/lib/context/yaml/handlers/connections.js +1 -17
  19. package/lib/context/yaml/handlers/guardianFactors.js +3 -1
  20. package/lib/context/yaml/handlers/tenant.js +1 -1
  21. package/lib/context/yaml/index.js +2 -1
  22. package/lib/sessionDurationsToMinutes.d.ts +9 -7
  23. package/lib/sessionDurationsToMinutes.js +11 -10
  24. package/lib/tools/auth0/handlers/actions.d.ts +1 -0
  25. package/lib/tools/auth0/handlers/actions.js +36 -0
  26. package/lib/tools/auth0/handlers/attackProtection.js +15 -0
  27. package/lib/tools/auth0/handlers/branding.js +7 -0
  28. package/lib/tools/auth0/handlers/clientGrants.js +32 -4
  29. package/lib/tools/auth0/handlers/clients.d.ts +52 -2
  30. package/lib/tools/auth0/handlers/clients.js +175 -22
  31. package/lib/tools/auth0/handlers/connections.d.ts +1 -1
  32. package/lib/tools/auth0/handlers/connections.js +42 -6
  33. package/lib/tools/auth0/handlers/customDomains.d.ts +5 -0
  34. package/lib/tools/auth0/handlers/customDomains.js +26 -0
  35. package/lib/tools/auth0/handlers/databases.d.ts +91 -0
  36. package/lib/tools/auth0/handlers/databases.js +162 -2
  37. package/lib/tools/auth0/handlers/default.d.ts +4 -0
  38. package/lib/tools/auth0/handlers/default.js +82 -4
  39. package/lib/tools/auth0/handlers/emailProvider.js +8 -0
  40. package/lib/tools/auth0/handlers/emailTemplates.js +7 -0
  41. package/lib/tools/auth0/handlers/flowVaultConnections.js +6 -1
  42. package/lib/tools/auth0/handlers/flows.js +13 -4
  43. package/lib/tools/auth0/handlers/forms.js +10 -1
  44. package/lib/tools/auth0/handlers/guardianFactors.js +7 -1
  45. package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +8 -1
  46. package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +8 -1
  47. package/lib/tools/auth0/handlers/guardianPolicies.js +7 -0
  48. package/lib/tools/auth0/handlers/hooks.d.ts +1 -0
  49. package/lib/tools/auth0/handlers/hooks.js +10 -0
  50. package/lib/tools/auth0/handlers/organizations.d.ts +11 -1
  51. package/lib/tools/auth0/handlers/organizations.js +48 -52
  52. package/lib/tools/auth0/handlers/pages.js +7 -0
  53. package/lib/tools/auth0/handlers/phoneProvider.js +7 -0
  54. package/lib/tools/auth0/handlers/prompts.js +7 -0
  55. package/lib/tools/auth0/handlers/resourceServers.d.ts +1 -2
  56. package/lib/tools/auth0/handlers/resourceServers.js +9 -25
  57. package/lib/tools/auth0/handlers/roles.js +7 -0
  58. package/lib/tools/auth0/handlers/rules.d.ts +1 -0
  59. package/lib/tools/auth0/handlers/rules.js +9 -0
  60. package/lib/tools/auth0/handlers/rulesConfigs.d.ts +1 -0
  61. package/lib/tools/auth0/handlers/rulesConfigs.js +3 -0
  62. package/lib/tools/auth0/handlers/scimHandler.js +8 -1
  63. package/lib/tools/auth0/handlers/selfServiceProfiles.d.ts +1 -1
  64. package/lib/tools/auth0/handlers/selfServiceProfiles.js +10 -17
  65. package/lib/tools/auth0/handlers/tenant.d.ts +13 -1
  66. package/lib/tools/auth0/handlers/tenant.js +48 -4
  67. package/lib/tools/auth0/handlers/themes.js +11 -2
  68. package/lib/tools/auth0/handlers/triggers.js +6 -0
  69. package/lib/tools/auth0/handlers/userAttributeProfiles.js +16 -10
  70. package/lib/tools/auth0/index.d.ts +3 -0
  71. package/lib/tools/auth0/index.js +204 -0
  72. package/lib/tools/calculateChanges.d.ts +2 -2
  73. package/lib/tools/calculateChanges.js +21 -6
  74. package/lib/tools/calculateDryRunChanges.d.ts +71 -0
  75. package/lib/tools/calculateDryRunChanges.js +492 -0
  76. package/lib/tools/deploy.js +25 -1
  77. package/lib/tools/utils.d.ts +5 -0
  78. package/lib/tools/utils.js +64 -3
  79. package/lib/types.d.ts +17 -0
  80. package/lib/utils.d.ts +7 -0
  81. package/lib/utils.js +46 -2
  82. package/package.json +10 -6
@@ -1,5 +1,5 @@
1
1
  import { Management } from 'auth0';
2
- import { Assets, Auth0APIClient } from '../../../types';
2
+ import { Assets, Auth0APIClient, CalculatedChanges } from '../../../types';
3
3
  import DefaultAPIHandler from './default';
4
4
  export declare const schema: {
5
5
  type: string;
@@ -11,6 +11,22 @@ export declare const schema: {
11
11
  minLength: number;
12
12
  pattern: string;
13
13
  };
14
+ external_client_id: {
15
+ type: string;
16
+ description: string;
17
+ };
18
+ external_metadata_type: {
19
+ type: string;
20
+ description: string;
21
+ };
22
+ external_metadata_created_by: {
23
+ type: string;
24
+ description: string;
25
+ };
26
+ jwks_uri: {
27
+ type: string;
28
+ description: string;
29
+ };
14
30
  mobile: {
15
31
  type: string;
16
32
  properties: {
@@ -184,6 +200,35 @@ export declare const schema: {
184
200
  enum: string[];
185
201
  };
186
202
  };
203
+ my_organization_configuration: {
204
+ type: string[];
205
+ description: string;
206
+ properties: {
207
+ connection_profile_id: {
208
+ type: string;
209
+ description: string;
210
+ };
211
+ user_attribute_profile_id: {
212
+ type: string;
213
+ description: string;
214
+ };
215
+ allowed_strategies: {
216
+ type: string;
217
+ description: string;
218
+ items: {
219
+ type: string;
220
+ enum: ("samlp" | "pingfederate" | "adfs" | "waad" | "google-apps" | "okta" | "oidc")[];
221
+ };
222
+ uniqueItems: boolean;
223
+ };
224
+ connection_deletion_behavior: {
225
+ type: string;
226
+ enum: ("allow" | "allow_if_empty")[];
227
+ description: string;
228
+ };
229
+ };
230
+ required: string[];
231
+ };
187
232
  async_approval_notification_channels: {
188
233
  type: string[];
189
234
  description: string;
@@ -315,7 +360,12 @@ export default class ClientHandler extends DefaultAPIHandler {
315
360
  existing: Client[];
316
361
  constructor(config: DefaultAPIHandler);
317
362
  objString(item: any): string;
363
+ calcChanges(assets: Assets): Promise<CalculatedChanges>;
318
364
  processChanges(assets: Assets): Promise<void>;
319
365
  getType(): Promise<Management.Client[]>;
320
- sanitizeMapExpressConfiguration(auth0Client: Auth0APIClient, clientList: Client[]): Promise<Client[]>;
366
+ private isCimdClient;
367
+ private createClient;
368
+ private getCIMDEditableFields;
369
+ private updateClient;
370
+ sanitizeMapClientReferences(auth0Client: Auth0APIClient, clientList: Client[]): Promise<Client[]>;
321
371
  }
@@ -4,9 +4,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.schema = void 0;
7
+ const auth0_1 = require("auth0");
7
8
  const lodash_1 = require("lodash");
8
9
  const client_1 = require("../client");
9
10
  const default_1 = __importDefault(require("./default"));
11
+ const calculateChanges_1 = require("../../calculateChanges");
10
12
  const connectionProfiles_1 = require("./connectionProfiles");
11
13
  const userAttributeProfiles_1 = require("./userAttributeProfiles");
12
14
  const logger_1 = __importDefault(require("../../../logger"));
@@ -31,12 +33,57 @@ const multiResourceRefreshTokenPoliciesSchema = {
31
33
  required: ['audience', 'scope'],
32
34
  },
33
35
  };
36
+ const myOrganizationConfigurationSchema = {
37
+ type: ['object', 'null'],
38
+ description: 'Configuration related to the My Organization API for the client.',
39
+ properties: {
40
+ connection_profile_id: {
41
+ type: 'string',
42
+ description: 'The name of the connection profile to use for this application',
43
+ },
44
+ user_attribute_profile_id: {
45
+ type: 'string',
46
+ description: 'The name of the user attribute profile to use for this application',
47
+ },
48
+ allowed_strategies: {
49
+ type: 'array',
50
+ description: 'The allowed connection strategies for the My Organization configuration',
51
+ items: {
52
+ type: 'string',
53
+ enum: Object.values(auth0_1.Management.ClientMyOrganizationConfigurationAllowedStrategiesEnum),
54
+ },
55
+ uniqueItems: true,
56
+ },
57
+ connection_deletion_behavior: {
58
+ type: 'string',
59
+ enum: Object.values(auth0_1.Management.ClientMyOrganizationDeletionBehaviorEnum),
60
+ description: 'The deletion behavior for My Organization connections created by this client',
61
+ },
62
+ },
63
+ required: ['allowed_strategies', 'connection_deletion_behavior'],
64
+ };
34
65
  exports.schema = {
35
66
  type: 'array',
36
67
  items: {
37
68
  type: 'object',
38
69
  properties: {
39
70
  name: { type: 'string', minLength: 1, pattern: '[^<>]+' },
71
+ external_client_id: {
72
+ type: 'string',
73
+ description: 'Alternative identifier for the client. For CIMD clients, this is the HTTPS URL to the OAuth 2.0 Client ID Metadata Document. Client name should match the client_name value in the metadata document.',
74
+ },
75
+ external_metadata_type: {
76
+ type: 'string',
77
+ description: 'Type of external client registration metadata.',
78
+ },
79
+ external_metadata_created_by: {
80
+ type: 'string',
81
+ description: 'Indicates who created the external metadata client: admin for Management API, client for dynamic registration.',
82
+ },
83
+ jwks_uri: {
84
+ type: 'string',
85
+ description: 'JSON Web Key Set endpoint associated with the client.',
86
+ },
40
87
  mobile: {
41
88
  type: 'object',
42
89
  properties: {
@@ -177,6 +224,7 @@ exports.schema = {
177
224
  enum: ['email', 'organization_name'],
178
225
  },
179
226
  },
227
+ my_organization_configuration: myOrganizationConfigurationSchema,
180
228
  async_approval_notification_channels: {
181
229
  type: ['array', 'null'],
182
230
  description: 'An ordered array of notification channels enabled for CIBA (Client-Initiated Backchannel Authentication) requests. Channels are evaluated in the order specified.',
@@ -259,7 +307,7 @@ exports.schema = {
259
307
  description: 'List of enabled token exchange profile types for this client',
260
308
  items: {
261
309
  type: 'string',
262
- enum: ['custom_authentication'],
310
+ enum: ['custom_authentication', 'on_behalf_of_token_exchange'],
263
311
  },
264
312
  },
265
313
  },
@@ -376,6 +424,7 @@ class ClientHandler extends default_1.default {
376
424
  id: 'client_id',
377
425
  identifiers: ['client_id', 'name'],
378
426
  objectFields: ['client_metadata'],
427
+ stripCreateFields: ['external_metadata_type', 'external_metadata_created_by', 'jwks_uri'],
379
428
  stripUpdateFields: [
380
429
  // Fields not allowed during updates
381
430
  'callback_url_template',
@@ -384,18 +433,60 @@ class ClientHandler extends default_1.default {
384
433
  'tenant',
385
434
  'jwt_configuration.secret_encoded',
386
435
  'resource_server_identifier',
436
+ 'external_metadata_type',
437
+ 'external_metadata_created_by',
438
+ 'jwks_uri',
387
439
  ],
440
+ functions: {
441
+ create: (client) => this.createClient(client),
442
+ update: (clientId, client) => this.updateClient(clientId, client),
443
+ },
388
444
  });
389
445
  }
390
446
  objString(item) {
391
447
  return super.objString({ name: item.name, client_id: item.client_id });
392
448
  }
449
+ async calcChanges(assets) {
450
+ const clients = assets[this.type];
451
+ if (!clients) {
452
+ return { del: [], create: [], conflicts: [], update: [] };
453
+ }
454
+ const existing = await this.getType();
455
+ const allowDelete = !!this.config('AUTH0_ALLOW_DELETE');
456
+ const cimdClients = clients.filter((c) => this.isCimdClient(c));
457
+ const existingCimd = (existing || []).filter((c) => this.isCimdClient(c));
458
+ const regularClients = clients.filter((c) => !this.isCimdClient(c));
459
+ const existingRegular = (existing || []).filter((c) => !this.isCimdClient(c));
460
+ const regularChanges = (0, calculateChanges_1.calculateChanges)({
461
+ handler: this,
462
+ assets: regularClients,
463
+ existing: existingRegular,
464
+ identifiers: ['client_id', 'name'],
465
+ allowDelete,
466
+ });
467
+ // CIMD clients:
468
+ // If external_client_id changes (and no client_id match), old client is deleted
469
+ // and new registration is created with the new external_client_id.
470
+ const cimdChanges = (0, calculateChanges_1.calculateChanges)({
471
+ handler: this,
472
+ assets: cimdClients,
473
+ existing: existingCimd,
474
+ identifiers: ['client_id', 'external_client_id'],
475
+ allowDelete,
476
+ });
477
+ return {
478
+ del: [...regularChanges.del, ...cimdChanges.del],
479
+ update: [...regularChanges.update, ...cimdChanges.update],
480
+ create: [...regularChanges.create, ...cimdChanges.create],
481
+ conflicts: [...regularChanges.conflicts, ...cimdChanges.conflicts],
482
+ };
483
+ }
393
484
  async processChanges(assets) {
394
485
  const { clients } = assets;
395
486
  // Do nothing if not set
396
487
  if (!clients)
397
488
  return;
398
- assets.clients = await this.sanitizeMapExpressConfiguration(this.client, clients);
489
+ assets.clients = await this.sanitizeMapClientReferences(this.client, clients);
399
490
  const excludedClients = (assets.exclude && assets.exclude.clients) || [];
400
491
  const { del, update, create, conflicts } = await this.calcChanges(assets);
401
492
  // Always filter out the client we are using to access Auth0 Management API
@@ -453,37 +544,99 @@ class ClientHandler extends default_1.default {
453
544
  this.existing = createClientSanitizer(clients).sanitizeCrossOriginAuth(false).get();
454
545
  return this.existing;
455
546
  }
456
- // convert names back to IDs for express configuration
457
- async sanitizeMapExpressConfiguration(auth0Client, clientList) {
458
- // if no clients have express configuration, return early
459
- if (!clientList.some((p) => p.express_configuration)) {
547
+ isCimdClient(client) {
548
+ return !!client.external_client_id;
549
+ }
550
+ async createClient(client) {
551
+ if (!this.isCimdClient(client)) {
552
+ return this.client.clients.create(client);
553
+ }
554
+ const externalClientId = client.external_client_id;
555
+ const registration = await this.client.clients.registerCimdClient({
556
+ external_client_id: externalClientId,
557
+ });
558
+ return registration;
559
+ }
560
+ getCIMDEditableFields(client) {
561
+ // Only a subset of fields are editable for CIMD clients.
562
+ return (0, lodash_1.pick)(client, [
563
+ 'description',
564
+ 'app_type',
565
+ 'allowed_origins',
566
+ 'web_origins',
567
+ 'grant_types',
568
+ 'oidc_conformant',
569
+ 'organization_discovery_methods',
570
+ 'client_metadata',
571
+ 'default_organization',
572
+ 'require_proof_of_possession',
573
+ 'token_quota',
574
+ 'skip_non_verifiable_callback_uri_confirmation_prompt',
575
+ 'jwt_configuration',
576
+ 'refresh_token',
577
+ ]);
578
+ }
579
+ async updateClient(clientId, client) {
580
+ // For non-CIMD clients
581
+ if (!this.isCimdClient(client)) {
582
+ return this.client.clients.update(clientId, client);
583
+ }
584
+ const updatePayload = this.getCIMDEditableFields(client);
585
+ const registrationClientId = client.client_id || clientId;
586
+ if (registrationClientId && Object.keys(updatePayload).length > 0) {
587
+ return this.client.clients.update(registrationClientId, updatePayload);
588
+ }
589
+ return client;
590
+ }
591
+ // convert names back to IDs for client reference-based configuration
592
+ async sanitizeMapClientReferences(auth0Client, clientList) {
593
+ const hasExpressConfiguration = clientList.some((client) => client.express_configuration);
594
+ const hasMyOrganizationConfiguration = clientList.some((client) => client.my_organization_configuration);
595
+ if (!hasExpressConfiguration && !hasMyOrganizationConfiguration) {
460
596
  return clientList;
461
597
  }
462
598
  const clientData = await this.getType();
463
599
  const connectionProfiles = await (0, connectionProfiles_1.getConnectionProfile)(auth0Client);
464
600
  const userAttributeProfiles = await (0, userAttributeProfiles_1.getUserAttributeProfiles)(auth0Client);
465
601
  return clientList.map((client) => {
466
- if (!client.express_configuration)
602
+ if (client.express_configuration) {
603
+ const userAttributeProfileName = client.express_configuration.user_attribute_profile_id;
604
+ if (userAttributeProfileName) {
605
+ const userAttributeProfile = userAttributeProfiles?.find((uap) => uap.name === userAttributeProfileName);
606
+ if (userAttributeProfile?.id) {
607
+ client.express_configuration.user_attribute_profile_id = userAttributeProfile.id;
608
+ }
609
+ }
610
+ const connectionProfileName = client.express_configuration.connection_profile_id;
611
+ if (connectionProfileName) {
612
+ const connectionProfile = connectionProfiles?.find((cp) => cp.name === connectionProfileName);
613
+ if (connectionProfile?.id) {
614
+ client.express_configuration.connection_profile_id = connectionProfile.id;
615
+ }
616
+ }
617
+ const oktaOinClientName = client.express_configuration.okta_oin_client_id;
618
+ if (oktaOinClientName) {
619
+ const oktaOinClient = clientData?.find((c) => c.name === oktaOinClientName);
620
+ if (oktaOinClient?.client_id) {
621
+ client.express_configuration.okta_oin_client_id = oktaOinClient.client_id;
622
+ }
623
+ }
624
+ }
625
+ if (!client.my_organization_configuration) {
467
626
  return client;
468
- const userAttributeProfileName = client.express_configuration?.user_attribute_profile_id;
469
- if (userAttributeProfileName) {
470
- const userAttributeProfile = userAttributeProfiles?.find((uap) => uap.name === userAttributeProfileName);
627
+ }
628
+ const myOrganizationUserAttributeProfileName = client.my_organization_configuration.user_attribute_profile_id;
629
+ if (myOrganizationUserAttributeProfileName) {
630
+ const userAttributeProfile = userAttributeProfiles?.find((uap) => uap.name === myOrganizationUserAttributeProfileName);
471
631
  if (userAttributeProfile?.id) {
472
- client.express_configuration.user_attribute_profile_id = userAttributeProfile.id;
632
+ client.my_organization_configuration.user_attribute_profile_id = userAttributeProfile.id;
473
633
  }
474
634
  }
475
- const connectionProfileName = client.express_configuration.connection_profile_id;
476
- if (connectionProfileName) {
477
- const connectionProfile = connectionProfiles?.find((cp) => cp.name === connectionProfileName);
635
+ const myOrganizationConnectionProfileName = client.my_organization_configuration.connection_profile_id;
636
+ if (myOrganizationConnectionProfileName) {
637
+ const connectionProfile = connectionProfiles?.find((cp) => cp.name === myOrganizationConnectionProfileName);
478
638
  if (connectionProfile?.id) {
479
- client.express_configuration.connection_profile_id = connectionProfile.id;
480
- }
481
- }
482
- const oktaOinClientName = client.express_configuration.okta_oin_client_id;
483
- if (oktaOinClientName) {
484
- const oktaOinClient = clientData?.find((c) => c.name === oktaOinClientName);
485
- if (oktaOinClient?.client_id) {
486
- client.express_configuration.okta_oin_client_id = oktaOinClient.client_id;
639
+ client.my_organization_configuration.connection_profile_id = connectionProfile.id;
487
640
  }
488
641
  }
489
642
  return client;
@@ -19,7 +19,6 @@ export declare const schema: {
19
19
  properties: {
20
20
  dpop_signing_alg: {
21
21
  type: string;
22
- enum: ("ES256" | "Ed25519")[];
23
22
  };
24
23
  };
25
24
  };
@@ -196,6 +195,7 @@ export default class ConnectionsHandler extends DefaultAPIHandler {
196
195
  processConnectionDirectoryProvisioning(changes: CalculatedChanges): Promise<void>;
197
196
  getType(): Promise<Asset[] | null>;
198
197
  calcChanges(assets: Assets): Promise<CalculatedChanges>;
198
+ dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
199
199
  processChanges(assets: Assets): Promise<void>;
200
200
  }
201
201
  export {};
@@ -56,7 +56,6 @@ const connectionOptionsSchema = {
56
56
  properties: {
57
57
  dpop_signing_alg: {
58
58
  type: 'string',
59
- enum: Object.values(auth0_1.Management.ConnectionDpopSigningAlgEnum),
60
59
  },
61
60
  },
62
61
  };
@@ -544,11 +543,14 @@ class ConnectionsHandler extends default_1.default {
544
543
  });
545
544
  // Prepare an id map. We'll use this map later to get the `strategy` and SCIM enable status of the connections.
546
545
  await this.scimHandler.createIdMap(existingConnections);
547
- const formatted = connections.map((connection) => ({
548
- ...connection,
549
- ...this.getFormattedOptions(connection, clients),
550
- enabled_clients: (0, utils_1.getEnabledClients)(assets, connection, existingConnections, clients),
551
- }));
546
+ const formatted = connections.map((connection) => {
547
+ const enabledClients = (0, utils_1.getEnabledClients)(assets, connection, existingConnections, clients);
548
+ return {
549
+ ...connection,
550
+ ...this.getFormattedOptions(connection, clients),
551
+ ...(enabledClients !== undefined && { enabled_clients: enabledClients }),
552
+ };
553
+ });
552
554
  const proposedChanges = await super.calcChanges({ ...assets, connections: formatted });
553
555
  const proposedChangesWithExcludedProperties = (0, exports.addExcludedConnectionPropertiesToChanges)({
554
556
  proposedChanges,
@@ -557,6 +559,40 @@ class ConnectionsHandler extends default_1.default {
557
559
  });
558
560
  return proposedChangesWithExcludedProperties;
559
561
  }
562
+ async dryRunChanges(assets) {
563
+ const { connections } = assets;
564
+ if (!connections) {
565
+ return {
566
+ del: [],
567
+ create: [],
568
+ update: [],
569
+ conflicts: [],
570
+ };
571
+ }
572
+ const clients = await (0, client_1.paginate)(this.client.clients.list, {
573
+ paginate: true,
574
+ include_totals: true,
575
+ });
576
+ const existingConnections = await (0, client_1.paginate)(this.client.connections.list, {
577
+ checkpoint: true,
578
+ include_totals: true,
579
+ });
580
+ await this.scimHandler.createIdMap(existingConnections);
581
+ const formatted = connections.map((connection) => {
582
+ const enabledClients = (0, utils_1.getEnabledClients)(assets, connection, existingConnections, clients);
583
+ return {
584
+ ...connection,
585
+ ...this.getFormattedOptions(connection, clients),
586
+ ...(enabledClients !== undefined && { enabled_clients: enabledClients }),
587
+ };
588
+ });
589
+ const proposedChanges = await super.dryRunChanges({ ...assets, connections: formatted });
590
+ return (0, exports.addExcludedConnectionPropertiesToChanges)({
591
+ proposedChanges,
592
+ existingConnections,
593
+ config: this.config,
594
+ });
595
+ }
560
596
  // Run after clients are updated so we can convert all the enabled_clients names to id's
561
597
  async processChanges(assets) {
562
598
  const { connections } = assets;
@@ -50,6 +50,10 @@ export declare const schema: {
50
50
  type: string[];
51
51
  description: string;
52
52
  };
53
+ is_default: {
54
+ type: string;
55
+ description: string;
56
+ };
53
57
  };
54
58
  required: string[];
55
59
  };
@@ -60,6 +64,7 @@ export default class CustomDomainsHadnler extends DefaultAPIHandler {
60
64
  constructor(config: DefaultAPIHandler);
61
65
  objString(item: Asset): string;
62
66
  getType(): Promise<Asset | null>;
67
+ validate(assets: Assets): Promise<void>;
63
68
  processChanges(assets: Assets): Promise<void>;
64
69
  }
65
70
  export {};
@@ -44,6 +44,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
44
44
  Object.defineProperty(exports, "__esModule", { value: true });
45
45
  exports.schema = void 0;
46
46
  const default_1 = __importStar(require("./default"));
47
+ const validationError_1 = __importDefault(require("../../validationError"));
47
48
  const logger_1 = __importDefault(require("../../../logger"));
48
49
  exports.schema = {
49
50
  type: 'array',
@@ -81,6 +82,10 @@ exports.schema = {
81
82
  type: ['string'],
82
83
  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
84
  },
85
+ is_default: {
86
+ type: 'boolean',
87
+ description: 'Whether this custom domain is the default domain used for email notifications.',
88
+ },
84
89
  },
85
90
  required: ['domain', 'type'],
86
91
  },
@@ -136,6 +141,16 @@ class CustomDomainsHadnler extends default_1.default {
136
141
  throw err;
137
142
  }
138
143
  }
144
+ async validate(assets) {
145
+ await super.validate(assets);
146
+ const { customDomains } = assets;
147
+ if (!customDomains)
148
+ return;
149
+ const defaultDomains = customDomains.filter((d) => d.is_default === true);
150
+ if (defaultDomains.length > 1) {
151
+ throw new validationError_1.default(`Only one custom domain can be set as default (is_default: true), but found ${defaultDomains.length}: ${defaultDomains.map((d) => d.domain).join(', ')}`);
152
+ }
153
+ }
139
154
  async processChanges(assets) {
140
155
  const { customDomains } = assets;
141
156
  if (!customDomains)
@@ -149,6 +164,17 @@ class CustomDomainsHadnler extends default_1.default {
149
164
  }
150
165
  const changes = await this.calcChanges(assets);
151
166
  await super.processChanges(assets, changes);
167
+ // If a domain is marked as is_default, set it as the tenant's default custom domain.
168
+ const defaultDomain = customDomains.find((d) => d.is_default === true);
169
+ if (defaultDomain) {
170
+ try {
171
+ await this.client.customDomains.setDefault({ domain: defaultDomain.domain });
172
+ logger_1.default.info(`Set default custom domain: ${defaultDomain.domain}`);
173
+ }
174
+ catch (err) {
175
+ throw new Error(`Problem setting default custom domain ${defaultDomain.domain}\n${err}`);
176
+ }
177
+ }
152
178
  }
153
179
  }
154
180
  exports.default = CustomDomainsHadnler;
@@ -37,6 +37,11 @@ export declare const schema: {
37
37
  };
38
38
  api_behavior: {
39
39
  type: string;
40
+ enum: string[];
41
+ };
42
+ signup_behavior: {
43
+ type: string;
44
+ enum: string[];
40
45
  };
41
46
  };
42
47
  };
@@ -190,6 +195,90 @@ export declare const schema: {
190
195
  };
191
196
  };
192
197
  };
198
+ password_options: {
199
+ type: string;
200
+ properties: {
201
+ complexity: {
202
+ type: string;
203
+ properties: {
204
+ min_length: {
205
+ type: string;
206
+ minimum: number;
207
+ maximum: number;
208
+ };
209
+ character_types: {
210
+ type: string;
211
+ items: {
212
+ type: string;
213
+ enum: string[];
214
+ };
215
+ };
216
+ character_type_rule: {
217
+ type: string;
218
+ enum: string[];
219
+ };
220
+ identical_characters: {
221
+ type: string;
222
+ enum: string[];
223
+ };
224
+ sequential_characters: {
225
+ type: string;
226
+ enum: string[];
227
+ };
228
+ max_length_exceeded: {
229
+ type: string;
230
+ enum: string[];
231
+ };
232
+ };
233
+ };
234
+ profile_data: {
235
+ type: string;
236
+ properties: {
237
+ active: {
238
+ type: string;
239
+ };
240
+ blocked_fields: {
241
+ type: string;
242
+ items: {
243
+ type: string;
244
+ };
245
+ maxItems: number;
246
+ };
247
+ };
248
+ };
249
+ history: {
250
+ type: string;
251
+ properties: {
252
+ active: {
253
+ type: string;
254
+ };
255
+ size: {
256
+ type: string;
257
+ minimum: number;
258
+ maximum: number;
259
+ };
260
+ };
261
+ };
262
+ dictionary: {
263
+ type: string;
264
+ properties: {
265
+ active: {
266
+ type: string;
267
+ };
268
+ default: {
269
+ type: string;
270
+ enum: string[];
271
+ };
272
+ custom: {
273
+ type: string;
274
+ items: {
275
+ type: string;
276
+ };
277
+ };
278
+ };
279
+ };
280
+ };
281
+ };
193
282
  };
194
283
  };
195
284
  };
@@ -202,10 +291,12 @@ export default class DatabaseHandler extends DefaultAPIHandler {
202
291
  objString(db: any): string;
203
292
  getFormattedOptions(options: any, actions?: Action[]): any;
204
293
  validate(assets: Assets): Promise<void>;
294
+ private validatePasswordOptions;
205
295
  private validatePasswordlessSettings;
206
296
  private validateEmailUniqueConstraints;
207
297
  getClientFN(fn: 'create' | 'delete' | 'getAll' | 'update'): Function;
208
298
  getType(): Promise<Connection[]>;
209
299
  calcChanges(assets: Assets): Promise<CalculatedChanges>;
300
+ dryRunChanges(assets: Assets): Promise<CalculatedChanges>;
210
301
  processChanges(assets: Assets): Promise<void>;
211
302
  }