Editor bundle

# Overview

An editor bundle is the source code of a pre-configured and ready-to-use CKEditor 5, which is minified and built as a single file. To use the document storage, import and export or connection optimization features you need to upload an exact copy of the editor file from your application to the CKEditor Cloud Services server.

CKEditor Cloud Services uses your editor bundle to convert operations in the collaboration session into data. Thanks to this, CKEditor Cloud Services can ensure data consistency between users and the stored data. Furthermore, if your editor bundle is using some custom plugins that can output some custom data, it will be then properly handled by CKEditor Cloud Services.

Whenever you change something in your editor bundle or its configuration, you should update it on the CKEditor Cloud Services server, too. If the users use different versions of the editor than the one uploaded to the server, it may lead to data loss or even editor crashes.

# Building the editor bundle

First, you need to create an editor bundle. You can follow our step-by-step editor bundling guide or go with ready-to-use editor bundle examples.

# Uploading the editor bundle

If you have already built your editor that meets the requirements, you can upload it to CKEditor Cloud Services together with the editor configuration. The editor upload process requires the use of the POST /editors method from the Cloud Services REST API.

Every request made to the CKEditor Cloud Services REST API needs to have additional headers: X-CS-Timestamp and X-CS-Signature. Refer to the request signature guide for more details.

Three parameters are passed to the body of this method:

  • bundle – The code of your minified editor passed as a string.
  • config – This is the editor configuration that will be used by the editor in CKEditor Cloud Services. This should be the same config as used by the editor in your application, especially when it can alter the data output.
  • test_data – This is the real document content generated by the editor you upload to the CKEditor Cloud Services server. It helps to detect if any of your custom plugins modify the document content incorrectly or if an invalid configuration has been passed. This parameter is optional but it is highly recommended to use it. You should make sure that your test data has been created using all the custom plugins you have implemented.

The body of the upload request should look like this:

{
    "bundle": "the content of editor bundle file",
    "config": {
        "cloudServices": {
            "bundleVersion": "unique_editor_bundle_version"
        },
        "removePlugins": [ "myCustomAutoSavePlugin" ],
        ... other config options
    },
    "test_data": "<p>example output from your editor</p>"
}

The bundleVersion property inside the config.cloudServices object is required.

Remember that the uploaded editor bundle is only available within the environment to which it was assigned. If you use the same editor for different environments, you must upload it separately for each of them.

# Editor configuration

The bundleVersion property set during an upload acts as a unique build identifier. It tells CKEditor Cloud Services which editor should be used when a user starts the collaboration session. You need to make sure that the editor configuration in your application also has the bundleVersion property and its value matches the editor uploaded to the CKEditor Cloud Services server. An example editor configuration with set bundleVersion looks like this:

return CKEditorCS
    .create( document.querySelector( '.collaboration-demo__editable' ), {
        cloudServices: {
            tokenUrl: 'TOKEN_URL',
            uploadUrl: 'UPLOAD_URL',
            webSocketUrl: 'WEBSOCKET_URL',
            bundleVersion: 'editor-1.0.0'
        },
        collaboration: {
            channelId: 'CHANNEL_ID'
        },
        toolbar: [
            // Toolbar items
        ],
        // Other config options
    } );

The editor configuration uploaded to the CKEditor Cloud Services server should be in JSON format. Therefore, in some cases, the config object needs to be modified before sending:

  • properties of particular plugins that require DOM elements should be set to null,
  • regex values in General HTML Support configuration should be converted to strings, e.g. "/.*/".

# Multi-root editor builds

For multi-root editor builds, an upload request body requires an additional is_multi_root_editor field set to true. The field indicates that the uploaded editor is a multi-root build. Additionally, the test_data property is expected to be a stringified JSON structure where the keys are the root names and the values are the HTML content for particular roots. Moreover, if you want to use the roots’ attributes you must provide example values for each root in the editor config.

{
    "bundle": "the content of a multi-root editor bundle file",
    "config": {
        "cloudServices": {
            "bundleVersion": "unique_multiroot_editor_bundle_version"
        },
        "removePlugins": [
            "myCustomAutoSavePlugin"
        ],
        "rootsAttributes": {
            "main": {
            "order": 1
            }
        },
        ... other config options
    },
    "test_data": "{\"header\":\"<p>Multi-root document header.</p>\",\"footer\":\"<p>Multi-root document footer.</p>\"}",
    "is_multi_root_editor": true
}

# Example

Follow this example to learn how to properly upload the editor bundle to CKEditor Cloud Services. This example is using Node.js and npm, hence it is required to have these tools installed. It also assumes that you have already built the editor bundle. This example will continue using the files from the previous example.

  1. In your terminal, use cd to get into the extracted folder and install the axios package with the npm i axios command.

  2. Create a new upload.js file inside the extracted folder with the following content:

const crypto = require( 'crypto' );
const fs = require( 'fs' );
const path = require( 'path' );
const axios = require( 'axios' );

// Update with your credentials and application endpoint
const environmentId = 'txQ9sTfqmXUyWU5LmDbr';
const apiSecret = '4zZBCQoPfRZ7Rr7TEnGAuRsGgbfF58Eg0PA8xcLD2kvPhjGjy4VGgB8k0hXn';
const applicationEndpoint = 'https://33333.cke-cs.com';

const apiEndpoint = `${ applicationEndpoint }/api/v5/${ environmentId }/editors/`;
const editorBundle = fs.readFileSync( path.resolve( './build/ckeditor.js' ) );

const body = {
    bundle: editorBundle.toString(),
    config: {
        cloudServices: {
            bundleVersion: 'editor-1.0.0' // Set a unique name for the uploaded bundle
        },
        toolbar: [
            // Toolbar items
        ],
        // Other config options
    }
};

const CSTimestamp = Date.now();
const axiosConfig = {
    headers: {
        'X-CS-Timestamp': CSTimestamp,
        'X-CS-Signature': generateSignature( apiSecret, 'POST', apiEndpoint, CSTimestamp, body )
    }
};

axios.post( apiEndpoint, body, axiosConfig )
    .then( response => {
        console.log ( response.status );
    } ).catch( error => {
        console.log( error.message );
        console.log( error.response.data );
    } );

function generateSignature( apiSecret, method, uri, timestamp, body ) {
    const url = new URL( uri );
    const path = url.pathname + url.search;
    const hmac = crypto.createHmac( 'SHA256', apiSecret );

    hmac.update( `${ method.toUpperCase() }${ path }${ timestamp }` );

    if ( body ) {
        hmac.update( Buffer.from( JSON.stringify( body ) ) );
    }

    return hmac.digest( 'hex' );
}

Run the above code with the node upload.js command.

You should see the 201 status code in your console. You can run node upload.js once again to make sure that the bundle is already uploaded. In this case, you will get a 409 error with message Editor editor-1.0.0 already exists.

# Updating the editor bundle

As shown in the example above, it is not possible to overwrite an editor bundle on the CKEditor Cloud Services server. You may, however, encounter situations where you need to rebuild your editor, for example when you add a new plugin, update CKEditor 5 version or fix a bug in your custom plugin. You should follow these steps to start using a new editor bundle:

  1. Rebuild your editor with the necessary changes to the configuration or plugins.
  2. Upload the new editor bundle with the bundleVersion value being new and unique for your environment.
  3. Update the bundleVersion in the editor configuration in your application to match the new value from step 2.
  4. Wait for the active collaboration sessions to be removed automatically or remove them manually using the DELETE /collaborations/{document_id} from the CKEditor Cloud Services REST API.
  5. Open the document in your new editor.

A collaboration session initiated with certain bundleVersion can be opened only by editors with the same bundleVersion value. Because of this you can not connect to the previously edited documents with the new editor, without reinitializing such collaboration session (steps 4 and 5).

To ensure data consistency you should update the editor bundle on CKEditor Cloud Services every time there is a change in your editor. This is especially important when the changes are related to the conversions or the data outputs.