@dotcms/types
Version:
The `@dotcms/types` package contains TypeScript type definitions for the dotCMS ecosystem. Use it to enable type safety and an enhanced developer experience when working with dotCMS APIs and structured content.
499 lines (491 loc) • 15 kB
JavaScript
const DotCMSEntityState = {
IDLE: 'IDLE',
LOADING: 'LOADING',
SUCCESS: 'SUCCESS',
ERROR: 'ERROR'
};
/**
* Development mode
*
* @internal
*/
const DEVELOPMENT_MODE = 'development';
/**
* Production mode
*
* @internal
*/
const PRODUCTION_MODE = 'production';
/**
* Possible modes of UVE (Universal Visual Editor)
* @enum {string}
*
* @property {string} LIVE - Shows published and future content
* @property {string} PREVIEW - Shows published and working content
* @property {string} EDIT - Enables content editing functionality in UVE
* @property {string} UNKNOWN - Error state, UVE should not remain in this mode
*/
var UVE_MODE;
(function (UVE_MODE) {
UVE_MODE["EDIT"] = "EDIT_MODE";
UVE_MODE["PREVIEW"] = "PREVIEW_MODE";
UVE_MODE["LIVE"] = "LIVE";
UVE_MODE["UNKNOWN"] = "UNKNOWN";
})(UVE_MODE || (UVE_MODE = {}));
/**
* Actions send to the dotcms editor
*
* @export
* @enum {number}
*/
var DotCMSUVEAction;
(function (DotCMSUVEAction) {
/**
* Tell the dotcms editor that page change
*/
DotCMSUVEAction["NAVIGATION_UPDATE"] = "set-url";
/**
* Send the element position of the rows, columnsm containers and contentlets
*/
DotCMSUVEAction["SET_BOUNDS"] = "set-bounds";
/**
* Send the information of a *hovered* contentlet (fires on pointermove).
* The editor uses this to render the transient hover overlay around the
* contentlet under the cursor. Pairs with {@link SET_SELECTED_CONTENTLET}
* for clicks. The name is kept as `SET_CONTENTLET` for backwards
* compatibility with external SDK consumers — semantically it is
* "set hovered contentlet".
*/
DotCMSUVEAction["SET_CONTENTLET"] = "set-contentlet";
/**
* Send the information of a contentlet that was *clicked* inside the iframe.
* The editor uses this to promote the clicked contentlet to "selected"
* (persistent action toolbar + opens the quick-edit panel). Pairs with
* {@link SET_CONTENTLET} which handles hover.
*/
DotCMSUVEAction["SET_SELECTED_CONTENTLET"] = "set-selected-contentlet";
/**
* Tell the editor that the page is being scrolled
*/
DotCMSUVEAction["IFRAME_SCROLL"] = "scroll";
/**
* Tell the editor that the page has stopped scrolling
*/
DotCMSUVEAction["IFRAME_SCROLL_END"] = "scroll-end";
/**
* Ping the editor to see if the page is inside the editor
*/
DotCMSUVEAction["PING_EDITOR"] = "ping-editor";
/**
* Tell the editor to init the inline editing editor.
*/
DotCMSUVEAction["INIT_INLINE_EDITING"] = "init-inline-editing";
/**
* Tell the editor to open the Copy-contentlet dialog
* To copy a content and then edit it inline.
*/
DotCMSUVEAction["COPY_CONTENTLET_INLINE_EDITING"] = "copy-contentlet-inline-editing";
/**
* Tell the editor to save inline edited contentlet
*/
DotCMSUVEAction["UPDATE_CONTENTLET_INLINE_EDITING"] = "update-contentlet-inline-editing";
/**
* Tell the editor to trigger a menu reorder
*/
DotCMSUVEAction["REORDER_MENU"] = "reorder-menu";
/**
* Tell the editor to send the page info to iframe
*/
DotCMSUVEAction["GET_PAGE_DATA"] = "get-page-data";
/**
* Tell the editor an user send a graphql query
*/
DotCMSUVEAction["CLIENT_READY"] = "client-ready";
/**
* Tell the editor to edit a contentlet
*/
DotCMSUVEAction["EDIT_CONTENTLET"] = "edit-contentlet";
/**
* Tell the editor to register style schemas
*/
DotCMSUVEAction["REGISTER_STYLE_SCHEMAS"] = "register-style-schemas";
/**
* Tell the editor to report the iframe height
*/
DotCMSUVEAction["IFRAME_HEIGHT"] = "iframe-height";
/**
* Tell the editor to create a contentlet without adding it to the page
*/
DotCMSUVEAction["CREATE_CONTENTLET"] = "create-contentlet";
/**
* Tell the editor to do nothing
*/
DotCMSUVEAction["NOOP"] = "noop";
/**
* Report the offsetTop of a page section so the editor can scroll to it
*/
DotCMSUVEAction["SECTION_OFFSET"] = "section-offset";
})(DotCMSUVEAction || (DotCMSUVEAction = {}));
/**
* Available events in the Universal Visual Editor
* @enum {string}
*/
var UVEEventType;
(function (UVEEventType) {
/**
* Triggered when page data changes from the editor
*/
UVEEventType["CONTENT_CHANGES"] = "changes";
/**
* Triggered when the page needs to be reloaded
*/
UVEEventType["PAGE_RELOAD"] = "page-reload";
/**
* Triggered when scroll action is needed inside the iframe
*/
UVEEventType["IFRAME_SCROLL"] = "iframe-scroll";
/**
* Triggered when a contentlet is hovered
*/
UVEEventType["CONTENTLET_HOVERED"] = "contentlet-hovered";
/**
* Triggered when a contentlet is clicked (capture-phase `click` event on
* its element). Used by the editor to promote the clicked contentlet to
* "selected" without the editor having to capture pointer events on its
* hover overlay.
*/
UVEEventType["CONTENTLET_CLICKED"] = "contentlet-clicked";
/**
* Triggered when the editor requests a scroll to a specific page section
* @internal
*/
UVEEventType["SCROLL_TO_SECTION"] = "scroll-to-section";
/**
* Triggered when the editor clears its selection (resize, scroll, navigation).
* The SDK uses this to reset its "last selected" tracker so a subsequent click
* on the same contentlet re-emits CONTENTLET_CLICKED instead of being treated
* as a passthrough.
* @internal
*/
UVEEventType["SELECTION_CLEARED"] = "selection-cleared";
/**
* The single bounds-sync channel. The SDK observes the iframe document
* and every `[data-dot-object="container"]` with a debounced
* ResizeObserver and emits the full page bounds whenever the layout
* settles (sidebar open/close, device/zoom change, media-query
* reflows, image/font load shifts, scroll, etc.). The editor can
* also send a UVE_FLUSH_BOUNDS message to bypass the debounce when it
* needs an immediate snapshot (drag/drop dropzone).
* @internal
*/
UVEEventType["AUTO_BOUNDS"] = "auto-bounds";
})(UVEEventType || (UVEEventType = {}));
/* eslint-disable @typescript-eslint/no-explicit-any */
/**
* Page API specific error class
* Wraps HTTP errors and adds page-specific context including GraphQL information
*/
class DotErrorPage extends Error {
constructor(message, status = 500, code = 'UNKNOWN', httpError, graphql) {
super(message);
this.name = 'DotCMSPageError';
this.status = status;
this.code = code;
this.httpError = httpError;
this.graphql = graphql;
// Ensure proper prototype chain for instanceof checks
Object.setPrototypeOf(this, DotErrorPage.prototype);
}
/**
* Serializes the error to a plain object for logging or transmission
*/
toJSON() {
return {
name: this.name,
message: this.message,
status: this.status,
code: this.code,
httpError: this.httpError?.toJSON(),
graphql: this.graphql,
stack: this.stack
};
}
}
/**
* Standardized HTTP error class for all HTTP client implementations
*/
class DotHttpError extends Error {
constructor(details) {
super(details.message);
this.name = 'DotHttpError';
this.status = details.status;
this.statusText = details.statusText;
this.data = details.data;
// Ensure proper prototype chain for instanceof checks
Object.setPrototypeOf(this, DotHttpError.prototype);
}
/**
* Serializes the error to a plain object for logging or transmission
*/
toJSON() {
return {
name: this.name,
message: this.message,
status: this.status,
statusText: this.statusText,
data: this.data,
stack: this.stack
};
}
}
/**
* Abstract base class for HTTP client implementations.
* Provides common error handling utilities and enforces HttpError contract.
*
* @example
* ```typescript
* // Fetch API example
* export class FetchHttpClient extends BaseHttpClient {
* async request<T>(url: string, options?: DotRequestOptions): Promise<T> {
* try {
* const response = await fetch(url, options);
*
* if (!response.ok) {
* // Parse response body and headers
* let errorBody: string | unknown;
* try {
* const contentType = response.headers.get('content-type');
* if (contentType?.includes('application/json')) {
* errorBody = await response.json();
* } else {
* errorBody = await response.text();
* }
* } catch {
* errorBody = response.statusText;
* }
*
* const headers: Record<string, string> = {};
* response.headers.forEach((value, key) => {
* headers[key] = value;
* });
*
* throw this.createHttpError(
* response.status,
* response.statusText,
* headers,
* errorBody
* );
* }
*
* return response.json();
* } catch (error) {
* if (error instanceof TypeError) {
* throw this.createNetworkError(error);
* }
* throw error;
* }
* }
* }
*
* // Axios example
* export class AxiosHttpClient extends BaseHttpClient {
* async request<T>(url: string, options?: DotRequestOptions): Promise<T> {
* try {
* const response = await axios(url, options);
* return response.data;
* } catch (error) {
* if (axios.isAxiosError(error)) {
* throw this.createHttpError(
* error.response?.status || 0,
* error.response?.statusText || 'Network Error',
* error.response?.headers,
* error.response?.data
* );
* }
* throw this.createNetworkError(error);
* }
* }
* }
* ```
*/
class BaseHttpClient {
// This is my proposal to add this method to the class. We will need to stream data on AI Gen/Chat
// abstract requestStream(
// url: string,
// options?: DotRequestOptions
// ): Promise<{ body: ReadableStream<BufferSource>; contentLength: number }>;
/**
* Creates a standardized HttpError from HTTP response details.
* Handles parsing of error response body automatically.
*
* @param status - HTTP status code
* @param statusText - HTTP status text
* @param headers - Response headers (optional)
* @param body - Response body (optional)
* @param customMessage - Optional custom error message
* @returns HttpError instance with parsed response data
*/
createHttpError(status, statusText, headers, body, customMessage) {
let errorData = body;
// If body is a string, try to parse as JSON
if (typeof body === 'string') {
try {
const contentType = headers?.['content-type'] || headers?.['Content-Type'];
if (contentType?.includes('application/json')) {
errorData = JSON.parse(body);
} else {
errorData = body;
}
} catch {
errorData = body;
}
}
return new DotHttpError({
status,
statusText,
message: customMessage || `HTTP ${status}: ${statusText}`,
data: errorData
});
}
/**
* Creates a standardized HttpError for network/connection errors.
*
* @param originalError - The original network error
* @returns HttpError instance representing a network error
*/
createNetworkError(originalError) {
return new DotHttpError({
status: 0,
// Network error status
statusText: 'Network Error',
message: `Network error: ${originalError.message}`,
data: originalError
});
}
}
/**
* Content API specific error class
* Wraps HTTP errors and adds content-specific context including query information
*/
class DotErrorContent extends Error {
constructor(message, contentType, operation, httpError, query) {
super(message);
this.name = 'DotCMSContentError';
this.contentType = contentType;
this.operation = operation;
this.httpError = httpError;
this.query = query;
// Ensure proper prototype chain for instanceof checks
Object.setPrototypeOf(this, DotErrorContent.prototype);
}
/**
* Serializes the error to a plain object for logging or transmission
*/
toJSON() {
return {
name: this.name,
message: this.message,
contentType: this.contentType,
operation: this.operation,
httpError: this.httpError?.toJSON(),
query: this.query,
stack: this.stack
};
}
}
/**
* Navigation API specific error class
* Wraps HTTP errors and adds navigation-specific context
*/
class DotErrorNavigation extends Error {
constructor(message, path, httpError) {
super(message);
this.name = 'DotNavigationError';
this.path = path;
this.httpError = httpError;
// Ensure proper prototype chain for instanceof checks
Object.setPrototypeOf(this, DotErrorNavigation.prototype);
}
/**
* Serializes the error to a plain object for logging or transmission
*/
toJSON() {
return {
name: this.name,
message: this.message,
path: this.path,
httpError: this.httpError?.toJSON(),
stack: this.stack
};
}
}
/**
* The distance functions for the search results.
* @public
* @constant DISTANCE_FUNCTIONS
*/
const DISTANCE_FUNCTIONS = {
/**
* The L2 distance function.
* @constant L2 - The L2 distance function.
*/
L2: '<->',
/**
* The inner product distance function.
* @constant innerProduct - The inner product distance function.
*/
innerProduct: '<#>',
cosine: '<=>',
/**
* The L1 distance function.
* @constant L1 - The L1 distance function.
*/
L1: '<+>',
/**
* The hamming distance function.
* @constant hamming - The hamming distance function.
*/
hamming: '<~>',
/**
* The jaccard distance function.
* @constant jaccard - The jaccard distance function.
*/
jaccard: '<%>'
};
/**
* AI Search API specific error class
* Wraps HTTP errors and adds AI search-specific context including query information
*/
class DotErrorAISearch extends Error {
constructor({
message,
httpError,
prompt,
params,
indexName
}) {
super(message);
this.name = 'DotCMAISearchError';
this.httpError = httpError;
this.prompt = prompt;
this.params = params;
this.indexName = indexName;
// Ensure proper prototype chain for instanceof checks
Object.setPrototypeOf(this, DotErrorAISearch.prototype);
}
/**
* Serializes the error to a plain object for logging or transmission
*/
toJSON() {
return {
name: this.name,
message: this.message,
httpError: this.httpError?.toJSON(),
prompt: this.prompt,
params: this.params,
indexName: this.indexName,
stack: this.stack
};
}
}
export { BaseHttpClient, DEVELOPMENT_MODE, DISTANCE_FUNCTIONS, DotCMSEntityState, DotCMSUVEAction, DotErrorAISearch, DotErrorContent, DotErrorNavigation, DotErrorPage, DotHttpError, PRODUCTION_MODE, UVEEventType, UVE_MODE };