UNPKG

@ckeditor/ckeditor5-cloud-services

Version:

CKEditor 5's Cloud Services integration layer.

144 lines (143 loc) 5.71 kB
/** * @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved. * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options */ /** * @module cloud-services/cloudservices */ import { ContextPlugin } from 'ckeditor5/src/core.js'; import { CKEditorError } from 'ckeditor5/src/utils.js'; import CloudServicesCore from './cloudservicescore.js'; /** * Plugin introducing the integration between CKEditor 5 and CKEditor Cloud Services . * * It initializes the token provider based on * the {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig `config.cloudService`}. */ export default class CloudServices extends ContextPlugin { /** * The authentication token URL for CKEditor Cloud Services or a callback to the token value promise. See the * {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl} for more details. */ tokenUrl; /** * The URL to which the files should be uploaded. */ uploadUrl; /** * The URL for web socket communication, used by the `RealTimeCollaborativeEditing` plugin. Every customer (organization in the CKEditor * Ecosystem dashboard) has their own, unique URLs to communicate with CKEditor Cloud Services. The URL can be found in the * CKEditor Ecosystem customer dashboard. * * Note: Unlike most plugins, `RealTimeCollaborativeEditing` is not included in any CKEditor 5 build and needs to be installed manually. * Check [Collaboration overview](https://ckeditor.com/docs/ckeditor5/latest/features/collaboration/overview.html) for more details. */ webSocketUrl; /** * An optional parameter used for integration with CKEditor Cloud Services when uploading the editor build to cloud services. * * Whenever the editor build or the configuration changes, this parameter should be set to a new, unique value to differentiate * the new bundle (build + configuration) from the old ones. */ bundleVersion; /** * Other plugins use this token for the authorization process. It handles token requesting and refreshing. * Its value is `null` when {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl} is not provided. * * @readonly */ token = null; /** * A map of token object instances keyed by the token URLs. */ _tokens = new Map(); /** * @inheritDoc */ static get pluginName() { return 'CloudServices'; } /** * @inheritDoc */ static get isOfficialPlugin() { return true; } /** * @inheritDoc */ static get requires() { return [CloudServicesCore]; } /** * @inheritDoc */ async init() { const config = this.context.config; const options = config.get('cloudServices') || {}; for (const [key, value] of Object.entries(options)) { this[key] = value; } if (!this.tokenUrl) { this.token = null; return; } // Initialization of the token may fail. By default, the token is being refreshed on the failure. // The problem is that if this happens here, then the token refresh interval will be executed even // after destroying the editor (as the exception was thrown from `init` method). To prevent that // behavior we need to catch the exception and destroy the uninitialized token instance. // See: https://github.com/ckeditor/ckeditor5/issues/17531 const cloudServicesCore = this.context.plugins.get('CloudServicesCore'); const uninitializedToken = cloudServicesCore.createToken(this.tokenUrl); try { this.token = await uninitializedToken.init(); this._tokens.set(this.tokenUrl, this.token); } catch (error) { uninitializedToken.destroy(); throw error; } } /** * Registers an additional authentication token URL for CKEditor Cloud Services or a callback to the token value promise. See the * {@link module:cloud-services/cloudservicesconfig~CloudServicesConfig#tokenUrl} for more details. * * @param tokenUrl The authentication token URL for CKEditor Cloud Services or a callback to the token value promise. */ async registerTokenUrl(tokenUrl) { // Reuse the token instance in case of multiple features using the same token URL. if (this._tokens.has(tokenUrl)) { return this.getTokenFor(tokenUrl); } const cloudServicesCore = this.context.plugins.get('CloudServicesCore'); const token = await cloudServicesCore.createToken(tokenUrl).init(); this._tokens.set(tokenUrl, token); return token; } /** * Returns an authentication token provider previously registered by {@link #registerTokenUrl}. * * @param tokenUrl The authentication token URL for CKEditor Cloud Services or a callback to the token value promise. */ getTokenFor(tokenUrl) { const token = this._tokens.get(tokenUrl); if (!token) { /** * The provided `tokenUrl` was not registered by {@link module:cloud-services/cloudservices~CloudServices#registerTokenUrl}. * * @error cloudservices-token-not-registered */ throw new CKEditorError('cloudservices-token-not-registered', this); } return token; } /** * @inheritDoc */ destroy() { super.destroy(); for (const token of this._tokens.values()) { token.destroy(); } } }