Skip to content

Instantly share code, notes, and snippets.

@mrtnzlml
Created September 24, 2025 17:34
Show Gist options
  • Select an option

  • Save mrtnzlml/c59ea5c370a551a7e417638a3e67ff1f to your computer and use it in GitHub Desktop.

Select an option

Save mrtnzlml/c59ea5c370a551a7e417638a3e67ff1f to your computer and use it in GitHub Desktop.
Deduplicates shared queue schemas for Rossum.ai
// --- Configuration ---
// Replace with your Rossum API credentials and base URL.
const ROSSUM_API_TOKEN = 'YOUR_API_TOKEN'; // Replace with your actual API token
const BASE_URL = 'https://api.elis.rossum.ai/v1'; // Adjust if you have a dedicated instance URL
// --- Script Mode ---
// Set to true to simulate changes without writing to the API.
// Set to false to perform live changes.
const DRY_RUN = true;
/**
* A wrapper for the native fetch API to interact with the Rossum API.
* @param {string} path - The API endpoint path (e.g., '/schemas').
* @param {object} options - Standard fetch options (method, body, etc.).
* @returns {Promise<any>} A promise that resolves to the JSON response.
*/
async function rossumFetch(path, options = {}) {
const url = path.startsWith('http') ? path : `${BASE_URL}${path}`;
const headers = {
'Authorization': `Bearer ${ROSSUM_API_TOKEN}`,
'Content-Type': 'application/json',
...options.headers,
};
const response = await fetch(url, { ...options, headers });
if (!response.ok) {
const errorData = await response.json().catch(() => ({ message: response.statusText }));
const error = new Error(`API request failed with status ${response.status}`);
error.response = { data: errorData };
throw error;
}
// Handle responses that might not have a JSON body (e.g., 204 No Content for PATCH)
if (response.status === 204) {
return null;
}
return response.json();
}
/**
* Fetches all schemas from the Rossum API, handling pagination.
* @returns {Promise<Array<Object>>} A promise that resolves to an array of all schema objects.
*/
async function getAllSchemas() {
let schemas = [];
let nextUrl = '/schemas';
console.log('Fetching all schemas...');
while (nextUrl) {
try {
const response = await rossumFetch(nextUrl);
schemas = schemas.concat(response.results);
nextUrl = response.pagination.next;
} catch (error) {
console.error(`Error fetching schemas from ${nextUrl}:`, error.response ? error.response.data : error.message);
return [];
}
}
console.log(`Successfully fetched ${schemas.length} schemas.`);
return schemas;
}
/**
* Creates a copy of a given schema. In dry run mode, it simulates this action.
* @param {Object} originalSchema - The schema object to copy.
* @param {string} queueId - The ID of the queue for which the new schema is being created.
* @returns {Promise<Object>} A promise that resolves to the newly created (or simulated) schema object.
*/
async function copySchema(originalSchema, queueId) {
const newSchemaName = `${originalSchema.name} (Copy for Queue ${queueId})`;
if (DRY_RUN) {
console.log(`[DRY RUN] Would create schema copy: "${newSchemaName}"`);
// Return a mock object for the rest of the script to simulate the full flow
return {
id: `new-schema-for-${queueId}`,
url: `${BASE_URL}/schemas/new-schema-for-${queueId}`
};
}
const originalSchemaContent = (await rossumFetch(originalSchema.url)).content
const newSchemaPayload = {
name: newSchemaName,
content: originalSchemaContent
};
try {
console.log(`Creating a copy of schema "${originalSchema.name}" for queue ${queueId}...`);
const response = await rossumFetch('/schemas', {
method: 'POST',
body: JSON.stringify(newSchemaPayload),
});
console.log(`Successfully created new schema with ID: ${response.id}`);
return response;
} catch (error) {
console.error(`Failed to create schema copy for queue ${queueId}:`, error.response ? error.response.data : error.message);
throw error;
}
}
/**
* Updates a queue to use a new schema. In dry run mode, it simulates this action.
* @param {string} queueUrl - The URL of the queue to update.
* @param {string} newSchemaUrl - The URL of the new schema to assign to the queue.
*/
async function updateQueueSchema(queueUrl, newSchemaUrl) {
const queueId = queueUrl.split('/').pop();
if (DRY_RUN) {
console.log(`[DRY RUN] Would update queue ${queueId} to use new schema: ${newSchemaUrl}`);
return;
}
try {
console.log(`Updating queue ${queueId} to use new schema ${newSchemaUrl}...`);
await rossumFetch(queueUrl, {
method: 'PATCH',
body: JSON.stringify({ schema: newSchemaUrl }),
});
console.log(`Successfully updated queue ${queueId}.`);
} catch (error) {
console.error(`Failed to update queue ${queueUrl}:`, error.response ? error.response.data : error.message);
throw error;
}
}
/**
* Main function to find shared schemas and assign unique copies to each queue.
*/
async function main() {
console.log('--- Rossum Schema Deduplication Script ---');
if (DRY_RUN) {
console.log('\n*** RUNNING IN DRY RUN MODE. NO CHANGES WILL BE MADE. ***\n');
} else {
console.log('\n*** RUNNING IN LIVE MODE. CHANGES WILL BE APPLIED. ***\n');
}
const allSchemas = await getAllSchemas();
const sharedSchemas = allSchemas.filter(schema => schema.queues && schema.queues.length > 1);
if (sharedSchemas.length === 0) {
console.log('No shared schemas found. Exiting.');
return;
}
console.log(`Found ${sharedSchemas.length} shared schemas to process.`);
for (const schema of sharedSchemas) {
console.log(`\nProcessing shared schema: "${schema.name}" (ID: ${schema.id}), used by ${schema.queues.length} queues.`);
for (const queueUrl of schema.queues) {
try {
const queueId = queueUrl.split('/').pop();
const newSchema = await copySchema(schema, queueId);
await updateQueueSchema(queueUrl, newSchema.url);
} catch (err) {
console.error(`Could not process queue ${queueUrl} for schema ${schema.id}. Skipping.`);
}
}
}
console.log('\n--- Schema deduplication process finished. ---');
}
// Run the main function
main();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment