@dotcms/client 0.0.1-beta.9 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. package/README.md +565 -153
  2. package/index.cjs.js +1418 -741
  3. package/index.esm.js +1418 -732
  4. package/internal.cjs.d.ts +1 -0
  5. package/internal.cjs.default.js +1 -0
  6. package/internal.cjs.js +85 -0
  7. package/internal.cjs.mjs +2 -0
  8. package/internal.esm.d.ts +1 -0
  9. package/internal.esm.js +83 -0
  10. package/package.json +14 -17
  11. package/src/index.d.ts +1 -8
  12. package/src/internal.d.ts +1 -0
  13. package/src/lib/client/client.d.ts +1 -29
  14. package/src/lib/client/content/builders/collection/collection.d.ts +1 -1
  15. package/src/lib/client/content/content-api.d.ts +3 -6
  16. package/src/lib/client/content/shared/types.d.ts +1 -42
  17. package/src/lib/client/navigation/navigation-api.d.ts +3 -20
  18. package/src/lib/client/page/page-api.d.ts +14 -84
  19. package/src/lib/utils/graphql/transforms.d.ts +2 -13
  20. package/src/lib/utils/index.d.ts +0 -1
  21. package/next.cjs.d.ts +0 -1
  22. package/next.cjs.default.js +0 -1
  23. package/next.cjs.js +0 -553
  24. package/next.cjs.mjs +0 -2
  25. package/next.esm.d.ts +0 -1
  26. package/next.esm.js +0 -551
  27. package/src/lib/client/models/types.d.ts +0 -516
  28. package/src/lib/deprecated/editor/listeners/listeners.d.ts +0 -45
  29. package/src/lib/deprecated/editor/models/client.model.d.ts +0 -111
  30. package/src/lib/deprecated/editor/models/editor.model.d.ts +0 -62
  31. package/src/lib/deprecated/editor/models/inline-event.model.d.ts +0 -9
  32. package/src/lib/deprecated/editor/models/listeners.model.d.ts +0 -55
  33. package/src/lib/deprecated/editor/sdk-editor-vtl.d.ts +0 -1
  34. package/src/lib/deprecated/editor/sdk-editor.d.ts +0 -92
  35. package/src/lib/deprecated/editor/utils/editor.utils.d.ts +0 -159
  36. package/src/lib/deprecated/editor/utils/traditional-vtl.utils.d.ts +0 -4
  37. package/src/lib/deprecated/sdk-js-client.d.ts +0 -276
  38. package/src/lib/utils/page/common-utils.d.ts +0 -33
  39. package/src/next.d.ts +0 -1
  40. package/src/types.d.ts +0 -2
  41. package/transforms.cjs.js +0 -1145
  42. package/transforms.esm.js +0 -1139
  43. package/types.cjs.d.ts +0 -1
  44. package/types.cjs.default.js +0 -1
  45. package/types.cjs.js +0 -2
  46. package/types.cjs.mjs +0 -2
  47. package/types.esm.d.ts +0 -1
  48. package/types.esm.js +0 -1
package/index.esm.js CHANGED
@@ -1,903 +1,1589 @@
1
- import { _ as __classPrivateFieldGet, E as ErrorMessages, a as __classPrivateFieldSet, C as Content } from './transforms.esm.js';
2
- export { g as graphqlToPageEntity } from './transforms.esm.js';
1
+ import consola$1, { consola } from 'consola';
2
+ import { graphqlToPageEntity } from './internal.esm.js';
3
3
 
4
+ /******************************************************************************
5
+ Copyright (c) Microsoft Corporation.
6
+
7
+ Permission to use, copy, modify, and/or distribute this software for any
8
+ purpose with or without fee is hereby granted.
9
+
10
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
11
+ REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12
+ AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
13
+ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14
+ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
15
+ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16
+ PERFORMANCE OF THIS SOFTWARE.
17
+ ***************************************************************************** */
18
+ /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
19
+
20
+
21
+ function __classPrivateFieldGet(receiver, state, kind, f) {
22
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
23
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
24
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
25
+ }
26
+
27
+ function __classPrivateFieldSet(receiver, state, value, kind, f) {
28
+ if (kind === "m") throw new TypeError("Private method is not writable");
29
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
30
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
31
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
32
+ }
33
+
34
+ typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
35
+ var e = new Error(message);
36
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
37
+ };
38
+
39
+ /**
40
+ * Default variant identifier used in the application.
41
+ */
4
42
  /**
5
- * Actions received from the dotcms editor
43
+ * Fields that should not be formatted when sanitizing the query.
44
+ * These fields are essential for maintaining the integrity of the content type.
45
+ */
46
+ const CONTENT_TYPE_MAIN_FIELDS = ['live', 'variant', 'contentType', 'languageId'];
47
+ /**
48
+ * URL endpoint for the content API search functionality.
49
+ */
50
+ const CONTENT_API_URL = '/api/content/_search';
51
+
52
+ /**
53
+ * @description
54
+ * Sanitizes the query for the given content type.
55
+ * It replaces the fields that are not content type fields with the correct format.
56
+ * Example: +field: -> +contentTypeVar.field:
57
+ *
58
+ * @example
59
+ *
60
+ * ```ts
61
+ * const query = '+field: value';
62
+ * const contentType = 'contentTypeVar';
63
+ * const sanitizedQuery = sanitizeQueryForContentType(query, contentType); // Output: '+contentTypeVar.field: value'
64
+ * ```
6
65
  *
7
66
  * @export
8
- * @enum {number}
67
+ * @param {string} query - The query string to be sanitized.
68
+ * @param {string} contentType - The content type to be used for formatting the fields.
69
+ * @returns {string} The sanitized query string.
9
70
  */
10
- var NOTIFY_CLIENT;
11
- (function (NOTIFY_CLIENT) {
71
+ function sanitizeQueryForContentType(query, contentType) {
72
+ return query.replace(/\+([^+:]*?):/g, (original, field) => {
73
+ return !CONTENT_TYPE_MAIN_FIELDS.includes(field) // Fields that are not content type fields
74
+ ? `+${contentType}.${field}:` // Should have this format: +contentTypeVar.field:
75
+ : original; // Return the field if it is a content type field
76
+ });
77
+ }
78
+
79
+ var _Field_query;
80
+ /**
81
+ * The `Field` class is used to build a query with a specific field.
82
+ * A Lucene Field is a key used to search for a specific value in a document.
83
+ *
84
+ * @export
85
+ * @class Field
86
+ */
87
+ class Field {
12
88
  /**
13
- * Request to page to reload
89
+ * Creates an instance of the `Field` class.
90
+ *
91
+ * @param {string} query - The initial query string.
14
92
  */
15
- NOTIFY_CLIENT["UVE_RELOAD_PAGE"] = "uve-reload-page";
93
+ constructor(query) {
94
+ this.query = query;
95
+ _Field_query.set(this, '');
96
+ __classPrivateFieldSet(this, _Field_query, this.query, "f");
97
+ }
16
98
  /**
17
- * Request the bounds for the elements
99
+ * Appends a term to the query that should be included in the search.
100
+ *
101
+ * @example
102
+ * ```typescript
103
+ * const field = new Field("+myField");
104
+ * field.equals("myValue");
105
+ * ```
106
+ *
107
+ * @param {string} term - The term that should be included in the search.
108
+ * @return {Equals} - An instance of `Equals`.
109
+ * @memberof Field
18
110
  */
19
- NOTIFY_CLIENT["UVE_REQUEST_BOUNDS"] = "uve-request-bounds";
111
+ equals(term) {
112
+ return buildEquals(__classPrivateFieldGet(this, _Field_query, "f"), term);
113
+ }
114
+ }
115
+ _Field_query = new WeakMap();
116
+
117
+ var _NotOperand_query;
118
+ /**
119
+ * 'NotOperand' Is a Typescript class that provides the ability to use the NOT operand in the lucene query string.
120
+ *
121
+ * @export
122
+ * @class NotOperand
123
+ */
124
+ class NotOperand {
125
+ constructor(query) {
126
+ this.query = query;
127
+ _NotOperand_query.set(this, '');
128
+ __classPrivateFieldSet(this, _NotOperand_query, this.query, "f");
129
+ }
20
130
  /**
21
- * Received pong from the editor
131
+ * This method appends to the query a term that should be included in the search.
132
+ *
133
+ * @example
134
+ * ```typescript
135
+ * const notOperand = new NotOperand("+myField");
136
+ * notOperand.equals("myValue");
137
+ * ```
138
+ *
139
+ * @param {string} term - The term that should be included in the search.
140
+ * @return {*} {Equals} - An instance of Equals.
141
+ * @memberof NotOperand
22
142
  */
23
- NOTIFY_CLIENT["UVE_EDITOR_PONG"] = "uve-editor-pong";
143
+ equals(term) {
144
+ return buildEquals(__classPrivateFieldGet(this, _NotOperand_query, "f"), term);
145
+ }
146
+ }
147
+ _NotOperand_query = new WeakMap();
148
+
149
+ var _Operand_query;
150
+ /**
151
+ * 'Operand' Is a Typescript class that provides the ability to use operands in the lucene query string.}
152
+ * An operand is a logical operator used to join two or more conditions in a query.
153
+ *
154
+ * @export
155
+ * @class Operand
156
+ */
157
+ class Operand {
158
+ constructor(query) {
159
+ this.query = query;
160
+ _Operand_query.set(this, '');
161
+ __classPrivateFieldSet(this, _Operand_query, this.query, "f");
162
+ }
24
163
  /**
25
- * Received scroll event trigger from the editor
164
+ * This method appends to the query a term that should be excluded in the search.
165
+ *
166
+ * Ex: "-myValue"
167
+ *
168
+ * @param {string} field - The field that should be excluded in the search.
169
+ * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
170
+ * @memberof Operand
26
171
  */
27
- NOTIFY_CLIENT["UVE_SCROLL_INSIDE_IFRAME"] = "uve-scroll-inside-iframe";
172
+ excludeField(field) {
173
+ return buildExcludeField(__classPrivateFieldGet(this, _Operand_query, "f"), field);
174
+ }
28
175
  /**
29
- * Set the page data
176
+ * This method appends to the query a field that should be included in the search.
177
+ *
178
+ * Ex: "+myField:"
179
+ *
180
+ * @param {string} field - The field that should be included in the search.
181
+ * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
182
+ * @memberof Operand
30
183
  */
31
- NOTIFY_CLIENT["UVE_SET_PAGE_DATA"] = "uve-set-page-data";
184
+ field(field) {
185
+ return buildField(__classPrivateFieldGet(this, _Operand_query, "f"), field);
186
+ }
32
187
  /**
33
- * Copy contentlet inline editing success
188
+ * This method appends to the query a term that should be included in the search.
189
+ *
190
+ * Ex: myValue or "My value"
191
+ *
192
+ * @param {string} term - The term that should be included in the search.
193
+ * @return {*} {Equals} - An instance of Equals.
194
+ * @memberof Operand
34
195
  */
35
- NOTIFY_CLIENT["UVE_COPY_CONTENTLET_INLINE_EDITING_SUCCESS"] = "uve-copy-contentlet-inline-editing-success";
36
- })(NOTIFY_CLIENT || (NOTIFY_CLIENT = {}));
196
+ equals(term) {
197
+ return buildEquals(__classPrivateFieldGet(this, _Operand_query, "f"), term);
198
+ }
199
+ }
200
+ _Operand_query = new WeakMap();
37
201
 
38
202
  /**
39
- * Calculates the bounding information for each page element within the given containers.
203
+ * Enum for common Operands
40
204
  *
41
205
  * @export
42
- * @param {HTMLDivElement[]} containers - An array of HTMLDivElement representing the containers.
43
- * @return {ContainerBound[]} An array of objects containing the bounding information for each page element.
44
- * @example
45
- * ```ts
46
- * const containers = document.querySelectorAll('.container');
47
- * const bounds = getPageElementBound(containers);
48
- * console.log(bounds);
49
- * ```
206
+ * @enum {number}
50
207
  */
51
- function getPageElementBound(containers) {
52
- return containers.map((container) => {
53
- const containerRect = container.getBoundingClientRect();
54
- const contentlets = Array.from(container.querySelectorAll('[data-dot-object="contentlet"]'));
55
- return {
56
- x: containerRect.x,
57
- y: containerRect.y,
58
- width: containerRect.width,
59
- height: containerRect.height,
60
- payload: JSON.stringify({
61
- container: getContainerData(container)
62
- }),
63
- contentlets: getContentletsBound(containerRect, contentlets)
64
- };
65
- });
66
- }
208
+ var OPERAND;
209
+ (function (OPERAND) {
210
+ OPERAND["OR"] = "OR";
211
+ OPERAND["AND"] = "AND";
212
+ OPERAND["NOT"] = "NOT";
213
+ })(OPERAND || (OPERAND = {}));
67
214
  /**
68
- * Calculates the bounding information for each contentlet inside a container.
215
+ * This function removes extra spaces from a string.
69
216
  *
70
- * @export
71
- * @param {DOMRect} containerRect - The bounding rectangle of the container.
72
- * @param {HTMLDivElement[]} contentlets - An array of HTMLDivElement representing the contentlets.
73
- * @return {ContentletBound[]} An array of objects containing the bounding information for each contentlet.
74
217
  * @example
75
218
  * ```ts
76
- * const containerRect = container.getBoundingClientRect();
77
- * const contentlets = container.querySelectorAll('.contentlet');
78
- * const bounds = getContentletsBound(containerRect, contentlets);
79
- * console.log(bounds); // Element bounds within the container
219
+ * sanitizeQuery(" my query "); // Output: "my query"
80
220
  * ```
221
+ *
222
+ * @export
223
+ * @param {string} str
224
+ * @return {*} {string}
81
225
  */
