Script to migrate assets from one space to another

I am trying to copy all of the assets from one space to another. Is there any example scripts or tools that can do this?

Hello @jhs129,

Transferring assets from one Builder.io space to another can be done programmatically by leveraging the Builder.io APIs. You would typically need to take the following steps:

  1. Retrieve content that contains assets from the source space: Utilize the Content API for this purpose.
  2. Download and re-upload these assets to the target space: Use the Upload API to handle asset uploads.

Here’s the script using Private API keys for both source and target spaces

const axios = require('axios');
const FormData = require('form-data');

// Replace with your actual API keys
const SOURCE_API_PRIVATE_KEY = 'YOUR_SOURCE_API_PRIVATE_KEY';
const TARGET_API_PRIVATE_KEY = 'YOUR_TARGET_API_PRIVATE_KEY';

// Fetch content that includes assets from the source space
async function fetchSourceContent() {
  const response = await axios.get('https://cdn.builder.io/api/v2/content/<model_name>', {
    headers: {
      Authorization: `Bearer ${SOURCE_API_PRIVATE_KEY}`,
    },
  });
  return response.data.results; // Assuming results contain an array of content entries
}

// Download asset data
async function downloadAsset(url) {
  const response = await axios.get(url, { responseType: 'arraybuffer' });
  return response.data;
}

// Upload asset to the target space
async function uploadAssetToTarget(assetName, assetData) {
  const formData = new FormData();
  formData.append('file', Buffer.from(assetData), assetName);

  const response = await axios.post('https://cdn.builder.io/api/v1/upload', formData, {
    headers: {
      Authorization: `Bearer ${TARGET_API_PRIVATE_KEY}`,
      ...formData.getHeaders(),
    },
  });

  return response.data;
}

// Main function to copy assets
async function copyAssets() {
  try {
    const content = await fetchSourceContent();
    for (const item of content) {
      const assetUrls = extractAssetUrls(item); // you need to implement this function

      for (const assetUrl of assetUrls) {
        const assetData = await downloadAsset(assetUrl);
        const assetName = assetUrl.split('/').pop(); // Extracting file name from URL
        await uploadAssetToTarget(assetName, assetData);
        console.log(`Uploaded asset ${assetName} to the target space.`);
      }
    }
  } catch (error) {
    console.error('Error copying asset:', error);
  }
}

async function extractAssetUrls(contentItem) {
  // Implement this function to extract asset URLs from the content item's fields
  // Example: return an array of asset URLs found in the content item
}

// Start the asset copying process
copyAssets();

Important Notes:

  • Private API Key Authorization: The Authorization header is used to include the Private API key for both fetching and uploading operations.
  • Form Data Handling: The script creates a FormData object to handle the binary data upload.

By using the Private API keys, you ensure that the operations are authenticated with the necessary permissions to perform asset management tasks.

Additional Links:

This script should serve as a comprehensive solution for copying assets from one Builder.io space to another. Make sure to replace the placeholder API keys with your actual Private API keys for your spaces.

Hi Manish-

Thanks for sending this info over, this helps but isn’t quite what I was looking for. More specifically, how can I export all of the images from one space and copy them to another. So I would want something that does this:

foreach $image in (getImagesFromSourceSpace()) {
importImageToTargetSpace($image)
}

What you sent over gives me how to upload the images, but not how to query all of the image from the source space. Can you provide instructions on how to do that?

Also to be clear, I am looking for Images from the Asset Library and not content of a specific model so I dont think the https://cdn.builder.io/api/v2/content/<model_name> api would work.

Hello @jhs129,

Regrettably, we do not have a specific API to assist you in fetching all the assets. Therefore, your only option is to manually download and upload assets from one space to another. Or use content API to filter assets from each page and use upload API to upload to another space.

If you believe this could be a useful feature, you can submit a feature request at Builder.io Ideas.

Thank you.

Hi Manish-
Are you saying there is no API that can return a result set of all of the images in the asset library? I would think there has to be one as how else does the asset library browse page work in the admin ui (Builder.io: Visual Development Platform)? If one did exist then I could simply get the result set, iterate thru it and then upload each image to the other space.

If this doesn’t exist could you provide a code example of how I could use the content API to filter assets from each page to get the list of images in the asset library?
Thanks,
John

Hello @jhs129,

Regrettably, there is no public API to query all the assets at the moment, we use query API internally which makes a call to fetch all the assets from the database but this API is not exposed to the public yet.

Therefore, you will need to consider using content API to filter out all the images and use upload API to upload them.

  1. Fetch all the page content from the Builder.io API.
  2. Parse the content to extract the images.
  3. Display the list of images.
import type { NextApiRequest, NextApiResponse } from 'next';
import { builder, BuilderContent } from '@builder.io/react';

type Image = {
  src: string;
  alt: string;
};

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse<Image[]>
) {
  try {
    // Fetch all page content from Builder
    const pages: BuilderContent[] = await builder.getAll('page', {
      prerender: false,
    });

    const images: Image[] = [];

    // Function to recursively extract images from content
    const extractImages = (content: any) => {
      if (!content) return;

      if (content.component?.name === 'Image' && content.options?.image) {
        images.push({
          src: content.options.image,
          alt: content.options.alt || '',
        });
      }

      if (Array.isArray(content)) {
        content.forEach(extractImages);
      } else if (typeof content === 'object') {
        Object.values(content).forEach(extractImages);
      }
    };

    // Loop through all pages and extract images
    pages.forEach((page) => {
      extractImages(page.data.blocks);
    });

    res.status(200).json(images);
  } catch (error) {
    res.status(500).json({ error: 'Failed to fetch images' });
  }
}

Then use upload API to upload those images