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