auth0-tenant-to-tenant-user-migration-tool
Version:
Auth0 tenant to tenant user migration tool
90 lines • 4.11 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));
const form_data_1 = __importDefault(require("form-data"));
const stream_1 = require("stream");
const logger_1 = __importDefault(require("./logger"));
async function waitForJobCompletion(jobId, token, tenantDomain, intervalMs = 5000, timeoutMs = 300000) {
const start = Date.now();
while (Date.now() - start < timeoutMs) {
const response = await axios_1.default.get(`https://${tenantDomain}/api/v2/jobs/${jobId}`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
const status = response.data.status;
if (status === 'completed' || status === 'failed') {
return response.data;
}
await new Promise((resolve) => setTimeout(resolve, intervalMs));
}
throw new Error('Timed out waiting for import job to complete.');
}
async function getImportJobErrors(jobId, token, tenantDomain) {
try {
const response = await axios_1.default.get(`https://${tenantDomain}/api/v2/jobs/${jobId}/errors`, {
headers: {
Authorization: `Bearer ${token}`,
},
});
return response.data;
}
catch (error) {
logger_1.default.error('❌ Failed to fetch import job errors.');
logger_1.default.error(error.response?.data || error.message);
return [];
}
}
async function importUsers({ users, token, connectionId, tenantDomain, isUpsert, }) {
const jsonBuffer = Buffer.from(JSON.stringify(users, null, 2));
const stream = stream_1.Readable.from(jsonBuffer);
const form = new form_data_1.default();
form.append('users', stream, {
filename: 'users.json',
contentType: 'application/json',
});
form.append('connection_id', connectionId);
form.append('upsert', isUpsert.toString());
const response = await axios_1.default.post(`https://${tenantDomain}/api/v2/jobs/users-imports`, form, {
headers: {
...form.getHeaders(),
Authorization: `Bearer ${token}`,
},
});
const jobId = response.data.id;
logger_1.default.info(`📤 Import job started. Waiting for completion (Job ID: ${jobId})...`);
const finalStatus = await waitForJobCompletion(jobId, token, tenantDomain);
logger_1.default.info('📋 Import Job Summary');
logger_1.default.info('----------------------');
logger_1.default.info(`Job ID: ${finalStatus.id}`);
logger_1.default.info(`Status: ${finalStatus.status}`);
logger_1.default.info(`Type: ${finalStatus.type}`);
logger_1.default.info(`Created At: ${finalStatus.created_at}`);
logger_1.default.info(`Connection ID: ${finalStatus.connection_id}`);
logger_1.default.info(`Users Processed: ${finalStatus.summary.total}`);
logger_1.default.info(`Users Inserted: ${finalStatus.summary.inserted}`);
logger_1.default.info(`Users Updated: ${finalStatus.summary.updated}`);
logger_1.default.info(`Users Failed: ${finalStatus.summary.failed}`);
if (finalStatus.summary.failed > 0) {
const errors = await getImportJobErrors(jobId, token, tenantDomain);
if (errors.length > 0) {
logger_1.default.warn('Import Errors:');
errors.forEach((err, index) => {
const userId = err.user?.user_id || 'N/A';
const name = err.user?.name || 'N/A';
const errorMessages = (err.errors || [])
.map((e) => `${e.message} (code: ${e.code})`)
.join('; ');
logger_1.default.warn(`User ${index + 1}:\n - user_id: ${userId}\n - name: ${name}\n - error: ${errorMessages}`);
});
}
else {
logger_1.default.warn('No detailed error information returned.');
}
}
}
exports.default = importUsers;
//# sourceMappingURL=import-users.js.map