auth0-deploy-cli 9.0.0-beta.1 → 9.0.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/AGENTS.md +2 -357
- package/CHANGELOG.md +162 -6
- package/CLAUDE.md +138 -2
- package/README.md +1 -1
- package/lib/context/defaults.d.ts +7 -0
- package/lib/context/defaults.js +74 -30
- package/lib/context/directory/handlers/actionModules.js +8 -5
- package/lib/context/directory/handlers/actions.js +8 -4
- package/lib/context/directory/handlers/attackProtection.js +1 -1
- package/lib/context/directory/handlers/branding.js +4 -1
- package/lib/context/directory/handlers/clientAuthCredentials.d.ts +5 -0
- package/lib/context/directory/handlers/clientAuthCredentials.js +13 -0
- package/lib/context/directory/handlers/clientGrants.js +78 -24
- package/lib/context/directory/handlers/clients.js +20 -3
- package/lib/context/directory/handlers/connections.js +19 -5
- package/lib/context/directory/handlers/databases.js +2 -4
- package/lib/context/directory/handlers/emailTemplates.js +5 -0
- package/lib/context/directory/handlers/guardianEmailFactorSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianEmailFactorSettings.js +38 -0
- package/lib/context/directory/handlers/guardianPhoneFactorSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianPhoneFactorSettings.js +38 -0
- package/lib/context/directory/handlers/guardianSettings.d.ts +5 -0
- package/lib/context/directory/handlers/guardianSettings.js +38 -0
- package/lib/context/directory/handlers/hooks.js +8 -1
- package/lib/context/directory/handlers/index.js +12 -0
- package/lib/context/directory/handlers/networkACLKeys.d.ts +6 -0
- package/lib/context/directory/handlers/networkACLKeys.js +54 -0
- package/lib/context/directory/handlers/prompts.js +7 -3
- package/lib/context/directory/handlers/rateLimitPolicies.d.ts +6 -0
- package/lib/context/directory/handlers/rateLimitPolicies.js +53 -0
- package/lib/context/directory/handlers/rules.js +8 -1
- package/lib/context/directory/index.js +4 -7
- package/lib/context/index.js +31 -31
- package/lib/context/yaml/handlers/attackProtection.js +1 -1
- package/lib/context/yaml/handlers/branding.js +4 -1
- package/lib/context/yaml/handlers/clientAuthCredentials.d.ts +5 -0
- package/lib/context/yaml/handlers/clientAuthCredentials.js +13 -0
- package/lib/context/yaml/handlers/clients.js +19 -1
- package/lib/context/yaml/handlers/connections.js +8 -1
- package/lib/context/yaml/handlers/flows.js +3 -0
- package/lib/context/yaml/handlers/forms.js +3 -0
- package/lib/context/yaml/handlers/guardianEmailFactorSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianEmailFactorSettings.js +15 -0
- package/lib/context/yaml/handlers/guardianPhoneFactorSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianPhoneFactorSettings.js +15 -0
- package/lib/context/yaml/handlers/guardianSettings.d.ts +5 -0
- package/lib/context/yaml/handlers/guardianSettings.js +15 -0
- package/lib/context/yaml/handlers/index.js +12 -0
- package/lib/context/yaml/handlers/networkACLKeys.d.ts +6 -0
- package/lib/context/yaml/handlers/networkACLKeys.js +42 -0
- package/lib/context/yaml/handlers/prompts.js +3 -1
- package/lib/context/yaml/handlers/rateLimitPolicies.d.ts +6 -0
- package/lib/context/yaml/handlers/rateLimitPolicies.js +27 -0
- package/lib/context/yaml/index.js +3 -5
- package/lib/keywordPreservation.d.ts +1 -1
- package/lib/keywordPreservation.js +2 -1
- package/lib/readonly.js +5 -0
- package/lib/tools/auth0/handlers/attackProtection.js +19 -6
- package/lib/tools/auth0/handlers/clientAuthCredentials.d.ts +27 -0
- package/lib/tools/auth0/handlers/clientAuthCredentials.js +234 -0
- package/lib/tools/auth0/handlers/clientAuthCredentialsPre.d.ts +38 -0
- package/lib/tools/auth0/handlers/clientAuthCredentialsPre.js +123 -0
- package/lib/tools/auth0/handlers/clientGrants.d.ts +1 -1
- package/lib/tools/auth0/handlers/clients.d.ts +106 -0
- package/lib/tools/auth0/handlers/clients.js +206 -2
- package/lib/tools/auth0/handlers/connectionProfiles.d.ts +27 -0
- package/lib/tools/auth0/handlers/connectionProfiles.js +30 -0
- package/lib/tools/auth0/handlers/connections.d.ts +32 -6
- package/lib/tools/auth0/handlers/connections.js +49 -7
- package/lib/tools/auth0/handlers/databases.d.ts +28 -0
- package/lib/tools/auth0/handlers/databases.js +58 -24
- package/lib/tools/auth0/handlers/default.d.ts +23 -0
- package/lib/tools/auth0/handlers/default.js +47 -29
- package/lib/tools/auth0/handlers/eventStreams.js +10 -2
- package/lib/tools/auth0/handlers/guardianEmailFactorSettings.d.ts +22 -0
- package/lib/tools/auth0/handlers/guardianEmailFactorSettings.js +77 -0
- package/lib/tools/auth0/handlers/guardianFactorTemplates.js +13 -4
- package/lib/tools/auth0/handlers/guardianPhoneFactorMessageTypes.js +11 -9
- package/lib/tools/auth0/handlers/guardianPhoneFactorSelectedProvider.js +11 -9
- package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.d.ts +22 -0
- package/lib/tools/auth0/handlers/guardianPhoneFactorSettings.js +77 -0
- package/lib/tools/auth0/handlers/guardianPolicies.js +11 -1
- package/lib/tools/auth0/handlers/guardianSettings.d.ts +30 -0
- package/lib/tools/auth0/handlers/guardianSettings.js +85 -0
- package/lib/tools/auth0/handlers/hooks.js +1 -1
- package/lib/tools/auth0/handlers/index.js +16 -0
- package/lib/tools/auth0/handlers/networkACLKeys.d.ts +45 -0
- package/lib/tools/auth0/handlers/networkACLKeys.js +177 -0
- package/lib/tools/auth0/handlers/networkACLs.d.ts +132 -2
- package/lib/tools/auth0/handlers/networkACLs.js +100 -16
- package/lib/tools/auth0/handlers/organizations.d.ts +33 -1
- package/lib/tools/auth0/handlers/organizations.js +177 -19
- package/lib/tools/auth0/handlers/phoneProvider.js +10 -2
- package/lib/tools/auth0/handlers/phoneTemplates.d.ts +4 -1
- package/lib/tools/auth0/handlers/phoneTemplates.js +67 -10
- package/lib/tools/auth0/handlers/prompts.js +1 -1
- package/lib/tools/auth0/handlers/rateLimitPolicies.d.ts +81 -0
- package/lib/tools/auth0/handlers/rateLimitPolicies.js +203 -0
- package/lib/tools/auth0/handlers/resourceServers.d.ts +44 -0
- package/lib/tools/auth0/handlers/resourceServers.js +44 -0
- package/lib/tools/auth0/handlers/riskAssessment.d.ts +1 -1
- package/lib/tools/auth0/handlers/riskAssessment.js +19 -1
- package/lib/tools/auth0/handlers/roles.d.ts +4 -0
- package/lib/tools/auth0/handlers/roles.js +10 -0
- package/lib/tools/auth0/handlers/rules.js +19 -7
- package/lib/tools/auth0/handlers/tenant.d.ts +45 -0
- package/lib/tools/auth0/handlers/tenant.js +48 -0
- package/lib/tools/auth0/handlers/themes.d.ts +37 -1
- package/lib/tools/auth0/handlers/themes.js +64 -0
- package/lib/tools/auth0/handlers/tokenExchangeProfiles.js +3 -1
- package/lib/tools/auth0/index.js +12 -6
- package/lib/tools/calculateDryRunChanges.js +12 -8
- package/lib/tools/constants.d.ts +2 -0
- package/lib/tools/constants.js +3 -0
- package/lib/tools/utils.d.ts +3 -0
- package/lib/tools/utils.js +41 -2
- package/lib/types.d.ts +9 -1
- package/lib/utils.d.ts +6 -0
- package/lib/utils.js +17 -2
- package/package.json +2 -2
- package/references/code-style.md +133 -0
- package/references/commands.md +98 -0
- package/references/docs-update.md +34 -0
- package/references/git-workflow.md +135 -0
- package/references/pitfalls.md +62 -0
- package/references/testing.md +118 -0
|
@@ -51,6 +51,12 @@ const logger_1 = __importDefault(require("../../../logger"));
|
|
|
51
51
|
const client_1 = require("../client");
|
|
52
52
|
const utils_1 = require("../../../utils");
|
|
53
53
|
const utils_2 = require("../../utils");
|
|
54
|
+
// Org sub-resources are skipped when the tenant can't read them: the EA feature is off
|
|
55
|
+
// (feature_not_enabled, returned as 400 or 403) or the token lacks scope (403). The SDK
|
|
56
|
+
// puts the API code on `err.body.errorCode`, not `err.errorCode`.
|
|
57
|
+
function isOrgSubresourceUnavailable(err) {
|
|
58
|
+
return err?.statusCode === 403 || err?.body?.errorCode === 'feature_not_enabled';
|
|
59
|
+
}
|
|
54
60
|
exports.schema = {
|
|
55
61
|
type: 'array',
|
|
56
62
|
items: {
|
|
@@ -127,6 +133,23 @@ exports.schema = {
|
|
|
127
133
|
required: ['domain', 'status'],
|
|
128
134
|
},
|
|
129
135
|
},
|
|
136
|
+
third_party_client_access: {
|
|
137
|
+
type: 'string',
|
|
138
|
+
enum: Object.values(auth0_1.Management.OrganizationThirdPartyClientAccessEnum),
|
|
139
|
+
},
|
|
140
|
+
is_app_entitlement_active: { type: 'boolean' },
|
|
141
|
+
clients: {
|
|
142
|
+
type: 'array',
|
|
143
|
+
items: {
|
|
144
|
+
type: 'object',
|
|
145
|
+
properties: {
|
|
146
|
+
client_id: { type: 'string' },
|
|
147
|
+
use_for_member_access: { type: 'boolean' },
|
|
148
|
+
},
|
|
149
|
+
required: ['client_id', 'use_for_member_access'],
|
|
150
|
+
},
|
|
151
|
+
default: [],
|
|
152
|
+
},
|
|
130
153
|
},
|
|
131
154
|
required: ['name'],
|
|
132
155
|
},
|
|
@@ -168,6 +191,7 @@ class OrganizationsHandler extends default_1.default {
|
|
|
168
191
|
const organization = { ...org };
|
|
169
192
|
delete organization.connections;
|
|
170
193
|
delete organization.client_grants;
|
|
194
|
+
delete organization.clients;
|
|
171
195
|
if ('discovery_domains' in organization) {
|
|
172
196
|
delete organization.discovery_domains;
|
|
173
197
|
}
|
|
@@ -176,8 +200,9 @@ class OrganizationsHandler extends default_1.default {
|
|
|
176
200
|
throw new Error(`Organization "${organization.name}" was created but the response did not include an ID. Skipping connection/grant association.`);
|
|
177
201
|
}
|
|
178
202
|
const createdId = created.id;
|
|
203
|
+
const retryConfig = this.getRetryConfig();
|
|
179
204
|
if (typeof org.connections !== 'undefined' && org.connections.length > 0) {
|
|
180
|
-
await Promise.all(org.connections.map((conn) => this.client.organizations.connections.create(createdId, conn)));
|
|
205
|
+
await Promise.all(org.connections.map((conn) => (0, default_1.retryWithExponentialBackoff)(() => this.client.organizations.connections.create(createdId, conn), retryConfig)));
|
|
181
206
|
}
|
|
182
207
|
if (typeof org.client_grants !== 'undefined' && org.client_grants.length > 0) {
|
|
183
208
|
await Promise.all(org.client_grants.map((organizationClientGrants) => this.createOrganizationClientGrants(createdId, this.getClientGrantIDByClientName(organizationClientGrants.client_id))));
|
|
@@ -191,6 +216,19 @@ class OrganizationsHandler extends default_1.default {
|
|
|
191
216
|
throw new Error(`Problem creating discovery domain ${discoveryDomain?.domain} for organization ${createdId}\n${err}`);
|
|
192
217
|
})));
|
|
193
218
|
}
|
|
219
|
+
if (typeof org.clients !== 'undefined' && org.clients.length > 0) {
|
|
220
|
+
const clientsToCreate = org.clients
|
|
221
|
+
.map((oc) => ({
|
|
222
|
+
client_id: this.getClientIdByClientName(oc.client_id),
|
|
223
|
+
use_for_member_access: oc.use_for_member_access,
|
|
224
|
+
}))
|
|
225
|
+
.filter((oc) => !!oc.client_id);
|
|
226
|
+
if (clientsToCreate.length > 0) {
|
|
227
|
+
await this.createOrganizationClients(createdId, clientsToCreate).catch((err) => {
|
|
228
|
+
throw new Error(`Problem creating org clients for organization ${createdId}\n${err}`);
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
}
|
|
194
232
|
return created;
|
|
195
233
|
}
|
|
196
234
|
async createOrganizations(creates) {
|
|
@@ -209,15 +247,24 @@ class OrganizationsHandler extends default_1.default {
|
|
|
209
247
|
.promise();
|
|
210
248
|
}
|
|
211
249
|
async updateOrganization(org, organizations) {
|
|
212
|
-
const
|
|
250
|
+
const existingOrg = organizations.find((orgToUpdate) => orgToUpdate.name === org.name);
|
|
251
|
+
const { connections: existingConnections, client_grants: existingClientGrants, discovery_domains: existingDiscoveryDomains, clients: existingOrgClients = [], } = existingOrg;
|
|
213
252
|
const params = { id: org.id };
|
|
214
|
-
const { connections, client_grants: organizationClientGrants, discovery_domains: organizationDiscoveryDomains, } = org;
|
|
253
|
+
const { connections, client_grants: organizationClientGrants, discovery_domains: organizationDiscoveryDomains, clients: organizationClients, } = org;
|
|
215
254
|
delete org.connections;
|
|
216
255
|
delete org.name;
|
|
217
256
|
delete org.id;
|
|
218
257
|
delete org.client_grants;
|
|
219
258
|
delete org.discovery_domains;
|
|
220
|
-
|
|
259
|
+
delete org.clients;
|
|
260
|
+
// Only PATCH if top-level properties actually differ from the existing state.
|
|
261
|
+
// Compare only the keys present in the desired config against those same keys
|
|
262
|
+
// on the remote org, so that fields the user didn't specify are not considered.
|
|
263
|
+
let changed = false;
|
|
264
|
+
if (!(0, lodash_1.isEqual)(org, (0, lodash_1.pick)(existingOrg, Object.keys(org)))) {
|
|
265
|
+
await this.client.organizations.update(params.id, org);
|
|
266
|
+
changed = true;
|
|
267
|
+
}
|
|
221
268
|
// organization connections
|
|
222
269
|
const connectionsToRemove = existingConnections.filter((c) => !connections.find((x) => x.connection_id === c.connection_id));
|
|
223
270
|
const connectionsToAdd = connections.filter((c) => !existingConnections.find((x) => x.connection_id === c.connection_id));
|
|
@@ -228,27 +275,27 @@ class OrganizationsHandler extends default_1.default {
|
|
|
228
275
|
x.organization_access_level !== c.organization_access_level ||
|
|
229
276
|
x.organization_connection_name !== c.organization_connection_name ||
|
|
230
277
|
x.is_enabled !== (c.is_enabled ?? true))));
|
|
278
|
+
if (connectionsToUpdate.length > 0 ||
|
|
279
|
+
connectionsToAdd.length > 0 ||
|
|
280
|
+
connectionsToRemove.length > 0) {
|
|
281
|
+
changed = true;
|
|
282
|
+
}
|
|
283
|
+
const retryConfig = this.getRetryConfig();
|
|
231
284
|
// Handle updates first
|
|
232
|
-
await Promise.all(connectionsToUpdate.map((conn) => this.client.organizations.connections
|
|
233
|
-
.update(params.id, conn.connection_id, {
|
|
285
|
+
await Promise.all(connectionsToUpdate.map((conn) => (0, default_1.retryWithExponentialBackoff)(() => this.client.organizations.connections.update(params.id, conn.connection_id, {
|
|
234
286
|
organization_connection_name: conn.organization_connection_name,
|
|
235
287
|
assign_membership_on_login: conn.assign_membership_on_login,
|
|
236
288
|
show_as_button: conn.show_as_button,
|
|
237
289
|
is_signup_enabled: conn.is_signup_enabled,
|
|
238
290
|
is_enabled: conn.is_enabled,
|
|
239
291
|
organization_access_level: conn.organization_access_level,
|
|
240
|
-
})
|
|
241
|
-
.catch(() => {
|
|
292
|
+
}), retryConfig).catch(() => {
|
|
242
293
|
throw new Error(`Problem updating Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
|
|
243
294
|
})));
|
|
244
|
-
await Promise.all(connectionsToAdd.map((conn) => this.client.organizations.connections
|
|
245
|
-
.create(params.id, (0, lodash_1.omit)(conn, 'connection'))
|
|
246
|
-
.catch(() => {
|
|
295
|
+
await Promise.all(connectionsToAdd.map((conn) => (0, default_1.retryWithExponentialBackoff)(() => this.client.organizations.connections.create(params.id, (0, lodash_1.omit)(conn, 'connection')), retryConfig).catch(() => {
|
|
247
296
|
throw new Error(`Problem adding Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
|
|
248
297
|
})));
|
|
249
|
-
await Promise.all(connectionsToRemove.map((conn) => this.client.organizations.connections
|
|
250
|
-
.delete(params.id, conn.connection_id)
|
|
251
|
-
.catch(() => {
|
|
298
|
+
await Promise.all(connectionsToRemove.map((conn) => (0, default_1.retryWithExponentialBackoff)(() => this.client.organizations.connections.delete(params.id, conn.connection_id), retryConfig).catch(() => {
|
|
252
299
|
throw new Error(`Problem removing Enabled Connection ${conn.connection_id} for organizations ${params.id}`);
|
|
253
300
|
})));
|
|
254
301
|
// organization client_grants
|
|
@@ -262,6 +309,9 @@ class OrganizationsHandler extends default_1.default {
|
|
|
262
309
|
?.map((clientGrant) => ({
|
|
263
310
|
grant_id: this.getClientGrantIDByClientName(clientGrant.client_id),
|
|
264
311
|
})) || [];
|
|
312
|
+
if (orgClientGrantsToAdd.length > 0 || orgClientGrantsToRemove.length > 0) {
|
|
313
|
+
changed = true;
|
|
314
|
+
}
|
|
265
315
|
// Handle updates first
|
|
266
316
|
await Promise.all(orgClientGrantsToAdd.map((orgClientGrant) => this.createOrganizationClientGrants(params.id, orgClientGrant.grant_id).catch(() => {
|
|
267
317
|
throw new Error(`Problem adding organization clientGrant ${orgClientGrant.grant_id} for organizations ${params.id}`);
|
|
@@ -283,6 +333,9 @@ class OrganizationsHandler extends default_1.default {
|
|
|
283
333
|
};
|
|
284
334
|
})
|
|
285
335
|
.filter(Boolean) || [];
|
|
336
|
+
if (orgDiscoveryDomainsToUpdate.length > 0 || orgDiscoveryDomainsToAdd.length > 0) {
|
|
337
|
+
changed = true;
|
|
338
|
+
}
|
|
286
339
|
for (const { id, domain, ...updateParams } of orgDiscoveryDomainsToUpdate) {
|
|
287
340
|
try {
|
|
288
341
|
await this.updateOrganizationDiscoveryDomain(params.id, id, domain, updateParams);
|
|
@@ -306,6 +359,7 @@ class OrganizationsHandler extends default_1.default {
|
|
|
306
359
|
if (orgDiscoveryDomainsToRemove.length > 0) {
|
|
307
360
|
if (this.config('AUTH0_ALLOW_DELETE') === 'true' ||
|
|
308
361
|
this.config('AUTH0_ALLOW_DELETE') === true) {
|
|
362
|
+
changed = true;
|
|
309
363
|
for (const domain of orgDiscoveryDomainsToRemove) {
|
|
310
364
|
try {
|
|
311
365
|
await this.deleteOrganizationDiscoveryDomain(params.id, domain.domain, domain.id);
|
|
@@ -320,12 +374,66 @@ class OrganizationsHandler extends default_1.default {
|
|
|
320
374
|
\n${orgDiscoveryDomainsToRemove.map((i) => this.objString(i)).join('\n')}`);
|
|
321
375
|
}
|
|
322
376
|
}
|
|
323
|
-
|
|
377
|
+
// organization clients
|
|
378
|
+
const orgClientsToAdd = (organizationClients || [])
|
|
379
|
+
.filter((c) => !existingOrgClients.find((x) => x.client_id === c.client_id))
|
|
380
|
+
.map((oc) => ({
|
|
381
|
+
client_id: this.getClientIdByClientName(oc.client_id),
|
|
382
|
+
use_for_member_access: oc.use_for_member_access,
|
|
383
|
+
}))
|
|
384
|
+
.filter((oc) => !!oc.client_id);
|
|
385
|
+
const orgClientsToRemove = (existingOrgClients || [])
|
|
386
|
+
.filter((c) => !(organizationClients || []).find((x) => x.client_id === c.client_id))
|
|
387
|
+
.map((oc) => this.getClientIdByClientName(oc.client_id))
|
|
388
|
+
.filter(Boolean);
|
|
389
|
+
const orgClientsToUpdate = (organizationClients || [])
|
|
390
|
+
.filter((c) => {
|
|
391
|
+
const existing = existingOrgClients.find((x) => x.client_id === c.client_id);
|
|
392
|
+
return existing && existing.use_for_member_access !== c.use_for_member_access;
|
|
393
|
+
})
|
|
394
|
+
.map((oc) => ({
|
|
395
|
+
client_id: this.getClientIdByClientName(oc.client_id),
|
|
396
|
+
use_for_member_access: oc.use_for_member_access,
|
|
397
|
+
}))
|
|
398
|
+
.filter((oc) => !!oc.client_id);
|
|
399
|
+
if (orgClientsToAdd.length > 0) {
|
|
400
|
+
changed = true;
|
|
401
|
+
await this.createOrganizationClients(params.id, orgClientsToAdd).catch((err) => {
|
|
402
|
+
throw new Error(`Problem adding org clients for organization ${params.id}\n${err}`);
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
if (orgClientsToRemove.length > 0) {
|
|
406
|
+
if (this.config('AUTH0_ALLOW_DELETE') === 'true' ||
|
|
407
|
+
this.config('AUTH0_ALLOW_DELETE') === true) {
|
|
408
|
+
changed = true;
|
|
409
|
+
await this.deleteOrganizationClients(params.id, orgClientsToRemove).catch((err) => {
|
|
410
|
+
throw new Error(`Problem removing org clients for organization ${params.id}\n${err}`);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
logger_1.default.warn(`Detected the following organization client associations should be removed. Doing so may be destructive.\nYou can enable deletes by setting 'AUTH0_ALLOW_DELETE' to true in the config\n${orgClientsToRemove.join('\n')}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (orgClientsToUpdate.length > 0) {
|
|
418
|
+
changed = true;
|
|
419
|
+
}
|
|
420
|
+
await Promise.all(orgClientsToUpdate.map((oc) => this.client.organizations.clients
|
|
421
|
+
.update(params.id, oc.client_id, {
|
|
422
|
+
use_for_member_access: oc.use_for_member_access,
|
|
423
|
+
})
|
|
424
|
+
.catch((err) => {
|
|
425
|
+
throw new Error(`Problem updating org client ${oc.client_id} for organization ${params.id}\n${err}`);
|
|
426
|
+
})));
|
|
427
|
+
return changed ? params : null;
|
|
324
428
|
}
|
|
325
429
|
getClientGrantIDByClientName(clientsName) {
|
|
326
430
|
const found = this.formattedClientGrants.find((c) => c.client_id === clientsName);
|
|
327
431
|
return found?.grant_id || '';
|
|
328
432
|
}
|
|
433
|
+
getClientIdByClientName(clientName) {
|
|
434
|
+
const found = this.allClients?.find((c) => c.name === clientName);
|
|
435
|
+
return found?.client_id || '';
|
|
436
|
+
}
|
|
329
437
|
async getFormattedClientGrants() {
|
|
330
438
|
const [clients, clientGrants] = await Promise.all([
|
|
331
439
|
(0, client_1.paginate)(this.client.clients.list, {
|
|
@@ -335,6 +443,8 @@ class OrganizationsHandler extends default_1.default {
|
|
|
335
443
|
paginate: true,
|
|
336
444
|
}),
|
|
337
445
|
]);
|
|
446
|
+
// Store clients for org-client name→ID resolution
|
|
447
|
+
this.allClients = clients;
|
|
338
448
|
// Convert clients by name to the id and store it in the formattedClientGrants
|
|
339
449
|
const formattedClientGrantsMapping = clientGrants?.map((clientGrant) => {
|
|
340
450
|
const { id, client_id: clientName } = clientGrant;
|
|
@@ -352,8 +462,10 @@ class OrganizationsHandler extends default_1.default {
|
|
|
352
462
|
data: updates || [],
|
|
353
463
|
generator: (item) => this.updateOrganization(item, orgs)
|
|
354
464
|
.then((data) => {
|
|
355
|
-
|
|
356
|
-
|
|
465
|
+
if (data) {
|
|
466
|
+
this.didUpdate(data);
|
|
467
|
+
this.updated += 1;
|
|
468
|
+
}
|
|
357
469
|
})
|
|
358
470
|
.catch((err) => {
|
|
359
471
|
throw new Error(`Problem updating ${this.type} ${this.objString(item)}\n${err}`);
|
|
@@ -390,6 +502,14 @@ class OrganizationsHandler extends default_1.default {
|
|
|
390
502
|
if (organizationDiscoveryDomains) {
|
|
391
503
|
org.discovery_domains = organizationDiscoveryDomains;
|
|
392
504
|
}
|
|
505
|
+
// Get org-client associations
|
|
506
|
+
const orgClients = await this.getAllOrganizationClients(org.id);
|
|
507
|
+
if (orgClients) {
|
|
508
|
+
org.clients = orgClients.map((oc) => ({
|
|
509
|
+
client_id: (0, utils_1.convertClientIdToName)(oc.client_id, clients),
|
|
510
|
+
use_for_member_access: oc.use_for_member_access,
|
|
511
|
+
}));
|
|
512
|
+
}
|
|
393
513
|
}
|
|
394
514
|
this.existing = organizations;
|
|
395
515
|
return this.existing;
|
|
@@ -504,8 +624,8 @@ class OrganizationsHandler extends default_1.default {
|
|
|
504
624
|
if (err.statusCode === 404 || err.statusCode === 501) {
|
|
505
625
|
return null;
|
|
506
626
|
}
|
|
507
|
-
if (err
|
|
508
|
-
logger_1.default.debug(
|
|
627
|
+
if (isOrgSubresourceUnavailable(err)) {
|
|
628
|
+
logger_1.default.debug(`Skipping organization discovery domains (${err?.body?.errorCode ?? err.statusCode}).`);
|
|
509
629
|
return null;
|
|
510
630
|
}
|
|
511
631
|
throw err;
|
|
@@ -535,6 +655,44 @@ class OrganizationsHandler extends default_1.default {
|
|
|
535
655
|
logger_1.default.debug(`Deleting discovery domain ${discoveryDomain} for organization ${organizationId}`);
|
|
536
656
|
await this.client.organizations.discoveryDomains.delete(organizationId, discoveryDomainId);
|
|
537
657
|
}
|
|
658
|
+
async getAllOrganizationClients(organizationId) {
|
|
659
|
+
const allOrgClients = [];
|
|
660
|
+
try {
|
|
661
|
+
let orgClients = await this.client.organizations.clients.list(organizationId);
|
|
662
|
+
allOrgClients.push(...orgClients.data);
|
|
663
|
+
while (orgClients.hasNextPage()) {
|
|
664
|
+
orgClients = await orgClients.getNextPage();
|
|
665
|
+
allOrgClients.push(...orgClients.data);
|
|
666
|
+
}
|
|
667
|
+
return allOrgClients;
|
|
668
|
+
}
|
|
669
|
+
catch (err) {
|
|
670
|
+
if (err.statusCode === 404 || err.statusCode === 501) {
|
|
671
|
+
return null;
|
|
672
|
+
}
|
|
673
|
+
if (isOrgSubresourceUnavailable(err)) {
|
|
674
|
+
logger_1.default.debug(`Skipping org-client associations (${err?.body?.errorCode ?? err.statusCode}).`);
|
|
675
|
+
return null;
|
|
676
|
+
}
|
|
677
|
+
throw err;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
async createOrganizationClients(organizationId, clients) {
|
|
681
|
+
const BATCH_SIZE = 10;
|
|
682
|
+
for (let i = 0; i < clients.length; i += BATCH_SIZE) {
|
|
683
|
+
const batch = clients.slice(i, i + BATCH_SIZE);
|
|
684
|
+
logger_1.default.debug(`Creating ${batch.length} org client(s) for organization ${organizationId}`);
|
|
685
|
+
await this.client.organizations.clients.create(organizationId, { clients: batch });
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
async deleteOrganizationClients(organizationId, clientIds) {
|
|
689
|
+
const BATCH_SIZE = 10;
|
|
690
|
+
for (let i = 0; i < clientIds.length; i += BATCH_SIZE) {
|
|
691
|
+
const batch = clientIds.slice(i, i + BATCH_SIZE);
|
|
692
|
+
logger_1.default.debug(`Deleting ${batch.length} org client(s) for organization ${organizationId}`);
|
|
693
|
+
await this.client.organizations.clients.delete(organizationId, { clients: batch });
|
|
694
|
+
}
|
|
695
|
+
}
|
|
538
696
|
}
|
|
539
697
|
exports.default = OrganizationsHandler;
|
|
540
698
|
__decorate([
|
|
@@ -202,12 +202,20 @@ class PhoneProviderHandler extends default_1.default {
|
|
|
202
202
|
}
|
|
203
203
|
const currentProviders = await this.getPhoneProviders();
|
|
204
204
|
const providerReqPayload = (() => {
|
|
205
|
+
// Work on a shallow copy so we don't mutate the caller's asset (phoneProviders[0]).
|
|
206
|
+
// The SDK response type doesn't declare `credentials`, so widen it here.
|
|
207
|
+
const payload = { ...phoneProviders[0] };
|
|
205
208
|
// Removing id from update and create payloads, otherwise API will error
|
|
206
209
|
// id may be required to handle if `--export_ids=true`
|
|
207
|
-
|
|
208
|
-
if (payload && 'id' in payload) {
|
|
210
|
+
if ('id' in payload) {
|
|
209
211
|
delete payload.id;
|
|
210
212
|
}
|
|
213
|
+
// The `custom` provider requires a `credentials` object in the payload even
|
|
214
|
+
// when it is empty. Exported configs omit credentials, so inject an empty
|
|
215
|
+
// object here to avoid a "Missing required property: credentials" 400 error.
|
|
216
|
+
if (payload.name === 'custom' && payload.credentials == null) {
|
|
217
|
+
payload.credentials = {};
|
|
218
|
+
}
|
|
211
219
|
return payload;
|
|
212
220
|
})();
|
|
213
221
|
if (currentProviders === null || currentProviders.length === 0) {
|
|
@@ -54,7 +54,10 @@ export default class PhoneTemplatesHandler extends DefaultHandler {
|
|
|
54
54
|
objString(template: any): string;
|
|
55
55
|
getType(): Promise<PhoneTemplate[]>;
|
|
56
56
|
processChanges(assets: Assets): Promise<void>;
|
|
57
|
-
createPhoneTemplate(template: any): Promise<
|
|
57
|
+
createPhoneTemplate(template: any): Promise<{
|
|
58
|
+
asset: Asset;
|
|
59
|
+
action: 'create' | 'update';
|
|
60
|
+
}>;
|
|
58
61
|
createPhoneTemplates(creates: CalculatedChanges['create']): Promise<void>;
|
|
59
62
|
updatePhoneTemplate(template: any): Promise<Asset>;
|
|
60
63
|
updatePhoneTemplates(updates: CalculatedChanges['update']): Promise<void>;
|
|
@@ -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 utils_1 = require("../../utils");
|
|
47
48
|
const logger_1 = __importDefault(require("../../../logger"));
|
|
48
49
|
exports.schema = {
|
|
49
50
|
type: 'array',
|
|
@@ -121,25 +122,77 @@ class PhoneTemplatesHandler extends default_1.default {
|
|
|
121
122
|
if (del.length > 0) {
|
|
122
123
|
await this.deletePhoneTemplates(del);
|
|
123
124
|
}
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
// On newly created tenants the phone templates returned by the API have no
|
|
126
|
+
// ID until they are explicitly created. calcChanges matches assets by `type`
|
|
127
|
+
// and routes them all to `update`, but PATCH requires an ID. Split out the
|
|
128
|
+
// templates whose existing counterpart has no ID yet and create them instead.
|
|
129
|
+
const missingId = [];
|
|
130
|
+
const hasId = [];
|
|
131
|
+
update.forEach((template) => {
|
|
132
|
+
const existing = this.existing?.find((t) => t.type === template.type);
|
|
133
|
+
if (existing?.id) {
|
|
134
|
+
hasId.push(template);
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
missingId.push(template);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
const toCreate = [...create, ...missingId];
|
|
141
|
+
if (toCreate.length > 0) {
|
|
142
|
+
await this.createPhoneTemplates(toCreate);
|
|
126
143
|
}
|
|
127
|
-
if (
|
|
128
|
-
await this.updatePhoneTemplates(
|
|
144
|
+
if (hasId.length > 0) {
|
|
145
|
+
await this.updatePhoneTemplates(hasId);
|
|
129
146
|
}
|
|
130
147
|
}
|
|
131
148
|
async createPhoneTemplate(template) {
|
|
132
|
-
|
|
133
|
-
|
|
149
|
+
// The create endpoint only accepts type/disabled/content; strip read-only
|
|
150
|
+
// fields (channel, customizable, tenant) that the API would reject.
|
|
151
|
+
const createPayload = (0, utils_1.stripFields)(template, this.stripCreateFields);
|
|
152
|
+
// The API rejects an empty `content.from`, which is what fresh tenants
|
|
153
|
+
// export. Drop it when blank (cloning `content`, which stripFields only
|
|
154
|
+
// shallow-copied, so the caller's original asset isn't mutated).
|
|
155
|
+
if (createPayload.content && !createPayload.content.from) {
|
|
156
|
+
createPayload.content = { ...createPayload.content };
|
|
157
|
+
delete createPayload.content.from;
|
|
158
|
+
}
|
|
159
|
+
try {
|
|
160
|
+
const created = await this.client.branding.phone.templates.create(createPayload);
|
|
161
|
+
return { asset: created, action: 'create' };
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
// A 409 means the template already exists on the tenant (it was created
|
|
165
|
+
// between our list call and this create, or the list endpoint didn't
|
|
166
|
+
// surface its ID). Re-fetch to pick up the ID and fall back to an update.
|
|
167
|
+
if (err.statusCode === 409) {
|
|
168
|
+
logger_1.default.debug(`Phone template type '${template.type}' already exists, falling back to update`);
|
|
169
|
+
// Reassigns the shared `this.existing`; safe under concurrency since
|
|
170
|
+
// every re-fetch returns the same consistent list. If it still lacks an
|
|
171
|
+
// ID, updatePhoneTemplate warns and skips.
|
|
172
|
+
const response = await this.client.branding.phone.templates.list();
|
|
173
|
+
this.existing = response.templates ?? [];
|
|
174
|
+
const updated = await this.updatePhoneTemplate(template);
|
|
175
|
+
return { asset: updated, action: 'update' };
|
|
176
|
+
}
|
|
177
|
+
throw err;
|
|
178
|
+
}
|
|
134
179
|
}
|
|
135
180
|
async createPhoneTemplates(creates) {
|
|
136
181
|
await this.client.pool
|
|
137
182
|
.addEachTask({
|
|
138
183
|
data: creates || [],
|
|
139
184
|
generator: (item) => this.createPhoneTemplate(item)
|
|
140
|
-
.then((
|
|
141
|
-
|
|
142
|
-
|
|
185
|
+
.then(({ asset, action }) => {
|
|
186
|
+
// A 409 fallback actually performed an update; count it as such so
|
|
187
|
+
// the import summary doesn't report a phantom "create".
|
|
188
|
+
if (action === 'update') {
|
|
189
|
+
this.didUpdate(asset);
|
|
190
|
+
this.updated += 1;
|
|
191
|
+
}
|
|
192
|
+
else {
|
|
193
|
+
this.didCreate(asset);
|
|
194
|
+
this.created += 1;
|
|
195
|
+
}
|
|
143
196
|
})
|
|
144
197
|
.catch((err) => {
|
|
145
198
|
throw new Error(`Problem creating ${this.type} ${this.objString(item)}\n${err}`);
|
|
@@ -160,7 +213,6 @@ class PhoneTemplatesHandler extends default_1.default {
|
|
|
160
213
|
logger_1.default.debug(`Stripping ${this.type} create-only fields ${JSON.stringify(stripUpdateFields)}`);
|
|
161
214
|
const updatePayload = {
|
|
162
215
|
content: {
|
|
163
|
-
from: template.content?.from,
|
|
164
216
|
body: {
|
|
165
217
|
text: template.content?.body?.text,
|
|
166
218
|
voice: template.content?.body?.voice,
|
|
@@ -168,6 +220,11 @@ class PhoneTemplatesHandler extends default_1.default {
|
|
|
168
220
|
},
|
|
169
221
|
disabled: template.disabled,
|
|
170
222
|
};
|
|
223
|
+
// `content.from` is optional but the API rejects an empty string, which is
|
|
224
|
+
// what fresh tenants export. Only include it when it has a value.
|
|
225
|
+
if (template.content?.from) {
|
|
226
|
+
updatePayload.content.from = template.content.from;
|
|
227
|
+
}
|
|
171
228
|
const updated = await this.client.branding.phone.templates.update(existing.id, updatePayload);
|
|
172
229
|
return updated;
|
|
173
230
|
}
|
|
@@ -496,7 +496,7 @@ class PromptsHandler extends default_1.default {
|
|
|
496
496
|
updatePayload = {
|
|
497
497
|
...updatePrams,
|
|
498
498
|
rendering_mode: auth0_1.Management.AculRenderingModeEnum.Advanced,
|
|
499
|
-
default_head_tags_disabled: screenRenderer.default_head_tags_disabled
|
|
499
|
+
default_head_tags_disabled: screenRenderer.default_head_tags_disabled ?? undefined,
|
|
500
500
|
head_tags: screenRenderer.head_tags,
|
|
501
501
|
};
|
|
502
502
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { Management } from 'auth0';
|
|
2
|
+
import DefaultAPIHandler from './default';
|
|
3
|
+
import { Asset, Assets, CalculatedChanges } from '../../../types';
|
|
4
|
+
export type RateLimitPolicyConfiguration = Management.RateLimitPolicyConfiguration;
|
|
5
|
+
export type RateLimitPolicy = Management.RateLimitPolicy;
|
|
6
|
+
export declare const schema: {
|
|
7
|
+
type: string;
|
|
8
|
+
items: {
|
|
9
|
+
type: string;
|
|
10
|
+
properties: {
|
|
11
|
+
resource: {
|
|
12
|
+
type: string;
|
|
13
|
+
enum: "oauth_authentication_api"[];
|
|
14
|
+
};
|
|
15
|
+
consumer: {
|
|
16
|
+
type: string;
|
|
17
|
+
enum: "client"[];
|
|
18
|
+
};
|
|
19
|
+
consumer_selector: {
|
|
20
|
+
type: string;
|
|
21
|
+
};
|
|
22
|
+
configuration: {
|
|
23
|
+
type: string;
|
|
24
|
+
oneOf: ({
|
|
25
|
+
required: string[];
|
|
26
|
+
properties: {
|
|
27
|
+
action: {
|
|
28
|
+
type: string;
|
|
29
|
+
enum: string[];
|
|
30
|
+
};
|
|
31
|
+
limit?: undefined;
|
|
32
|
+
redirect_uri?: undefined;
|
|
33
|
+
};
|
|
34
|
+
additionalProperties: boolean;
|
|
35
|
+
} | {
|
|
36
|
+
required: string[];
|
|
37
|
+
properties: {
|
|
38
|
+
action: {
|
|
39
|
+
type: string;
|
|
40
|
+
enum: string[];
|
|
41
|
+
};
|
|
42
|
+
limit: {
|
|
43
|
+
type: string;
|
|
44
|
+
};
|
|
45
|
+
redirect_uri?: undefined;
|
|
46
|
+
};
|
|
47
|
+
additionalProperties: boolean;
|
|
48
|
+
} | {
|
|
49
|
+
required: string[];
|
|
50
|
+
properties: {
|
|
51
|
+
action: {
|
|
52
|
+
type: string;
|
|
53
|
+
enum: string[];
|
|
54
|
+
};
|
|
55
|
+
limit: {
|
|
56
|
+
type: string;
|
|
57
|
+
};
|
|
58
|
+
redirect_uri: {
|
|
59
|
+
type: string;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
additionalProperties: boolean;
|
|
63
|
+
})[];
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
required: string[];
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
export default class RateLimitPoliciesHandler extends DefaultAPIHandler {
|
|
70
|
+
existing: RateLimitPolicy[] | null;
|
|
71
|
+
constructor(config: DefaultAPIHandler);
|
|
72
|
+
objString(policy: RateLimitPolicy): string;
|
|
73
|
+
getType(): Promise<Asset | null>;
|
|
74
|
+
processChanges(assets: Assets): Promise<void>;
|
|
75
|
+
createRateLimitPolicy(policy: RateLimitPolicy): Promise<RateLimitPolicy>;
|
|
76
|
+
createRateLimitPolicies(creates: CalculatedChanges['create']): Promise<void>;
|
|
77
|
+
updateRateLimitPolicy(policy: RateLimitPolicy): Promise<void>;
|
|
78
|
+
updateRateLimitPolicies(updates: CalculatedChanges['update']): Promise<void>;
|
|
79
|
+
deleteRateLimitPolicy(policy: RateLimitPolicy): Promise<void>;
|
|
80
|
+
deleteRateLimitPolicies(data: Asset[]): Promise<void>;
|
|
81
|
+
}
|