82
- function getContentletsBound(containerRect, contentlets) {
83
- return contentlets.map((contentlet) => {
84
- const contentletRect = contentlet.getBoundingClientRect();
85
- return {
86
- x: 0,
87
- y: contentletRect.y - containerRect.y,
88
- width: contentletRect.width,
89
- height: contentletRect.height,
90
- payload: JSON.stringify({
91
- container: contentlet.dataset?.['dotContainer']
92
- ? JSON.parse(contentlet.dataset?.['dotContainer'])
93
- : getClosestContainerData(contentlet),
94
- contentlet: {
95
- identifier: contentlet.dataset?.['dotIdentifier'],
96
- title: contentlet.dataset?.['dotTitle'],
97
- inode: contentlet.dataset?.['dotInode'],
98
- contentType: contentlet.dataset?.['dotType']
99
- }
100
- })
101
- };
102
- });
226
+ function sanitizeQuery(str) {
227
+ return str.replace(/\s{2,}/g, ' ').trim();
103
228
  }
104
229
  /**
105
- * Get container data from VTLS.
230
+ * This function sanitizes a term by adding quotes if it contains spaces.
231
+ * In lucene, a term with spaces should be enclosed in quotes.
106
232
  *
107
- * @export
108
- * @param {HTMLElement} container - The container element.
109
- * @return {object} An object containing the container data.
110
233
  * @example
111
234
  * ```ts
112
- * const container = document.querySelector('.container');
113
- * const data = getContainerData(container);
114
- * console.log(data);
235
+ * sanitizePhrases(`my term`); // Output: `"my term"`
236
+ * sanitizePhrases(`myterm`); // Output: `myterm`
115
237
  * ```
238
+ *
239
+ * @export
240
+ * @param {string} term
241
+ * @return {*} {string}
116
242
  */
117
- function getContainerData(container) {
118
- return {
119
- acceptTypes: container.dataset?.['dotAcceptTypes'] || '',
120
- identifier: container.dataset?.['dotIdentifier'] || '',
121
- maxContentlets: container.dataset?.['maxContentlets'] || '',
122
- uuid: container.dataset?.['dotUuid'] || ''
123
- };
243
+ function sanitizePhrases(term) {
244
+ return term.includes(' ') ? `'${term}'` : term;
124
245
  }
125
246
  /**
126
- * Get the closest container data from the contentlet.
247
+ * This function builds a term to be used in a lucene query.
248
+ * We need to sanitize the term before adding it to the query.
127
249
  *
128
- * @export
129
- * @param {Element} element - The contentlet element.
130
- * @return {object | null} An object containing the closest container data or null if no container is found.
131
250
  * @example
132
251
  * ```ts
133
- * const contentlet = document.querySelector('.contentlet');
134
- * const data = getClosestContainerData(contentlet);
135
- * console.log(data);
252
+ * const equals = buildEquals("+myField: ", "myValue"); // Current query: "+myField: myValue"
136
253
  * ```
137
- */
138
- function getClosestContainerData(element) {
139
- // Find the closest ancestor element with data-dot-object="container" attribute
140
- const container = element.closest('[data-dot-object="container"]');
141
- // If a container element is found
142
- if (container) {
143
- // Return the dataset of the container element
144
- return getContainerData(container);
145
- }
146
- else {
147
- // If no container element is found, return null
148
- console.warn('No container found for the contentlet');
149
- return null;
150
- }
151
- }
152
- /**
153
- * Find the closest contentlet element based on HTMLElement.
154
254
  *
155
255
  * @export
156
- * @param {HTMLElement | null} element - The starting element.
157
- * @return {HTMLElement | null} The closest contentlet element or null if not found.
158
- * @example
159
- * const element = document.querySelector('.some-element');
160
- * const contentlet = findDotElement(element);
161
- * console.log(contentlet);
256
+ * @param {string} query
257
+ * @param {string} term
258
+ * @return {*} {Equals}
162
259
  */
163
- function findDotElement(element) {
164
- if (!element)
165
- return null;
166
- if (element?.dataset?.['dotObject'] === 'contentlet' ||
167
- (element?.dataset?.['dotObject'] === 'container' && element.children.length === 0)) {
168
- return element;
169
- }
170
- return findDotElement(element?.['parentElement']);
260
+ function buildEquals(query, term) {
261
+ const newQuery = query + sanitizePhrases(term);
262
+ return new Equals(newQuery);
171
263
  }
172
264
  /**
173
- * Find VTL data within a target element.
265
+ * This function builds a term to be used in a lucene query.
266
+ * We need to sanitize the raw query before adding it to the query.
174
267
  *
175
- * @export
176
- * @param {HTMLElement} target - The target element to search within.
177
- * @return {Array<{ inode: string, name: string }> | null} An array of objects containing VTL data or null if none found.
178
268
  * @example
179
269
  * ```ts
180
- * const target = document.querySelector('.target-element');
181
- * const vtlData = findVTLData(target);
182
- * console.log(vtlData);
270
+ * const query = "+myField: myValue";
271
+ * const field = buildRawEquals(query, "-myField2: myValue2"); // Current query: "+myField: myValue -myField2: myValue"
183
272
  * ```
273
+ *
274
+ * @export
275
+ * @param {string} query
276
+ * @param {string} raw
277
+ * @return {*} {Equals}
184
278
  */
185
- function findVTLData(target) {
186
- const vltElements = target.querySelectorAll('[data-dot-object="vtl-file"]');
187
- if (!vltElements.length) {
188
- return null;
189
- }
190
- return Array.from(vltElements).map((vltElement) => {
191
- return {
192
- inode: vltElement.dataset?.['dotInode'],
193
- name: vltElement.dataset?.['dotUrl']
194
- };
195
- });
279
+ function buildRawEquals(query, raw) {
280
+ const newQuery = query + ` ${raw}`;
281
+ return new Equals(sanitizeQuery(newQuery));
196
282
  }
197
283
  /**
198
- * Check if the scroll position is at the bottom of the page.
284
+ * This function builds a field to be used in a lucene query.
285
+ * We need to format the field before adding it to the query.
199
286
  *
200
- * @export
201
- * @return {boolean} True if the scroll position is at the bottom, otherwise false.
202
287
  * @example
203
288
  * ```ts
204
- * if (scrollIsInBottom()) {
205
- * console.log('Scrolled to the bottom');
206
- * }
289
+ * const field = buildField("+myField: ", "myValue"); // Current query: "+myField: myValue"
207
290
  * ```
208
- */
209
- function scrollIsInBottom() {
210
- const documentHeight = document.documentElement.scrollHeight;
211
- const viewportHeight = window.innerHeight;
212
- const scrollY = window.scrollY;
213
- return scrollY + viewportHeight >= documentHeight;
214
- }
215
-
216
- /**
217
- * Represents an array of DotCMSPageEditorSubscription objects.
218
- * Used to store the subscriptions for the editor and unsubscribe later.
219
- */
220
- const subscriptions = [];
221
- /**
222
- * Sets the bounds of the containers in the editor.
223
- * Retrieves the containers from the DOM and sends their position data to the editor.
224
- * @private
225
- * @memberof DotCMSPageEditor
226
- */
227
- function setBounds() {
228
- const containers = Array.from(document.querySelectorAll('[data-dot-object="container"]'));
229
- const positionData = getPageElementBound(containers);
230
- postMessageToEditor({
231
- action: CLIENT_ACTIONS.SET_BOUNDS,
232
- payload: positionData
233
- });
234
- }
235
- /**
236
- * Listens for editor messages and performs corresponding actions based on the received message.
237
291
  *
238
- * @private
239
- * @memberof DotCMSPageEditor
292
+ * @export
293
+ * @param {string} query
294
+ * @param {string} field
295
+ * @return {*} {Field}
240
296
  */
241
- function listenEditorMessages() {
242
- const messageCallback = (event) => {
243
- const ACTIONS_NOTIFICATION = {
244
- [NOTIFY_CLIENT.UVE_RELOAD_PAGE]: () => {
245
- window.location.reload();
246
- },
247
- [NOTIFY_CLIENT.UVE_REQUEST_BOUNDS]: () => {
248
- setBounds();
249
- },
250
- [NOTIFY_CLIENT.UVE_SCROLL_INSIDE_IFRAME]: () => {
251
- const direction = event.data.direction;
252
- if ((window.scrollY === 0 && direction === 'up') ||
253
- (scrollIsInBottom() && direction === 'down')) {
254
- // If the iframe scroll is at the top or bottom, do not send anything.
255
- // This avoids losing the scrollend event.
256
- return;
257
- }
258
- const scrollY = direction === 'up' ? -120 : 120;
259
- window.scrollBy({ left: 0, top: scrollY, behavior: 'smooth' });
260
- }
261
- };
262
- ACTIONS_NOTIFICATION[event.data.name]?.();
263
- };
264
- window.addEventListener('message', messageCallback);
265
- subscriptions.push({
266
- type: 'listener',
267
- event: 'message',
268
- callback: messageCallback
269
- });
297
+ function buildField(query, field) {
298
+ const newQuery = query + ` +${field}:`;
299
+ return new Field(newQuery);
270
300
  }
271
301
  /**
272
- * Listens for pointer move events and extracts information about the hovered contentlet.
302
+ * This function builds an exclude field to be used in a lucene query.
303
+ * We need to format the field before adding it to the query.
273
304
  *
274
- * @private
275
- * @memberof DotCMSPageEditor
276
- */
277
- function listenHoveredContentlet() {
278
- const pointerMoveCallback = (event) => {
279
- const foundElement = findDotElement(event.target);
280
- if (!foundElement)
281
- return;
282
- const { x, y, width, height } = foundElement.getBoundingClientRect();
283
- const isContainer = foundElement.dataset?.['dotObject'] === 'container';
284
- const contentletForEmptyContainer = {
285
- identifier: 'TEMP_EMPTY_CONTENTLET',
286
- title: 'TEMP_EMPTY_CONTENTLET',
287
- contentType: 'TEMP_EMPTY_CONTENTLET_TYPE',
288
- inode: 'TEMPY_EMPTY_CONTENTLET_INODE',
289
- widgetTitle: 'TEMP_EMPTY_CONTENTLET',
290
- baseType: 'TEMP_EMPTY_CONTENTLET',
291
- onNumberOfPages: 1
292
- };
293
- const contentlet = {
294
- identifier: foundElement.dataset?.['dotIdentifier'],
295
- title: foundElement.dataset?.['dotTitle'],
296
- inode: foundElement.dataset?.['dotInode'],
297
- contentType: foundElement.dataset?.['dotType'],
298
- baseType: foundElement.dataset?.['dotBasetype'],
299
- widgetTitle: foundElement.dataset?.['dotWidgetTitle'],
300
- onNumberOfPages: foundElement.dataset?.['dotOnNumberOfPages']
301
- };
302
- const vtlFiles = findVTLData(foundElement);
303
- const contentletPayload = {
304
- container:
305
- // Here extract dot-container from contentlet if it is Headless
306
- // or search in parent container if it is VTL
307
- foundElement.dataset?.['dotContainer']
308
- ? JSON.parse(foundElement.dataset?.['dotContainer'])
309
- : getClosestContainerData(foundElement),
310
- contentlet: isContainer ? contentletForEmptyContainer : contentlet,
311
- vtlFiles
312
- };
313
- postMessageToEditor({
314
- action: CLIENT_ACTIONS.SET_CONTENTLET,
315
- payload: {
316
- x,
317
- y,
318
- width,
319
- height,
320
- payload: contentletPayload
321
- }
322
- });
323
- };
324
- document.addEventListener('pointermove', pointerMoveCallback);
325
- subscriptions.push({
326
- type: 'listener',
327
- event: 'pointermove',
328
- callback: pointerMoveCallback
329
- });
330
- }
331
- /**
332
- * Attaches a scroll event listener to the window
333
- * and sends a message to the editor when the window is scrolled.
305
+ * @example
306
+ * ```ts
307
+ * const query = "+myField: myValue";
308
+ * const field = buildExcludeField(query, "myField2"); // Current query: "+myField: myValue -myField2:"
309
+ * ```
334
310
  *
335
- * @private
336
- * @memberof DotCMSPageEditor
337
- */
338
- function scrollHandler() {
339
- const scrollCallback = () => {
340
- postMessageToEditor({
341
- action: CLIENT_ACTIONS.IFRAME_SCROLL
342
- });
343
- // In case it doesn't have a dotUVE object, we create it with the initial values.
344
- window.dotUVE = {
345
- ...(window.dotUVE ?? INITIAL_DOT_UVE),
346
- lastScrollYPosition: window.scrollY
347
- };
348
- };
349
- const scrollEndCallback = () => {
350
- postMessageToEditor({
351
- action: CLIENT_ACTIONS.IFRAME_SCROLL_END
352
- });
353
- };
354
- window.addEventListener('scroll', scrollCallback);
355
- window.addEventListener('scrollend', scrollEndCallback);
356
- subscriptions.push({
357
- type: 'listener',
358
- event: 'scroll',
359
- callback: scrollEndCallback
360
- });
361
- subscriptions.push({
362
- type: 'listener',
363
- event: 'scroll',
364
- callback: scrollCallback
365
- });
366
- }
367
- /**
368
- * Sends a message to the editor to get the page data.
369
- * @param {string} pathname - The pathname of the page.
370
- * @private
371
- * @memberof DotCMSPageEditor
311
+ * @export
312
+ * @param {string} query
313
+ * @param {string} field
314
+ * @return {*} {Field}
372
315
  */
373
- function fetchPageDataFromInsideUVE(pathname) {
374
- postMessageToEditor({
375
- action: CLIENT_ACTIONS.GET_PAGE_DATA,
376
- payload: {
377
- pathname
378
- }
379
- });
316
+ function buildExcludeField(query, field) {
317
+ const newQuery = query + ` -${field}:`;
318
+ return new Field(newQuery);
380
319
  }
381
-
382
320
  /**
383
- * Updates the navigation in the editor.
321
+ * This function builds an operand to be used in a lucene query.
322
+ * We need to format the operand before adding it to the query.
384
323
  *
385
- * @param {string} pathname - The pathname to update the navigation with.
386
- * @memberof DotCMSPageEditor
387
324
  * @example
388
- * updateNavigation('/home'); // Sends a message to the editor to update the navigation to '/home'
389
- */
390
- function updateNavigation(pathname) {
391
- postMessageToEditor({
392
- action: CLIENT_ACTIONS.NAVIGATION_UPDATE,
393
- payload: {
394
- url: pathname || '/'
395
- }
396
- });
397
- }
398
- /**
399
- * You can use this function to edit a contentlet in the editor.
400
- *
401
- * Calling this function inside the editor, will prompt the UVE to open a dialog to edit the contentlet.
402
- *
325
+ * <caption>E.g. Using the AND operand</caption>
326
+ * ```ts
327
+ * const query = "+myField: myValue";
328
+ * const field = buildOperand(query, OPERAND.AND); // Current query: "+myField: myValue AND"
329
+ * ```
330
+ * @example
331
+ * <caption>E.g. Using the OR operand</caption>
332
+ * ```ts
333
+ * const query = "+myField: myValue";
334
+ * const field = buildOperand(query, OPERAND.OR); // Current query: "+myField: myValue OR"
335
+ * ```
403
336
  * @export
404
- * @template T
405
- * @param {Contentlet<T>} contentlet - The contentlet to edit.
337
+ * @param {string} query
338
+ * @param {OPERAND} operand
339
+ * @return {*} {Operand}
406
340
  */
407
- function editContentlet(contentlet) {
408
- postMessageToEditor({
409
- action: CLIENT_ACTIONS.EDIT_CONTENTLET,
410
- payload: contentlet
411
- });
341
+ function buildOperand(query, operand) {
342
+ const newQuery = query + ` ${operand} `;
343
+ return new Operand(newQuery);
412
344
  }
413
345
  /**
414
- * Initializes the inline editing in the editor.
346
+ * This function builds a NOT operand to be used in a lucene query.
347
+ * We need to format the operand before adding it to the query.
415
348
  *
416
- * @export
417
- * @param {INLINE_EDITING_EVENT_KEY} type
418
- * @param {InlineEditEventData} eventData
419
- * @return {*}
420
- *
421
- * * @example
422
- * ```html
423
- * <div onclick="initInlineEditing('BLOCK_EDITOR', { inode, languageId, contentType, fieldName, content })">
424
- * ${My Content}
425
- * </div>
349
+ * @example
350
+ * ```ts
351
+ * const query = "+myField: myValue";
352
+ * const field = buildNotOperand(query); // Current query: "+myField: myValue NOT"
426
353
  * ```
427
- */
428
- function initInlineEditing(type, data) {
429
- postMessageToEditor({
430
- action: CLIENT_ACTIONS.INIT_INLINE_EDITING,
431
- payload: {
432
- type,
433
- data
434
- }
435
- });
436
- }
437
- /*
438
- * Reorders the menu based on the provided configuration.
439
- *
440
- * @param {ReorderMenuConfig} [config] - Optional configuration for reordering the menu.
441
- * @param {number} [config.startLevel=1] - The starting level of the menu to reorder.
442
- * @param {number} [config.depth=2] - The depth of the menu to reorder.
443
354
  *
444
- * This function constructs a URL for the reorder menu page with the specified
445
- * start level and depth, and sends a message to the editor to perform the reorder action.
355
+ * @export
356
+ * @param {string} query
357
+ * @return {*} {NotOperand}
446
358
  */
447
- function reorderMenu(config) {
448
- const { startLevel = 1, depth = 2 } = config || {};
449
- postMessageToEditor({
450
- action: CLIENT_ACTIONS.REORDER_MENU,
451
- payload: { startLevel, depth }
452
- });
359
+ function buildNotOperand(query) {
360
+ const newQuery = query + ` ${OPERAND.NOT} `;
361
+ return new NotOperand(newQuery);
453
362
  }
363
+
364
+ var _Equals_query;
454
365
  /**
455
- * @deprecated Use `getUVEState` function on {@link https://npmjs.com/package/@dotcms/uve|@dotcms/uve} instead, this function will be removed on future versions.
456
- *
457
- * Checks if the code is running inside the DotCMS Universal Visual Editor (UVE).
366
+ * 'Equal' Is a Typescript class that provides the ability to use terms in the lucene query string.
367
+ * A term is a value used to search for a specific value in a document. It can be a word or a phrase.
458
368
  *
459
- * The function checks three conditions:
460
- * 1. If window is defined (for SSR environments)
461
- * 2. If the page is not in preview mode
462
- * 3. If the current window is embedded in a parent frame
369
+ * Ex: myValue or "My Value"
463
370
  *
464
- * @returns {boolean} Returns true if running inside the UVE editor, false if running standalone or in preview mode
465
- * @example
466
- * ```ts
467
- * // Check if code is running in editor before initializing editor-specific features
468
- * if (isInsideEditor()) {
469
- * initEditor(config);
470
- * } else {
471
- * initStandaloneMode();
472
- * }
473
- * ```
371
+ * @export
372
+ * @class Equal
474
373
  */
475
- function isInsideEditor() {
476
- if (typeof window === 'undefined') {
477
- return false;
374
+ class Equals {
375
+ constructor(query) {
376
+ this.query = query;
377
+ _Equals_query.set(this, '');
378
+ __classPrivateFieldSet(this, _Equals_query, this.query, "f");
379
+ }
380
+ /**
381
+ * This method appends to the query a term that should be excluded in the search.
382
+ *
383
+ * @example
384
+ * ```ts
385
+ * const equals = new Equals("+myField: myValue");
386
+ * equals.excludeField("myField2").equals("myValue2"); // Current query: "+myField: myValue -myField2: myValue2"
387
+ * ```
388
+ *
389
+ * @param {string} field - The field that should be excluded in the search.
390
+ * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
391
+ * @memberof Equal
392
+ */
393
+ excludeField(field) {
394
+ return buildExcludeField(__classPrivateFieldGet(this, _Equals_query, "f"), field);
395
+ }
396
+ /**
397
+ * This method appends to the query a field that should be included in the search.
398
+ *
399
+ * @example
400
+ * ```ts
401
+ * const equals = new Equals("+myField: myValue");
402
+ * equals.field("myField2").equals("myValue2"); // Current query: "+myField: myValue +myField2: myValue2"
403
+ *```
404
+ * @param {string} field - The field that should be included in the search.
405
+ * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
406
+ * @memberof Equal
407
+ */
408
+ field(field) {
409
+ return buildField(__classPrivateFieldGet(this, _Equals_query, "f"), field);
410
+ }
411
+ /**
412
+ * This method appends to the query an operand to use logic operators in the query.
413
+ *
414
+ * @example
415
+ * @example
416
+ * ```ts
417
+ * const equals = new Equals("+myField: myValue");
418
+ * equals.or().field("myField2").equals("myValue2"); // Current query: "+myField: myValue OR +myField2: myValue2"
419
+ * ```
420
+ *
421
+ * @return {*} {Operand} - An instance of a Lucene Operand. An operand is a logical operator used to combine terms or phrases in a query.
422
+ * @memberof Equal
423
+ */
424
+ or() {
425
+ return buildOperand(__classPrivateFieldGet(this, _Equals_query, "f"), OPERAND.OR);
426
+ }
427
+ /**
428
+ * This method appends to the query an operand to use logic operators in the query.
429
+ *
430
+ * @example
431
+ * ```ts
432
+ * const equals = new Equals("+myField: myValue");
433
+ * equals.and().field("myField2").equals("myValue2"); // Current query: "+myField: myValue AND +myField2: myValue2"
434
+ * ```
435
+ *
436
+ * @return {*} {Operand} - An instance of a Lucene Operand. An operand is a logical operator used to combine terms or phrases in a query.
437
+ * @memberof Equal
438
+ */
439
+ and() {
440
+ return buildOperand(__classPrivateFieldGet(this, _Equals_query, "f"), OPERAND.AND);
441
+ }
442
+ /**
443
+ * This method appends to the query an operand to use logic operators in the query.
444
+ *
445
+ * @example
446
+ * ```ts
447
+ * const equals = new Equals("+myField: myValue");
448
+ * equals.not().field("myField").equals("myValue2"); // Current query: "+myField: myValue NOT +myField: myValue2"
449
+ * ```
450
+ *
451
+ * @return {*} {NotOperand} - An instance of a Lucene Not Operand. A not operand is a logical operator used to exclude terms or phrases in a query.
452
+ * @memberof Equal
453
+ */
454
+ not() {
455
+ return buildNotOperand(__classPrivateFieldGet(this, _Equals_query, "f"));
456
+ }
457
+ /**
458
+ * This method allows to pass a raw query string to the query builder.
459
+ * This raw query should end in a Lucene Equal.
460
+ * This method is useful when you want to append a complex query or an already written query to the query builder.
461
+ *
462
+ * @example
463
+ * ```ts
464
+ * // This builds the follow raw query "+myField: value AND (someOtherValue OR anotherValue)"
465
+ * const equals = new Equals("+myField: value");
466
+ * equals.raw("+myField2: value2"); // Current query: "+myField: value +myField2: anotherValue"
467
+ * ```
468
+ *
469
+ * @param {string} query - A raw query string.
470
+ * @return {*} {Equal} - An instance of a Lucene Equal. A term is a value used to search for a specific value in a document.
471
+ * @memberof QueryBuilder
472
+ */
473
+ raw(query) {
474
+ return buildRawEquals(__classPrivateFieldGet(this, _Equals_query, "f"), query);
475
+ }
476
+ /**
477
+ * This method returns the final query string.
478
+ *
479
+ * @example
480
+ * ```ts
481
+ * const equals = new Equals("+myField: myValue");
482
+ * equals.field("myField2").equals("myValue2").build(); // Returns "+myField: myValue +myField2: myValue2"
483
+ * ```
484
+ *
485
+ * @return {*} {string} - The final query string.
486
+ * @memberof Equal
487
+ */
488
+ build() {
489
+ return sanitizeQuery(__classPrivateFieldGet(this, _Equals_query, "f"));
478
490
  }
479
- return window.parent !== window;
480
- }
481
- function initDotUVE() {
482
- window.dotUVE = INITIAL_DOT_UVE;
483
491
  }
492
+ _Equals_query = new WeakMap();
493
+
494
+ var _QueryBuilder_query;
484
495
  /**
485
- * Initializes the DotCMS page editor.
486
- *
487
- * @param {DotCMSPageEditorConfig} config - Optional configuration for the editor.
496
+ * 'QueryBuilder' Is a Typescript class that provides the ability to build a query string using the Lucene syntax in a more readable way.
488
497
  * @example
489
498
  * ```ts
490
- * const config = { pathname: '/home' };
491
- * initEditor(config); // Initializes the editor with the provided configuration
499
+ * const qb = new QueryBuilder();
500
+ * const query = qb
501
+ * .field('contentType')
502
+ * .equals('Blog')
503
+ * .field('conhost')
504
+ * .equals('my-super-cool-site')
505
+ * .build(); // Output: `+contentType:Blog +conhost:my-super-cool-site"`
492
506
  * ```
493
- */
494
- function initEditor(config) {
495
- initDotUVE();
496
- fetchPageDataFromInsideUVE(config.pathname);
497
- listenEditorMessages();
498
- listenHoveredContentlet();
499
- scrollHandler();
500
- }
501
- /**
502
- * Destroys the editor by removing event listeners and disconnecting observers.
503
507
  *
504
508
  * @example
505
509
  * ```ts
506
- * destroyEditor(); // Cleans up the editor by removing all event listeners and disconnecting observers
510
+ * const qb = new QueryBuilder();
511
+ * const query = qb
512
+ * .field('contentType')
513
+ * .equals('Blog')
514
+ * .field('title')
515
+ * .equals('Football')
516
+ * .excludeField('summary')
517
+ * .equals('Lionel Messi')
518
+ * .build(); // Output: `+contentType:Blog +title:Football -summary:"Lionel Messi"`
507
519
  * ```
520
+ * @export
521
+ * @class QueryBuilder
508
522
  */
509
- function destroyEditor() {
510
- subscriptions.forEach((subscription) => {
511
- if (subscription.type === 'listener') {
512
- window.removeEventListener(subscription.event, subscription.callback);
513
- }
514
- if (subscription.type === 'observer') {
515
- subscription.observer.disconnect();
516
- }
517
- });
523
+ class QueryBuilder {
524
+ constructor() {
525
+ _QueryBuilder_query.set(this, '');
526
+ }
527
+ /**
528
+ * This method appends to the query a field that should be included in the search.
529
+ *
530
+ * @example
531
+ * ```ts
532
+ * const qb = new QueryBuilder();
533
+ * qb.field("+myField: ", "myValue"); // Current query: "+myField: myValue"
534
+ * ```
535
+ *
536
+ * @param {string} field - The field that should be included in the search.
537
+ * @return {*} {Field} - An instance of a Lucene Field. A field is a key used to search for a specific value in a document.
538
+ * @memberof QueryBuilder
539
+ */
540
+ field(field) {
541
+ return buildField(__classPrivateFieldGet(this, _QueryBuilder_query, "f"), field);
542
+ }
543
+ /**
544
+ * This method appends to the query a field that should be excluded from the search.
545
+ *
546
+ * @example
547
+ * ```ts
548
+ * const qb = new QueryBuilder();
549
+ * qb.excludeField("myField").equals("myValue"); // Current query: "-myField: myValue"
550
+ * ```
551
+ *
552
+ * @param {string} field - The field that should be excluded from the search.
553
+ * @return {*} {Field} - An instance of a Lucene Exclude Field. An exclude field is a key used to exclude for a specific value in a document.
554
+ * @memberof QueryBuilder
555
+ */
556
+ excludeField(field) {
557
+ return buildExcludeField(__classPrivateFieldGet(this, _QueryBuilder_query, "f"), field);
558
+ }
559
+ /**
560
+ * This method allows to pass a raw query string to the query builder.
561
+ * This raw query should end in Equals.
562
+ * This method is useful when you want to append a complex query or an already written query to the query builder.
563
+ *
564
+ * @example
565
+ * ```ts
566
+ * const qb = new QueryBuilder();
567
+ * qb.raw("+myField: value AND (someOtherValue OR anotherValue)"); // Current query: "+myField: value AND (someOtherValue OR anotherValue)"
568
+ * ```
569
+ *
570
+ * @param {string} query - A raw query string.
571
+ * @return {*} {Equals} - An instance of Equals. A term is a value used to search for a specific value in a document.
572
+ * @memberof QueryBuilder
573
+ */
574
+ raw(query) {
575
+ return buildRawEquals(__classPrivateFieldGet(this, _QueryBuilder_query, "f"), query);
576
+ }
518
577
  }
578
+ _QueryBuilder_query = new WeakMap();
519
579
 
520
- const INITIAL_DOT_UVE = {
521
- editContentlet,
522
- initInlineEditing,
523
- reorderMenu,
524
- lastScrollYPosition: 0
525
- };
580
+ var _CollectionBuilder_page, _CollectionBuilder_limit, _CollectionBuilder_depth, _CollectionBuilder_render, _CollectionBuilder_sortBy, _CollectionBuilder_contentType, _CollectionBuilder_defaultQuery, _CollectionBuilder_query, _CollectionBuilder_rawQuery, _CollectionBuilder_languageId, _CollectionBuilder_draft, _CollectionBuilder_serverUrl, _CollectionBuilder_requestOptions;
526
581
  /**
527
- * Actions send to the dotcms editor
582
+ * Creates a Builder to filter and fetch content from the content API for a specific content type.
528
583
  *
529
584
  * @export
530
- * @enum {number}
585
+ * @class CollectionBuilder
586
+ * @template T Represents the type of the content type to fetch. Defaults to unknown.
531
587
  */
532
- var CLIENT_ACTIONS;
533
- (function (CLIENT_ACTIONS) {
588
+ class CollectionBuilder {
534
589
  /**
535
- * Tell the dotcms editor that page change
590
+ * Creates an instance of CollectionBuilder.
591
+ * @param {ClientOptions} requestOptions Options for the client request.
592
+ * @param {string} serverUrl The server URL.
593
+ * @param {string} contentType The content type to fetch.
594
+ * @memberof CollectionBuilder
536
595
  */
537
- CLIENT_ACTIONS["NAVIGATION_UPDATE"] = "set-url";
596
+ constructor(requestOptions, serverUrl, contentType) {
597
+ _CollectionBuilder_page.set(this, 1);
598
+ _CollectionBuilder_limit.set(this, 10);
599
+ _CollectionBuilder_depth.set(this, 0);
600
+ _CollectionBuilder_render.set(this, false);
601
+ _CollectionBuilder_sortBy.set(this, void 0);
602
+ _CollectionBuilder_contentType.set(this, void 0);
603
+ _CollectionBuilder_defaultQuery.set(this, void 0);
604
+ _CollectionBuilder_query.set(this, void 0);
605
+ _CollectionBuilder_rawQuery.set(this, void 0);
606
+ _CollectionBuilder_languageId.set(this, 1);
607
+ _CollectionBuilder_draft.set(this, false);
608
+ _CollectionBuilder_serverUrl.set(this, void 0);
609
+ _CollectionBuilder_requestOptions.set(this, void 0);
610
+ __classPrivateFieldSet(this, _CollectionBuilder_requestOptions, requestOptions, "f");
611
+ __classPrivateFieldSet(this, _CollectionBuilder_serverUrl, serverUrl, "f");
612
+ __classPrivateFieldSet(this, _CollectionBuilder_contentType, contentType, "f");
613
+ // Build the default query with the contentType field
614
+ __classPrivateFieldSet(this, _CollectionBuilder_defaultQuery, new QueryBuilder().field('contentType').equals(__classPrivateFieldGet(this, _CollectionBuilder_contentType, "f")), "f");
615
+ }
538
616
  /**
539
- * Send the element position of the rows, columnsm containers and contentlets
617
+ * Returns the sort query in the format: field order, field order, ...
618
+ *
619
+ * @readonly
620
+ * @private
621
+ * @memberof CollectionBuilder
540
622
  */
541
- CLIENT_ACTIONS["SET_BOUNDS"] = "set-bounds";
623
+ get sort() {
624
+ return __classPrivateFieldGet(this, _CollectionBuilder_sortBy, "f")?.map((sort) => `${sort.field} ${sort.order}`).join(',');
625
+ }
542
626
  /**
543
- * Send the information of the hovered contentlet
627
+ * Returns the offset for pagination.
628
+ *
629
+ * @readonly
630
+ * @private
631
+ * @memberof CollectionBuilder
544
632
  */
545
- CLIENT_ACTIONS["SET_CONTENTLET"] = "set-contentlet";
633
+ get offset() {
634
+ return __classPrivateFieldGet(this, _CollectionBuilder_limit, "f") * (__classPrivateFieldGet(this, _CollectionBuilder_page, "f") - 1);
635
+ }
546
636
  /**
547
- * Tell the editor that the page is being scrolled
637
+ * Returns the full URL for the content API.
638
+ *
639
+ * @readonly
640
+ * @private
641
+ * @memberof CollectionBuilder
548
642
  */
549
- CLIENT_ACTIONS["IFRAME_SCROLL"] = "scroll";
643
+ get url() {
644
+ return `${__classPrivateFieldGet(this, _CollectionBuilder_serverUrl, "f")}${CONTENT_API_URL}`;
645
+ }
550
646
  /**
551
- * Tell the editor that the page has stopped scrolling
647
+ * Returns the current query built.
648
+ *
649
+ * @readonly
650
+ * @private
651
+ * @memberof CollectionBuilder
552
652
  */
553
- CLIENT_ACTIONS["IFRAME_SCROLL_END"] = "scroll-end";
653
+ get currentQuery() {
654
+ return __classPrivateFieldGet(this, _CollectionBuilder_query, "f") ?? __classPrivateFieldGet(this, _CollectionBuilder_defaultQuery, "f");
655
+ }
554
656
  /**
555
- * Ping the editor to see if the page is inside the editor
657
+ * Filters the content by the specified language ID.
658
+ *
659
+ * @example
660
+ * ```typescript
661
+ * const client = new DotCMSClient(config);
662
+ * const collectionBuilder = client.content.getCollection("Blog");
663
+ * collectionBuilder.language(1);
664
+ * ```
665
+ *
666
+ * @param {number | string} languageId The language ID to filter the content by.
667
+ * @return {CollectionBuilder} A CollectionBuilder instance.
668
+ * @memberof CollectionBuilder
556
669
  */
557
- CLIENT_ACTIONS["PING_EDITOR"] = "ping-editor";
670
+ language(languageId) {
671
+ __classPrivateFieldSet(this, _CollectionBuilder_languageId, languageId, "f");
672
+ return this;
673
+ }
558
674
  /**
559
- * Tell the editor to init the inline editing editor.
675
+ * Setting this to true will server side render (using velocity) any widgets that are returned by the content query.
676
+ *
677
+ * More information here: {@link https://www.dotcms.com/docs/latest/content-api-retrieval-and-querying#ParamsOptional}
678
+ *
679
+ * @return {CollectionBuilder} A CollectionBuilder instance.
680
+ * @memberof CollectionBuilder
560
681
  */
561
- CLIENT_ACTIONS["INIT_INLINE_EDITING"] = "init-inline-editing";
682
+ render() {
683
+ __classPrivateFieldSet(this, _CollectionBuilder_render, true, "f");
684
+ return this;
685
+ }
562
686
  /**
563
- * Tell the editor to open the Copy-contentlet dialog
564
- * To copy a content and then edit it inline.
687
+ * Sorts the content by the specified fields and orders.
688
+ *
689
+ * @example
690
+ * ```typescript
691
+ * const client = new DotCMSClient(config);
692
+ * const collectionBuilder = client.content.getCollection("Blog");
693
+ * const sortBy = [{ field: 'title', order: 'asc' }, { field: 'modDate', order: 'desc' }];
694
+ * collectionBuilder("Blog").sortBy(sortBy);
695
+ * ```
696
+ *
697
+ * @param {SortBy[]} sortBy Array of constraints to sort the content by.
698
+ * @return {CollectionBuilder} A CollectionBuilder instance.
699
+ * @memberof CollectionBuilder
565
700
  */
566
- CLIENT_ACTIONS["COPY_CONTENTLET_INLINE_EDITING"] = "copy-contentlet-inline-editing";
701
+ sortBy(sortBy) {
702
+ __classPrivateFieldSet(this, _CollectionBuilder_sortBy, sortBy, "f");
703
+ return this;
704
+ }
567
705
  /**
568
- * Tell the editor to save inline edited contentlet
706
+ * Sets the maximum amount of content to fetch.
707
+ *
708
+ * @param {number} limit The maximum amount of content to fetch.
709
+ * @return {CollectionBuilder} A CollectionBuilder instance.
710
+ * @memberof CollectionBuilder
569
711
  */
570
- CLIENT_ACTIONS["UPDATE_CONTENTLET_INLINE_EDITING"] = "update-contentlet-inline-editing";
712
+ limit(limit) {
713
+ __classPrivateFieldSet(this, _CollectionBuilder_limit, limit, "f");
714
+ return this;
715
+ }
571
716
  /**
572
- * Tell the editor to trigger a menu reorder
717
+ * Sets the page number to fetch.
718
+ *
719
+ * @param {number} page The page number to fetch.
720
+ * @return {CollectionBuilder} A CollectionBuilder instance.
721
+ * @memberof CollectionBuilder
573
722
  */
574
- CLIENT_ACTIONS["REORDER_MENU"] = "reorder-menu";
723
+ page(page) {
724
+ __classPrivateFieldSet(this, _CollectionBuilder_page, page, "f");
725
+ return this;
726
+ }
727
+ query(arg) {
728
+ if (typeof arg === 'string') {
729
+ __classPrivateFieldSet(this, _CollectionBuilder_rawQuery, arg, "f");
730
+ return this;
731
+ }
732
+ if (typeof arg !== 'function') {
733
+ throw new Error(`Parameter for query method should be a buildQuery function or a string.\nExample:\nclient.content.getCollection('Activity').query((queryBuilder) => queryBuilder.field('title').equals('Hello World'))\nor\nclient.content.getCollection('Activity').query('+Activity.title:"Hello World"') \nSee documentation for more information.`);
734
+ }
735
+ const builtQuery = arg(new QueryBuilder());
736
+ // This can be use in Javascript so we cannot rely on the type checking
737
+ if (builtQuery instanceof Equals) {
738
+ __classPrivateFieldSet(this, _CollectionBuilder_query, builtQuery.raw(this.currentQuery.build()), "f");
739
+ }
740
+ else {
741
+ throw new Error('Provided query is not valid. A query should end in an equals method call.\nExample:\n(queryBuilder) => queryBuilder.field("title").equals("Hello World")\nSee documentation for more information.');
742
+ }
743
+ return this;
744
+ }
575
745
  /**
576
- * Tell the editor to send the page info to iframe
746
+ * Retrieves draft content.
747
+ * @example
748
+ * ```ts
749
+ * const client = new DotCMSClient(config);
750
+ * const collectionBuilder = client.content.getCollection("Blog");
751
+ * collectionBuilder
752
+ * .draft() // This will retrieve draft/working content
753
+ * .then((response) => // Your code here })
754
+ * .catch((error) => // Your code here })
755
+ * ```
756
+ *
757
+ * @return {CollectionBuilder} A CollectionBuilder instance.
758
+ * @memberof CollectionBuilder
577
759
  */
578
- CLIENT_ACTIONS["GET_PAGE_DATA"] = "get-page-data";
760
+ draft() {
761
+ __classPrivateFieldSet(this, _CollectionBuilder_draft, true, "f");
762
+ return this;
763
+ }
579
764
  /**
580
- * Tell the editor an user send a graphql query
765
+ * Filters the content by a variant ID for [Experiments](https://www.dotcms.com/docs/latest/experiments-and-a-b-testing)
766
+ *
767
+ * More information here: {@link https://www.dotcms.com/docs/latest/content-api-retrieval-and-querying#ParamsOptional}
768
+ *
769
+ * @example
770
+ * ```ts
771
+ * const client = new DotCMSClient(config);
772
+ * const collectionBuilder = client.content.getCollection("Blog");
773
+ * collectionBuilder
774
+ * .variant("YOUR_VARIANT_ID")
775
+ * .then((response) => // Your code here })
776
+ * .catch((error) => // Your code here })
777
+ * ```
778
+ *
779
+ * @param {string} variantId A string that represents a variant ID.
780
+ * @return {CollectionBuilder} A CollectionBuilder instance.
781
+ * @memberof CollectionBuilder
581
782
  */
582
- CLIENT_ACTIONS["CLIENT_READY"] = "client-ready";
783
+ variant(variantId) {
784
+ __classPrivateFieldSet(this, _CollectionBuilder_query, this.currentQuery.field('variant').equals(variantId), "f");
785
+ return this;
786
+ }
583
787
  /**
584
- * Tell the editor to edit a contentlet
788
+ * Sets the depth of the relationships of the content.
789
+ * Specifies the depth of related content to return in the results.
790
+ *
791
+ * More information here: {@link https://www.dotcms.com/docs/latest/content-api-retrieval-and-querying#ParamsOptional}
792
+ *
793
+ * @example
794
+ * ```ts
795
+ * const client = new DotCMSClient(config);
796
+ * const collectionBuilder = client.content.getCollection("Blog");
797
+ * collectionBuilder
798
+ * .depth(1)
799
+ * .then((response) => // Your code here })
800
+ * .catch((error) => // Your code here })
801
+ * ```
802
+ *
803
+ * @param {number} depth The depth of the relationships of the content.
804
+ * @return {CollectionBuilder} A CollectionBuilder instance.
805
+ * @memberof CollectionBuilder
585
806
  */
586
- CLIENT_ACTIONS["EDIT_CONTENTLET"] = "edit-contentlet";
807
+ depth(depth) {
808
+ if (depth < 0 || depth > 3) {
809
+ throw new Error('Depth value must be between 0 and 3');
810
+ }
811
+ __classPrivateFieldSet(this, _CollectionBuilder_depth, depth, "f");
812
+ return this;
813
+ }
587
814
  /**
588
- * Tell the editor to do nothing
815
+ * Executes the fetch and returns a promise that resolves to the content or rejects with an error.
816
+ *
817
+ * @example
818
+ * ```ts
819
+ * const client = new DotCMSClient(config);
820
+ * const collectionBuilder = client.content.getCollection("Blog");
821
+ * collectionBuilder
822
+ * .limit(10)
823
+ * .then((response) => // Your code here })
824
+ * .catch((error) => // Your code here })
825
+ * ```
826
+ *
827
+ * @param {OnFullfilled} [onfulfilled] A callback that is called when the fetch is successful.
828
+ * @param {OnRejected} [onrejected] A callback that is called when the fetch fails.
829
+ * @return {Promise<GetCollectionResponse<T> | GetCollectionError>} A promise that resolves to the content or rejects with an error.
830
+ * @memberof CollectionBuilder
589
831
  */
590
- CLIENT_ACTIONS["NOOP"] = "noop";
591
- })(CLIENT_ACTIONS || (CLIENT_ACTIONS = {}));
592
- /**
593
- * Post message to dotcms page editor
594
- *
595
- * @export
596
- * @template T
597
- * @param {PostMessageProps<T>} message
598
- */
599
- function postMessageToEditor(message) {
600
- window.parent.postMessage(message, '*');
601
- }
602
-
603
- var _DotCmsClient_config, _DotCmsClient_requestOptions, _DotCmsClient_listeners;
604
- function getHostURL(url) {
605
- try {
606
- return new URL(url);
832
+ then(onfulfilled, onrejected) {
833
+ return this.fetch().then(async (response) => {
834
+ const data = await response.json();
835
+ if (response.ok) {
836
+ const formattedResponse = this.formatResponse(data);
837
+ const finalResponse = typeof onfulfilled === 'function'
838
+ ? onfulfilled(formattedResponse)
839
+ : formattedResponse;
840
+ return finalResponse;
841
+ }
842
+ else {
843
+ return {
844
+ status: response.status,
845
+ ...data
846
+ };
847
+ }
848
+ }, onrejected);
607
849
  }
608
- catch (error) {
609
- return undefined;
850
+ /**
851
+ * Formats the response to the desired format.
852
+ *
853
+ * @private
854
+ * @param {GetCollectionRawResponse<T>} data The raw response data.
855
+ * @return {GetCollectionResponse<T>} The formatted response.
856
+ * @memberof CollectionBuilder
857
+ */
858
+ formatResponse(data) {
859
+ const contentlets = data.entity.jsonObjectView.contentlets;
860
+ const total = data.entity.resultsSize;
861
+ const mappedResponse = {
862
+ contentlets,
863
+ total,
864
+ page: __classPrivateFieldGet(this, _CollectionBuilder_page, "f"),
865
+ size: contentlets.length
866
+ };
867
+ return __classPrivateFieldGet(this, _CollectionBuilder_sortBy, "f")
868
+ ? {
869
+ ...mappedResponse,
870
+ sortedBy: __classPrivateFieldGet(this, _CollectionBuilder_sortBy, "f")
871
+ }
872
+ : mappedResponse;
873
+ }
874
+ /**
875
+ * Calls the content API to fetch the content.
876
+ *
877
+ * @private
878
+ * @return {Promise<Response>} The fetch response.
879
+ * @memberof CollectionBuilder
880
+ */
881
+ fetch() {
882
+ const finalQuery = this.currentQuery
883
+ .field('languageId')
884
+ .equals(__classPrivateFieldGet(this, _CollectionBuilder_languageId, "f").toString())
885
+ .field('live')
886
+ .equals((!__classPrivateFieldGet(this, _CollectionBuilder_draft, "f")).toString())
887
+ .build();
888
+ const sanitizedQuery = sanitizeQueryForContentType(finalQuery, __classPrivateFieldGet(this, _CollectionBuilder_contentType, "f"));
889
+ const query = __classPrivateFieldGet(this, _CollectionBuilder_rawQuery, "f") ? `${sanitizedQuery} ${__classPrivateFieldGet(this, _CollectionBuilder_rawQuery, "f")}` : sanitizedQuery;
890
+ return fetch(this.url, {
891
+ ...__classPrivateFieldGet(this, _CollectionBuilder_requestOptions, "f"),
892
+ method: 'POST',
893
+ headers: {
894
+ ...__classPrivateFieldGet(this, _CollectionBuilder_requestOptions, "f").headers,
895
+ 'Content-Type': 'application/json'
896
+ },
897
+ body: JSON.stringify({
898
+ query,
899
+ render: __classPrivateFieldGet(this, _CollectionBuilder_render, "f"),
900
+ sort: this.sort,
901
+ limit: __classPrivateFieldGet(this, _CollectionBuilder_limit, "f"),
902
+ offset: this.offset,
903
+ depth: __classPrivateFieldGet(this, _CollectionBuilder_depth, "f")
904
+ //userId: This exist but we currently don't use it
905
+ //allCategoriesInfo: This exist but we currently don't use it
906
+ })
907
+ });
610
908
  }
611
909
  }
910
+ _CollectionBuilder_page = new WeakMap(), _CollectionBuilder_limit = new WeakMap(), _CollectionBuilder_depth = new WeakMap(), _CollectionBuilder_render = new WeakMap(), _CollectionBuilder_sortBy = new WeakMap(), _CollectionBuilder_contentType = new WeakMap(), _CollectionBuilder_defaultQuery = new WeakMap(), _CollectionBuilder_query = new WeakMap(), _CollectionBuilder_rawQuery = new WeakMap(), _CollectionBuilder_languageId = new WeakMap(), _CollectionBuilder_draft = new WeakMap(), _CollectionBuilder_serverUrl = new WeakMap(), _CollectionBuilder_requestOptions = new WeakMap();
911
+
912
+ var _Content_requestOptions, _Content_serverUrl;
612
913
  /**
613
- * `DotCmsClient` is a TypeScript class that provides methods to interact with the DotCMS REST API.
614
- * DotCMS is a hybrid-headless CMS and digital experience platform.
615
- *
616
- * @class DotCmsClient
617
- * @property {ClientConfig} config - The configuration object for the DotCMS client.
618
- * @property {Content} content - Provides methods to interact with content in DotCMS.
914
+ * Creates a builder to filter and fetch a collection of content items.
915
+ * @param contentType - The content type to retrieve.
916
+ * @returns A CollectionBuilder instance for chaining filters and executing the query.
917
+ * @template T - The type of the content items (defaults to unknown).
619
918
  *
620
- * @method constructor(config: ClientConfig) - Constructs a new instance of the DotCmsClient class.
919
+ * @example Fetch blog posts with async/await
920
+ * ```typescript
921
+ * const response = await client.content
922
+ * .getCollection<BlogPost>('Blog')
923
+ * .limit(10)
924
+ * .page(2)
925
+ * .sortBy([{ field: 'title', order: 'asc' }])
926
+ * .query(q => q.field('author').equals('John Doe'))
927
+ * .depth(1)
621
928
  *
622
- * @method page.get(options: PageApiOptions): Promise<PageApiResponse> - Retrieves all the elements of any Page in your dotCMS system in JSON format.
623
- * The Page API enables you to retrieve page information, layout, template, content blocks, and more.
624
- * @see {@link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas}
625
- *
626
- * @method nav.get(options: NavApiOptions = { depth: 0, path: '/', languageId: 1 }): Promise<NavApiResponse> - Retrieves information about the dotCMS file and folder tree.
627
- * The Navigation API allows you to fetch the site structure and menu items.
628
- * @see {@link https://www.dotcms.com/docs/latest/navigation-rest-api}
629
- *
630
- * @method content.get(options: ContentApiOptions): Promise<ContentApiResponse> - Retrieves content items based on specified criteria.
631
- * The Content API allows you to query and retrieve content by ID, inode, or using Lucene queries.
632
- * @see {@link https://www.dotcms.com/docs/latest/content-api-retrieval-and-querying}
633
- *
634
- * @method editor.on(action: string, callbackFn: (payload: unknown) => void) - Allows you to react to actions issued by the Universal Visual Editor (UVE).
635
- * @method editor.off(action: string) - Stops listening to an action issued by UVE.
929
+ * console.log(response.contentlets);
930
+ * ```
636
931
  *
637
- * @static
638
- * @method init(config: ClientConfig): DotCmsClient - Initializes and returns a DotCmsClient instance.
639
- * @method dotcmsUrl: string - Retrieves the DotCMS URL from the instance configuration.
932
+ * @example Fetch blog posts with Promise chain
933
+ * ```typescript
934
+ * client.content
935
+ * .getCollection<BlogPost>('Blog')
936
+ * .limit(10)
937
+ * .page(2)
938
+ * .sortBy([{ field: 'title', order: 'asc' }])
939
+ * .query(q => q.field('author').equals('John Doe'))
940
+ * .depth(1)
941
+ * .then(response => console.log(response.contentlets))
942
+ * .catch(error => console.error(error));
943
+ * ```
640
944
  *
641
- * @example <caption>Basic usage</caption>
642
- * ```javascript
643
- * const client = DotCmsClient.init({ dotcmsUrl: 'https://demo.dotcms.com', authToken: 'your-auth-token' });
945
+ * @example Using a custom type
946
+ * ```typescript
947
+ * interface BlogPost {
948
+ * summary: string;
949
+ * author: string;
950
+ * title: string;
951
+ * }
644
952
  *
645
- * // Get a page
646
- * client.page.get({ path: '/about-us' }).then(response => console.log(response));
953
+ * const posts = await client.content
954
+ * .getCollection<BlogPost>('Blog')
955
+ * .limit(10)
647
956
  *
648
- * // Get navigation
649
- * client.nav.get({ path: '/about-us', depth: 2 }).then(response => console.log(response));
957
+ * posts.contentlets.forEach(post => {
958
+ * console.log(post.title, post.author, post.summary);
959
+ * });
960
+ * ```
961
+ */
962
+ class Content {
963
+ /**
964
+ * Creates an instance of Content.
965
+ * @param {RequestOptions} requestOptions - The options for the client request.
966
+ * @param {string} serverUrl - The server URL.
967
+ */
968
+ constructor(requestOptions, serverUrl) {
969
+ _Content_requestOptions.set(this, void 0);
970
+ _Content_serverUrl.set(this, void 0);
971
+ __classPrivateFieldSet(this, _Content_requestOptions, requestOptions, "f");
972
+ __classPrivateFieldSet(this, _Content_serverUrl, serverUrl, "f");
973
+ }
974
+ /**
975
+ * Takes a content type and returns a builder to filter and fetch the collection.
976
+ * @param {string} contentType - The content type to get the collection.
977
+ * @return {CollectionBuilder<T>} CollectionBuilder to filter and fetch the collection.
978
+ * @template T - Represents the type of the content type to fetch. Defaults to unknown.
979
+ * @memberof Content
980
+ *
981
+ * @example
982
+ * ```javascript
983
+ * // Using await and async
984
+ * const collectionResponse = await client.content
985
+ * .getCollection('Blog')
986
+ * .limit(10)
987
+ * .page(2)
988
+ * .sortBy([{ field: 'title', order: 'asc' }])
989
+ * .query((queryBuilder) => queryBuilder.field('author').equals('John Doe'))
990
+ * .depth(1);
991
+ * ```
992
+ * @example
993
+ * ```javascript
994
+ * // Using then and catch
995
+ * client.content
996
+ * .getCollection('Blog')
997
+ * .limit(10)
998
+ * .page(2)
999
+ * .sortBy([{ field: 'title', order: 'asc' }])
1000
+ * .query((queryBuilder) => queryBuilder.field('author').equals('John Doe'))
1001
+ * .depth(1)
1002
+ * .then((response) => {
1003
+ * console.log(response.contentlets);
1004
+ * })
1005
+ * .catch((error) => {
1006
+ * console.error(error);
1007
+ * });
1008
+ * ```
1009
+ * @example
1010
+ * ```typescript
1011
+ * // Using a specific type for your content
1012
+ *
1013
+ * type Blog = {
1014
+ * summary: string;
1015
+ * author: string;
1016
+ * title: string;
1017
+ * };
1018
+ *
1019
+ * client.content
1020
+ * .getCollection<Blog>('Blog')
1021
+ * .limit(10)
1022
+ * .page(2)
1023
+ * .sortBy([{ field: 'title', order: 'asc' }])
1024
+ * .query((queryBuilder) => queryBuilder.field('author').equals('John Doe'))
1025
+ * .depth(1)
1026
+ * .then((response) => {
1027
+ * response.contentlets.forEach((blog) => {
1028
+ * console.log(blog.title);
1029
+ * console.log(blog.author);
1030
+ * console.log(blog.summary);
1031
+ * });
1032
+ * })
1033
+ * .catch((error) => {
1034
+ * console.error(error);
1035
+ * });
1036
+ * ```
1037
+ *
1038
+ */
1039
+ getCollection(contentType) {
1040
+ return new CollectionBuilder(__classPrivateFieldGet(this, _Content_requestOptions, "f"), __classPrivateFieldGet(this, _Content_serverUrl, "f"), contentType);
1041
+ }
1042
+ }
1043
+ _Content_requestOptions = new WeakMap(), _Content_serverUrl = new WeakMap();
1044
+
1045
+ class NavigationClient {
1046
+ constructor(config, requestOptions) {
1047
+ this.requestOptions = requestOptions;
1048
+ this.BASE_URL = `${config?.dotcmsUrl}/api/v1/nav`;
1049
+ }
1050
+ /**
1051
+ * Retrieves information about the dotCMS file and folder tree.
1052
+ * @param {NavigationApiOptions} options - The options for the Navigation API call. Defaults to `{ depth: 0, path: '/', languageId: 1 }`.
1053
+ * @returns {Promise<DotCMSNavigationItem[]>} - A Promise that resolves to the response from the DotCMS API.
1054
+ * @throws {Error} - Throws an error if the options are not valid.
1055
+ */
1056
+ async get(path, params) {
1057
+ if (!path) {
1058
+ throw new Error("The 'path' parameter is required for the Navigation API");
1059
+ }
1060
+ const navParams = params ? this.mapToBackendParams(params) : {};
1061
+ const urlParams = new URLSearchParams(navParams).toString();
1062
+ const parsedPath = path.replace(/^\/+/, '/').replace(/\/+$/, '/');
1063
+ const url = `${this.BASE_URL}${parsedPath}${urlParams ? `?${urlParams}` : ''}`;
1064
+ const response = await fetch(url, this.requestOptions);
1065
+ if (!response.ok) {
1066
+ throw new Error(`Failed to fetch navigation data: ${response.statusText} - ${response.status}`);
1067
+ }
1068
+ return response.json().then((data) => data.entity);
1069
+ }
1070
+ mapToBackendParams(params) {
1071
+ const backendParams = {};
1072
+ if (params.depth) {
1073
+ backendParams['depth'] = String(params.depth);
1074
+ }
1075
+ if (params.languageId) {
1076
+ backendParams['language_id'] = String(params.languageId);
1077
+ }
1078
+ return backendParams;
1079
+ }
1080
+ }
1081
+
1082
+ /**
1083
+ * A record of HTTP status codes and their corresponding error messages.
650
1084
  *
651
- * // Get content
652
- * client.content.get({ query: '+contentType:Blog +languageId:1', limit: 10 }).then(response => console.log(response));
1085
+ * @type {Record<number, string>}
1086
+ * @property {string} 401 - Unauthorized. Check the token and try again.
1087
+ * @property {string} 403 - Forbidden. Check the permissions and try again.
1088
+ * @property {string} 404 - Not Found. Check the URL and try again.
1089
+ * @property {string} 500 - Internal Server Error. Try again later.
1090
+ * @property {string} 502 - Bad Gateway. Try again later.
1091
+ * @property {string} 503 - Service Unavailable. Try again later.
1092
+ */
1093
+ const ErrorMessages = {
1094
+ 401: 'Unauthorized. Check the token and try again.',
1095
+ 403: 'Forbidden. Check the permissions and try again.',
1096
+ 404: 'Not Found. Check the URL and try again.',
1097
+ 500: 'Internal Server Error. Try again later.',
1098
+ 502: 'Bad Gateway. Try again later.',
1099
+ 503: 'Service Unavailable. Try again later.'
1100
+ };
1101
+
1102
+ const DEFAULT_PAGE_CONTENTLETS_CONTENT = `
1103
+ publishDate
1104
+ inode
1105
+ identifier
1106
+ archived
1107
+ urlMap
1108
+ urlMap
1109
+ locked
1110
+ contentType
1111
+ creationDate
1112
+ modDate
1113
+ title
1114
+ baseType
1115
+ working
1116
+ live
1117
+ publishUser {
1118
+ firstName
1119
+ lastName
1120
+ }
1121
+ owner {
1122
+ lastName
1123
+ }
1124
+ conLanguage {
1125
+ language
1126
+ languageCode
1127
+ }
1128
+ modUser {
1129
+ firstName
1130
+ lastName
1131
+ }
1132
+ `;
1133
+ /**
1134
+ * Builds a GraphQL query for retrieving page content from DotCMS.
653
1135
  *
654
- * // Listen to editor changes
655
- * client.editor.on('changes', (payload) => console.log('Changes detected:', payload));
656
- * ```
1136
+ * @param {string} pageQuery - Custom fragment fields to include in the ClientPage fragment
1137
+ * @param {string} additionalQueries - Additional GraphQL queries to include in the main query
1138
+ * @returns {string} Complete GraphQL query string for page content
657
1139
  */
658
- class DotCmsClient {
659
- constructor(config = { dotcmsUrl: '', authToken: '', requestOptions: {}, siteId: '' }) {
660
- _DotCmsClient_config.set(this, void 0);
661
- _DotCmsClient_requestOptions.set(this, void 0);
662
- _DotCmsClient_listeners.set(this, []);
663
- this.page = {
664
- /**
665
- * `page.get` is an asynchronous method of the `DotCmsClient` class that retrieves all the elements of any Page in your dotCMS system in JSON format.
666
- * It takes a `PageApiOptions` object as a parameter and returns a Promise that resolves to the response from the DotCMS API.
667
- *
668
- * The Page API enables you to retrieve all the elements of any Page in your dotCMS system.
669
- * The elements may be retrieved in JSON format.
670
- *
671
- * @link https://www.dotcms.com/docs/latest/page-rest-api-layout-as-a-service-laas
672
- * @async
673
- * @param {PageApiOptions} options - The options for the Page API call.
674
- * @returns {Promise<unknown>} - A Promise that resolves to the response from the DotCMS API.
675
- * @throws {Error} - Throws an error if the options are not valid.
676
- * @example
677
- * ```ts
678
- * const client = new DotCmsClient({ dotcmsUrl: 'https://your.dotcms.com', authToken: 'your-auth-token', siteId: 'your-site-id' });
679
- * client.page.get({ path: '/about-us' }).then(response => console.log(response));
680
- * ```
681
- */
682
- get: async (options) => {
683
- this.validatePageOptions(options);
684
- const queryParamsObj = {};
685
- for (const [key, value] of Object.entries(options)) {
686
- if (value === undefined || key === 'path' || key === 'siteId')
687
- continue;
688
- if (key === 'personaId') {
689
- queryParamsObj['com.dotmarketing.persona.id'] = String(value);
690
- }
691
- else if (key === 'mode' && value) {
692
- queryParamsObj['mode'] = String(value);
693
- }
694
- else {
695
- queryParamsObj[key] = String(value);
696
- }
697
- }
698
- const queryHostId = options.siteId ?? __classPrivateFieldGet(this, _DotCmsClient_config, "f").siteId ?? '';
699
- if (queryHostId) {
700
- queryParamsObj['host_id'] = queryHostId;
701
- }
702
- const queryParams = new URLSearchParams(queryParamsObj).toString();
703
- const formattedPath = options.path.startsWith('/') ? options.path : `/${options.path}`;
704
- const url = `${__classPrivateFieldGet(this, _DotCmsClient_config, "f").dotcmsUrl}/api/v1/page/json${formattedPath}${queryParams ? `?${queryParams}` : ''}`;
705
- const response = await fetch(url, __classPrivateFieldGet(this, _DotCmsClient_requestOptions, "f"));
706
- if (!response.ok) {
707
- const error = {
708
- status: response.status,
709
- message: ErrorMessages[response.status] || response.statusText
710
- };
711
- console.error(error);
712
- throw error;
713
- }
714
- return response.json().then((data) => data.entity);
715
- }
716
- };
717
- this.editor = {
718
- /**
719
- * `editor.on` is an asynchronous method of the `DotCmsClient` class that allows you to react to actions issued by the UVE.
720
- *
721
- * NOTE: This is being used by the development team - This logic is probably varied or moved to another function/object.
722
- * @param {string} action - The name of the action emitted by UVE.
723
- * @param {function} callbackFn - The function to execute when the UVE emits the action.
724
- * @example
725
- * ```ts
726
- * client.editor.on('changes', (payload) => {
727
- * console.log('Changes detected:', payload);
728
- * });
729
- * ```
730
- */
731
- on: (action, callbackFn) => {
732
- if (!isInsideEditor()) {
733
- return;
734
- }
735
- if (action === 'changes') {
736
- const messageCallback = (event) => {
737
- if (event.data.name === NOTIFY_CLIENT.UVE_SET_PAGE_DATA) {
738
- callbackFn(event.data.payload);
739
- }
740
- };
741
- window.addEventListener('message', messageCallback);
742
- __classPrivateFieldGet(this, _DotCmsClient_listeners, "f").push({ event: 'message', callback: messageCallback, action });
743
- }
744
- },
745
- /**
746
- * `editor.off` is a synchronous method of the `DotCmsClient` class that allows you to stop listening and reacting to an action issued by UVE.
747
- *
748
- * NOTE: This is being used by the development team - This logic is probably varied or moved to another function/object.
749
- * @param {string} action - The name of the action to stop listening to.
750
- * @example
751
- * ```ts
752
- * client.editor.off('changes');
753
- * ```
754
- */
755
- off: (action) => {
756
- const listenerIndex = __classPrivateFieldGet(this, _DotCmsClient_listeners, "f").findIndex((listener) => listener.action === action);
757
- if (listenerIndex !== -1) {
758
- const listener = __classPrivateFieldGet(this, _DotCmsClient_listeners, "f")[listenerIndex];
759
- window.removeEventListener(listener.event, listener.callback);
760
- __classPrivateFieldGet(this, _DotCmsClient_listeners, "f").splice(listenerIndex, 1);
761
- }
762
- }
763
- };
764
- this.nav = {
765
- /**
766
- * `nav.get` is an asynchronous method of the `DotCmsClient` class that retrieves information about the dotCMS file and folder tree.
767
- * It takes a `NavApiOptions` object as a parameter (with default values) and returns a Promise that resolves to the response from the DotCMS API.
768
- *
769
- * The navigation REST API enables you to retrieve information about the dotCMS file and folder tree through REST API calls.
770
- * @link https://www.dotcms.com/docs/latest/navigation-rest-api
771
- * @async
772
- * @param {NavApiOptions} options - The options for the Nav API call. Defaults to `{ depth: 0, path: '/', languageId: 1 }`.
773
- * @returns {Promise<unknown>} - A Promise that resolves to the response from the DotCMS API.
774
- * @throws {Error} - Throws an error if the options are not valid.
775
- * @example
776
- * ```ts
777
- * const client = new DotCmsClient({ dotcmsUrl: 'https://your.dotcms.com', authToken: 'your-auth-token', siteId: 'your-site-id' }});
778
- * client.nav.get({ path: '/about-us', depth: 2 }).then(response => console.log(response));
779
- * ```
780
- */
781
- get: async (options = { depth: 0, path: '/', languageId: 1 }) => {
782
- this.validateNavOptions(options);
783
- // Extract the 'path' from the options and prepare the rest as query parameters
784
- const { path, ...queryParamsOptions } = options;
785
- const queryParamsObj = {};
786
- Object.entries(queryParamsOptions).forEach(([key, value]) => {
787
- if (value !== undefined) {
788
- queryParamsObj[key] = String(value);
789
- }
790
- });
791
- const queryParams = new URLSearchParams(queryParamsObj).toString();
792
- // Format the URL correctly depending on the 'path' value
793
- const formattedPath = path === '/' ? '/' : `/${path}`;
794
- const url = `${__classPrivateFieldGet(this, _DotCmsClient_config, "f").dotcmsUrl}/api/v1/nav${formattedPath}${queryParams ? `?${queryParams}` : ''}`;
795
- const response = await fetch(url, __classPrivateFieldGet(this, _DotCmsClient_requestOptions, "f"));
796
- return response.json();
1140
+ const buildPageQuery = ({ page, fragments, additionalQueries }) => {
1141
+ if (!page) {
1142
+ consola.warn("[DotCMS Client]: No page query was found, so we're loading all content using _map. This might slow things down. For better performance, we recommend adding a specific query in the page attribute.");
1143
+ }
1144
+ return `
1145
+ fragment DotCMSPage on DotPage {
1146
+ publishDate
1147
+ type
1148
+ httpsRequired
1149
+ inode
1150
+ path
1151
+ identifier
1152
+ hasTitleImage
1153
+ sortOrder
1154
+ extension
1155
+ canRead
1156
+ pageURI
1157
+ canEdit
1158
+ archived
1159
+ friendlyName
1160
+ workingInode
1161
+ url
1162
+ pageURI
1163
+ hasLiveVersion
1164
+ deleted
1165
+ pageUrl
1166
+ shortyWorking
1167
+ mimeType
1168
+ locked
1169
+ stInode
1170
+ contentType
1171
+ creationDate
1172
+ liveInode
1173
+ name
1174
+ shortyLive
1175
+ modDate
1176
+ title
1177
+ baseType
1178
+ working
1179
+ canLock
1180
+ live
1181
+ isContentlet
1182
+ statusIcons
1183
+ canEdit
1184
+ canLock
1185
+ canRead
1186
+ canEdit
1187
+ canLock
1188
+ canRead
1189
+ runningExperimentId
1190
+ urlContentMap {
1191
+ _map
1192
+ }
1193
+ host {
1194
+ identifier
1195
+ hostName
1196
+ googleMap
1197
+ archived
1198
+ contentType
1199
+ }
1200
+ vanityUrl {
1201
+ action
1202
+ forwardTo
1203
+ uri
1204
+ }
1205
+ conLanguage {
1206
+ id
1207
+ language
1208
+ languageCode
1209
+ }
1210
+ template {
1211
+ drawed
1212
+ anonymous
1213
+ theme
1214
+ identifier
1215
+ }
1216
+ containers {
1217
+ path
1218
+ identifier
1219
+ maxContentlets
1220
+ containerStructures {
1221
+ id
1222
+ code
1223
+ structureId
1224
+ containerId
1225
+ contentTypeVar
1226
+ containerInode
1227
+ }
1228
+ containerContentlets {
1229
+ uuid
1230
+ contentlets {
1231
+ ${page ? DEFAULT_PAGE_CONTENTLETS_CONTENT : '_map'}
1232
+ }
1233
+ }
1234
+ }
1235
+ layout {
1236
+ header
1237
+ footer
1238
+ body {
1239
+ rows {
1240
+ columns {
1241
+ leftOffset
1242
+ styleClass
1243
+ width
1244
+ left
1245
+ containers {
1246
+ identifier
1247
+ uuid
797
1248
  }
798
- };
799
- if (!config.dotcmsUrl) {
800
- throw new Error("Invalid configuration - 'dotcmsUrl' is required");
1249
+ }
801
1250
  }
802
- this.dotcmsUrl = getHostURL(config.dotcmsUrl)?.origin;
803
- if (!this.dotcmsUrl) {
804
- throw new Error("Invalid configuration - 'dotcmsUrl' must be a valid URL");
1251
+ }
1252
+ }
1253
+ viewAs {
1254
+ visitor {
1255
+ persona {
1256
+ modDate
1257
+ inode
1258
+ name
1259
+ identifier
1260
+ keyTag
1261
+ photo {
1262
+ versionPath
1263
+ }
805
1264
  }
806
- if (!config.authToken) {
807
- throw new Error("Invalid configuration - 'authToken' is required");
1265
+ }
1266
+ persona {
1267
+ modDate
1268
+ inode
1269
+ name
1270
+ identifier
1271
+ keyTag
1272
+ photo {
1273
+ versionPath
808
1274
  }
809
- __classPrivateFieldSet(this, _DotCmsClient_config, {
810
- ...config,
811
- dotcmsUrl: this.dotcmsUrl
812
- }, "f");
813
- __classPrivateFieldSet(this, _DotCmsClient_requestOptions, {
814
- ...__classPrivateFieldGet(this, _DotCmsClient_config, "f").requestOptions,
815
- headers: {
816
- Authorization: `Bearer ${__classPrivateFieldGet(this, _DotCmsClient_config, "f").authToken}`,
817
- ...__classPrivateFieldGet(this, _DotCmsClient_config, "f").requestOptions?.headers
818
- }
819
- }, "f");
820
- this.content = new Content(__classPrivateFieldGet(this, _DotCmsClient_requestOptions, "f"), __classPrivateFieldGet(this, _DotCmsClient_config, "f").dotcmsUrl);
1275
+ }
1276
+ language {
1277
+ id
1278
+ languageCode
1279
+ countryCode
1280
+ language
1281
+ country
1282
+ }
1283
+ }
1284
+ }
1285
+
1286
+ ${page ? ` fragment ClientPage on DotPage { ${page} } ` : ''}
1287
+
1288
+ ${fragments ? fragments.join('\n\n') : ''}
1289
+
1290
+ query PageContent($url: String!, $languageId: String, $mode: String, $personaId: String, $fireRules: Boolean, $publishDate: String, $siteId: String, $variantName: String) {
1291
+ page: page(url: $url, languageId: $languageId, pageMode: $mode, persona: $personaId, fireRules: $fireRules, publishDate: $publishDate, site: $siteId, variantName: $variantName) {
1292
+ ...DotCMSPage
1293
+ ${page ? '...ClientPage' : ''}
1294
+ }
1295
+
1296
+ ${additionalQueries}
1297
+ }
1298
+ `;
1299
+ };
1300
+ /**
1301
+ * Converts a record of query strings into a single GraphQL query string.
1302
+ *
1303
+ * @param {Record<string, string>} queryData - Object containing named query strings
1304
+ * @returns {string} Combined query string or empty string if no queryData provided
1305
+ */
1306
+ function buildQuery(queryData) {
1307
+ if (!queryData)
1308
+ return '';
1309
+ return Object.entries(queryData)
1310
+ .map(([key, query]) => `${key}: ${query}`)
1311
+ .join(' ');
1312
+ }
1313
+ /**
1314
+ * Filters response data to include only specified keys.
1315
+ *
1316
+ * @param {Record<string, string>} responseData - Original response data object
1317
+ * @param {string[]} keys - Array of keys to extract from the response data
1318
+ * @returns {Record<string, string>} New object containing only the specified keys
1319
+ */
1320
+ function mapResponseData(responseData, keys) {
1321
+ return keys.reduce((accumulator, key) => {
1322
+ if (responseData[key] !== undefined) {
1323
+ accumulator[key] = responseData[key];
1324
+ }
1325
+ return accumulator;
1326
+ }, {});
1327
+ }
1328
+ /**
1329
+ * Executes a GraphQL query against the DotCMS API.
1330
+ *
1331
+ * @param {Object} options - Options for the fetch request
1332
+ * @param {string} options.body - GraphQL query string
1333
+ * @param {Record<string, string>} options.headers - HTTP headers for the request
1334
+ * @returns {Promise<any>} Parsed JSON response from the GraphQL API
1335
+ * @throws {Error} If the HTTP response is not successful
1336
+ */
1337
+ async function fetchGraphQL({ baseURL, body, headers }) {
1338
+ const url = new URL(baseURL);
1339
+ url.pathname = '/api/v1/graphql';
1340
+ const response = await fetch(url.toString(), {
1341
+ method: 'POST',
1342
+ body,
1343
+ headers
1344
+ });
1345
+ if (!response.ok) {
1346
+ const error = {
1347
+ status: response.status,
1348
+ message: ErrorMessages[response.status] || response.statusText
1349
+ };
1350
+ throw error;
821
1351
  }
1352
+ return await response.json();
1353
+ }
1354
+
1355
+ /**
1356
+ * Client for interacting with the DotCMS Page API.
1357
+ * Provides methods to retrieve and manipulate pages.
1358
+ */
1359
+ class PageClient {
822
1360
  /**
823
- * Initializes the DotCmsClient instance with the provided configuration.
824
- * If an instance already exists, it returns the existing instance.
1361
+ * Creates a new PageClient instance.
825
1362
  *
826
- * @param {ClientConfig} config - The configuration object for the DotCMS client.
827
- * @returns {DotCmsClient} - The initialized DotCmsClient instance.
1363
+ * @param {DotCMSClientConfig} config - Configuration options for the DotCMS client
1364
+ * @param {RequestOptions} requestOptions - Options for fetch requests including authorization headers
828
1365
  * @example
829
- * ```ts
830
- * const client = DotCmsClient.init({ dotcmsUrl: 'https://demo.dotcms.com', authToken: 'your-auth-token' });
1366
+ * ```typescript
1367
+ * const pageClient = new PageClient(
1368
+ * {
1369
+ * dotcmsUrl: 'https://demo.dotcms.com',
1370
+ * authToken: 'your-auth-token',
1371
+ * siteId: 'demo.dotcms.com'
1372
+ * },
1373
+ * {
1374
+ * headers: {
1375
+ * Authorization: 'Bearer your-auth-token'
1376
+ * }
1377
+ * }
1378
+ * );
831
1379
  * ```
832
1380
  */
833
- static init(config) {
834
- if (this.instance) {
835
- console.warn('DotCmsClient has already been initialized. Please use the instance to interact with the DotCMS API.');
836
- }
837
- return this.instance ?? (this.instance = new DotCmsClient(config));
1381
+ constructor(config, requestOptions) {
1382
+ this.requestOptions = requestOptions;
1383
+ this.siteId = config.siteId || '';
1384
+ this.dotcmsUrl = config.dotcmsUrl;
838
1385
  }
839
1386
  /**
840
- * Retrieves the DotCMS URL from the instance configuration.
1387
+ * Retrieves a page from DotCMS using GraphQL.
841
1388
  *
842
- * @returns {string} - The DotCMS URL.
1389
+ * @param {string} url - The URL of the page to retrieve
1390
+ * @param {DotCMSPageRequestParams} [options] - Options for the request
1391
+ * @template T - The type of the page and content, defaults to DotCMSBasicPage and Record<string, unknown> | unknown
1392
+ * @returns {Promise<DotCMSComposedPageResponse<T>>} A Promise that resolves to the page data
1393
+ *
1394
+ * @example Using GraphQL
1395
+ * ```typescript
1396
+ * const page = await pageClient.get<{ page: MyPageWithBanners; content: { blogPosts: { blogTitle: string } } }>(
1397
+ * '/index',
1398
+ * {
1399
+ * languageId: '1',
1400
+ * mode: 'LIVE',
1401
+ * graphql: {
1402
+ * page: `
1403
+ * containers {
1404
+ * containerContentlets {
1405
+ * contentlets {
1406
+ * ... on Banner {
1407
+ * ...bannerFragment
1408
+ * }
1409
+ * }
1410
+ * }
1411
+ * `,
1412
+ * content: {
1413
+ * blogPosts: `
1414
+ * BlogCollection(limit: 3) {
1415
+ * ...blogFragment
1416
+ * }
1417
+ * `,
1418
+ * },
1419
+ * fragments: [
1420
+ * `
1421
+ * fragment bannerFragment on Banner {
1422
+ * caption
1423
+ * }
1424
+ * `,
1425
+ * `
1426
+ * fragment blogFragment on Blog {
1427
+ * title
1428
+ * urlTitle
1429
+ * }
1430
+ * `
1431
+ * ]
1432
+ * }
1433
+ * });
1434
+ * ```
843
1435
  */
844
- static get dotcmsUrl() {
845
- return (this.instance && __classPrivateFieldGet(this.instance, _DotCmsClient_config, "f").dotcmsUrl) || '';
1436
+ async get(url, options) {
1437
+ const { languageId = '1', mode = 'LIVE', siteId = this.siteId, fireRules = false, personaId, publishDate, variantName, graphql = {} } = options || {};
1438
+ const { page, content = {}, variables, fragments } = graphql;
1439
+ const contentQuery = buildQuery(content);
1440
+ const completeQuery = buildPageQuery({
1441
+ page,
1442
+ fragments,
1443
+ additionalQueries: contentQuery
1444
+ });
1445
+ const requestVariables = {
1446
+ // The url is expected to have a leading slash to comply on VanityURL Matching, some frameworks like Angular will not add the leading slash
1447
+ url: url.startsWith('/') ? url : `/${url}`,
1448
+ mode,
1449
+ languageId,
1450
+ personaId,
1451
+ fireRules,
1452
+ publishDate,
1453
+ siteId,
1454
+ variantName,
1455
+ ...variables
1456
+ };
1457
+ const requestHeaders = this.requestOptions.headers;
1458
+ const requestBody = JSON.stringify({ query: completeQuery, variables: requestVariables });
1459
+ try {
1460
+ const { data, errors } = await fetchGraphQL({
1461
+ baseURL: this.dotcmsUrl,
1462
+ body: requestBody,
1463
+ headers: requestHeaders
1464
+ });
1465
+ if (errors) {
1466
+ errors.forEach((error) => {
1467
+ consola$1.error('[DotCMS GraphQL Error]: ', error.message);
1468
+ });
1469
+ }
1470
+ const pageResponse = graphqlToPageEntity(data);
1471
+ if (!pageResponse) {
1472
+ throw new Error('No page data found');
1473
+ }
1474
+ const contentResponse = mapResponseData(data, Object.keys(content));
1475
+ return {
1476
+ pageAsset: pageResponse,
1477
+ content: contentResponse,
1478
+ graphql: {
1479
+ query: completeQuery,
1480
+ variables: requestVariables
1481
+ }
1482
+ };
1483
+ }
1484
+ catch (error) {
1485
+ const errorMessage = {
1486
+ error,
1487
+ message: 'Failed to retrieve page data',
1488
+ graphql: {
1489
+ query: completeQuery,
1490
+ variables: requestVariables
1491
+ }
1492
+ };
1493
+ throw errorMessage;
1494
+ }
846
1495
  }
1496
+ }
1497
+
1498
+ /**
1499
+ * Parses a string into a URL object.
1500
+ *
1501
+ * @param url - The URL string to parse
1502
+ * @returns A URL object if parsing is successful, undefined otherwise
1503
+ */
1504
+ function parseURL(url) {
1505
+ try {
1506
+ return new URL(url);
1507
+ }
1508
+ catch {
1509
+ consola.error('[DotCMS Client]: Invalid URL:', url);
1510
+ return undefined;
1511
+ }
1512
+ }
1513
+ /**
1514
+ * Default configuration for the DotCMS client.
1515
+ */
1516
+ const defaultConfig = {
1517
+ dotcmsUrl: '',
1518
+ authToken: '',
1519
+ requestOptions: {}
1520
+ };
1521
+ /**
1522
+ * Client for interacting with the DotCMS REST API.
1523
+ * Provides access to content, page, and navigation functionality.
1524
+ */
1525
+ class DotCMSClient {
847
1526
  /**
848
- * Throws an error if the path is not valid.
1527
+ * Creates a new DotCMS client instance.
849
1528
  *
850
- * @returns {string} - The authentication token.
1529
+ * @param config - Configuration options for the client
1530
+ * @throws Warning if dotcmsUrl is invalid or authToken is missing
851
1531
  */
852
- validatePageOptions(options) {
853
- if (!options.path) {
854
- throw new Error("The 'path' parameter is required for the Page API");
855
- }
1532
+ constructor(config = defaultConfig) {
1533
+ this.config = config;
1534
+ this.requestOptions = this.createAuthenticatedRequestOptions(this.config);
1535
+ // Initialize clients
1536
+ this.page = new PageClient(this.config, this.requestOptions);
1537
+ this.nav = new NavigationClient(this.config, this.requestOptions);
1538
+ this.content = new Content(this.requestOptions, this.config.dotcmsUrl);
856
1539
  }
857
1540
  /**
858
- * Throws an error if the path is not valid.
1541
+ * Creates request options with authentication headers.
859
1542
  *
860
- * @returns {string} - The authentication token.
1543
+ * @param config - The client configuration
1544
+ * @returns Request options with authorization headers
861
1545
  */
862
- validateNavOptions(options) {
863
- if (!options.path) {
864
- throw new Error("The 'path' parameter is required for the Nav API");
865
- }
1546
+ createAuthenticatedRequestOptions(config) {
1547
+ return {
1548
+ ...config.requestOptions,
1549
+ headers: {
1550
+ ...config.requestOptions?.headers,
1551
+ Authorization: `Bearer ${config.authToken}`
1552
+ }
1553
+ };
866
1554
  }
867
1555
  }
868
- _DotCmsClient_config = new WeakMap(), _DotCmsClient_requestOptions = new WeakMap(), _DotCmsClient_listeners = new WeakMap();
869
-
870
1556
  /**
871
- * Generates the page request parameters to be used in the API call.
1557
+ * Creates and returns a new DotCMS client instance.
872
1558
  *
873
- * @param {PageRequestParamsProps} PageRequestParamsProps - The properties for the page request.
874
- * @returns {PageApiOptions} The options for the page API.
1559
+ * @param config - Configuration options for the client
1560
+ * @returns A configured DotCMS client instance
875
1561
  * @example
876
- * ```ts
877
- * const pageApiOptions = getPageRequestParams({ path: '/api/v1/page', params: queryParams });
1562
+ * ```typescript
1563
+ * const client = dotCMSCreateClient({
1564
+ * dotcmsUrl: 'https://demo.dotcms.com',
1565
+ * authToken: 'your-auth-token'
1566
+ * });
1567
+ *
1568
+ * // Use the client to fetch content
1569
+ * const pages = await client.page.get('/about-us');
878
1570
  * ```
879
1571
  */
880
- const getPageRequestParams = ({ path = '', params = {} }) => {
881
- const copiedParams = params instanceof URLSearchParams ? Object.fromEntries(params.entries()) : { ...params };
882
- const finalParams = {};
883
- const dotMarketingPersonaId = copiedParams['com.dotmarketing.persona.id'] || '';
884
- finalParams['mode'] = copiedParams['mode'] || 'LIVE';
885
- if (copiedParams['language_id']) {
886
- finalParams['language_id'] = copiedParams['language_id'];
887
- }
888
- if (copiedParams['variantName']) {
889
- finalParams['variantName'] = copiedParams['variantName'];
890
- }
891
- if (copiedParams['personaId'] || dotMarketingPersonaId) {
892
- finalParams['personaId'] = copiedParams['personaId'] || dotMarketingPersonaId;
893
- }
894
- if (copiedParams['publishDate']) {
895
- finalParams['publishDate'] = copiedParams['publishDate'];
896
- }
897
- return {
898
- path,
899
- ...finalParams
1572
+ const createDotCMSClient = (clientConfig) => {
1573
+ const { dotcmsUrl, authToken } = clientConfig || {};
1574
+ const instanceUrl = parseURL(dotcmsUrl)?.origin;
1575
+ if (!instanceUrl) {
1576
+ throw new TypeError("Invalid configuration - 'dotcmsUrl' must be a valid URL");
1577
+ }
1578
+ if (!authToken) {
1579
+ throw new TypeError("Invalid configuration - 'authToken' is required");
1580
+ }
1581
+ const config = {
1582
+ ...clientConfig,
1583
+ authToken,
1584
+ dotcmsUrl: instanceUrl
900
1585
  };
1586
+ return new DotCMSClient(config);
901
1587
  };
902
1588
 
903
- export { CLIENT_ACTIONS, DotCmsClient, NOTIFY_CLIENT, destroyEditor, editContentlet, getPageRequestParams, initEditor, initInlineEditing, isInsideEditor, postMessageToEditor, reorderMenu, updateNavigation };
1589
+ export { createDotCMSClient };