@dotcms/client 1.2.0 → 1.2.1-next.10

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.
package/index.cjs.js CHANGED
@@ -147,6 +147,366 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
147
147
  return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
148
148
  };
149
149
 
150
+ /**
151
+ * Utility functions for AI search parameter mapping and processing
152
+ */
153
+ /**
154
+ * Appends mapped parameters to URLSearchParams based on a mapping configuration.
155
+ * Only includes parameters that have defined values.
156
+ *
157
+ * @param searchParams - The URLSearchParams object to append to
158
+ * @param sourceObject - The source object containing values
159
+ * @param mapping - Array of [targetKey, sourceKey] pairs for parameter mapping, or [key] to use same key
160
+ * @example
161
+ * ```typescript
162
+ * const params = new URLSearchParams();
163
+ * const query = { limit: 10, offset: 0, siteId: 'default', indexName: 'content' };
164
+ * const mapping = [
165
+ * ['searchLimit', 'limit'], // Maps limit -> searchLimit
166
+ * ['searchOffset', 'offset'], // Maps offset -> searchOffset
167
+ * ['site', 'siteId'], // Maps siteId -> site
168
+ * ['indexName'] // Uses indexName -> indexName (same key)
169
+ * ];
170
+ * appendMappedParams(params, query, mapping);
171
+ * // Results in: searchLimit=10&searchOffset=0&site=default&indexName=content
172
+ * ```
173
+ */
174
+ function appendMappedParams(searchParams, sourceObject, mapping) {
175
+ mapping.forEach((item) => {
176
+ const targetKey = item[0];
177
+ const sourceKey = item[1] ?? item[0];
178
+ const value = sourceObject[sourceKey];
179
+ if (value !== undefined) {
180
+ searchParams.append(targetKey, String(value));
181
+ }
182
+ });
183
+ }
184
+
185
+ var _BaseApiClient_requestOptions, _BaseApiClient_config, _BaseApiClient_httpClient;
186
+ /**
187
+ * Base class for all DotCMS API clients.
188
+ * Provides common constructor parameters and properties that all API clients need.
189
+ * Uses JavaScript private fields (#) for true runtime privacy.
190
+ */
191
+ class BaseApiClient {
192
+ /**
193
+ * Creates a new API client instance.
194
+ *
195
+ * @param {DotCMSClientConfig} config - Configuration options for the DotCMS client
196
+ * @param {DotRequestOptions} requestOptions - Options for fetch requests including authorization headers
197
+ * @param {DotHttpClient} httpClient - HTTP client for making requests
198
+ */
199
+ constructor(config, requestOptions = {}, httpClient) {
200
+ /**
201
+ * Request options including authorization headers.
202
+ * @private
203
+ */
204
+ _BaseApiClient_requestOptions.set(this, void 0);
205
+ /**
206
+ * DotCMS client configuration.
207
+ * @private
208
+ */
209
+ _BaseApiClient_config.set(this, void 0);
210
+ /**
211
+ * HTTP client for making requests.
212
+ * @private
213
+ */
214
+ _BaseApiClient_httpClient.set(this, void 0);
215
+ __classPrivateFieldSet(this, _BaseApiClient_config, {
216
+ siteId: '',
217
+ ...config
218
+ }, "f");
219
+ __classPrivateFieldSet(this, _BaseApiClient_requestOptions, {
220
+ ...requestOptions
221
+ }, "f");
222
+ __classPrivateFieldSet(this, _BaseApiClient_httpClient, httpClient, "f");
223
+ }
224
+ /**
225
+ * Gets the request options including authorization headers.
226
+ * @protected
227
+ */
228
+ get requestOptions() {
229
+ return __classPrivateFieldGet(this, _BaseApiClient_requestOptions, "f");
230
+ }
231
+ /**
232
+ * Gets the DotCMS client configuration.
233
+ * @protected
234
+ */
235
+ get config() {
236
+ return __classPrivateFieldGet(this, _BaseApiClient_config, "f");
237
+ }
238
+ /**
239
+ * Gets the HTTP client for making requests.
240
+ * @protected
241
+ */
242
+ get httpClient() {
243
+ return __classPrivateFieldGet(this, _BaseApiClient_httpClient, "f");
244
+ }
245
+ /**
246
+ * Gets the DotCMS URL from config.
247
+ * @protected
248
+ */
249
+ get dotcmsUrl() {
250
+ return __classPrivateFieldGet(this, _BaseApiClient_config, "f").dotcmsUrl;
251
+ }
252
+ /**
253
+ * Gets the site ID from config.
254
+ * @protected
255
+ */
256
+ get siteId() {
257
+ return __classPrivateFieldGet(this, _BaseApiClient_config, "f").siteId || '';
258
+ }
259
+ }
260
+ _BaseApiClient_requestOptions = new WeakMap(), _BaseApiClient_config = new WeakMap(), _BaseApiClient_httpClient = new WeakMap();
261
+
262
+ /**
263
+ * Default values for AI configuration
264
+ */
265
+ const DEFAULT_AI_CONFIG = {
266
+ threshold: 0.5,
267
+ distanceFunction: types.DISTANCE_FUNCTIONS.cosine,
268
+ responseLength: 1024
269
+ };
270
+ /**
271
+ * Default values for search query
272
+ */
273
+ const DEFAULT_QUERY = {
274
+ limit: 1000,
275
+ offset: 0,
276
+ indexName: 'default'
277
+ };
278
+
279
+ var _AISearch_params, _AISearch_prompt, _AISearch_indexName;
280
+ /**
281
+ * Class for executing AI searches.
282
+ *
283
+ * @template T - The type of the contentlet.
284
+ * @param config - The configuration for the client.
285
+ * @param requestOptions - The request options for the client.
286
+ * @param httpClient - The HTTP client for the client.
287
+ * @param params - The parameters for the search.
288
+ * @param prompt - The prompt for the search.
289
+ */
290
+ class AISearch extends BaseApiClient {
291
+ constructor(config, requestOptions, httpClient, prompt, indexName, params = {}) {
292
+ super(config, requestOptions, httpClient);
293
+ _AISearch_params.set(this, void 0);
294
+ _AISearch_prompt.set(this, void 0);
295
+ _AISearch_indexName.set(this, void 0);
296
+ __classPrivateFieldSet(this, _AISearch_params, params, "f");
297
+ __classPrivateFieldSet(this, _AISearch_prompt, prompt, "f");
298
+ __classPrivateFieldSet(this, _AISearch_indexName, indexName, "f");
299
+ }
300
+ /**
301
+ * Executes the AI search and returns a promise with the search results.
302
+ *
303
+ * @param onfulfilled - Callback function to handle the search results.
304
+ * @param onrejected - Callback function to handle the search error.
305
+ * @returns Promise with the search results or the error.
306
+ * @example
307
+ * ```typescript
308
+ * const results = await client.ai.search('machine learning articles', 'content_index', {
309
+ * query: {
310
+ * limit: 20,
311
+ * contentType: 'BlogPost',
312
+ * languageId: '1' // or 1
313
+ * },
314
+ * config: {
315
+ * threshold: 0.7
316
+ * }
317
+ * });
318
+ * ```
319
+ * @example
320
+ * ```typescript
321
+ * client.ai.search('machine learning articles', 'content_index', {
322
+ * query: {
323
+ * limit: 20,
324
+ * contentType: 'BlogPost',
325
+ * languageId: '1' // or 1
326
+ * },
327
+ * config: {
328
+ * threshold: 0.7
329
+ * }
330
+ * }).then((results) => {
331
+ * console.log(results);
332
+ * }).catch((error) => {
333
+ * console.error(error);
334
+ * });
335
+ * ```
336
+ */
337
+ then(onfulfilled, onrejected) {
338
+ return this.fetch().then((data) => {
339
+ const response = {
340
+ ...data,
341
+ results: data.dotCMSResults
342
+ };
343
+ if (typeof onfulfilled === 'function') {
344
+ const result = onfulfilled(response);
345
+ // Ensure we always return a value, fallback to data if callback returns undefined
346
+ return result ?? response;
347
+ }
348
+ return response;
349
+ }, (error) => {
350
+ // Wrap error in DotCMSContentError
351
+ let contentError;
352
+ if (error instanceof types.DotHttpError) {
353
+ contentError = new types.DotErrorAISearch({
354
+ message: `AI Search failed (fetch): ${error.message}`,
355
+ httpError: error,
356
+ params: __classPrivateFieldGet(this, _AISearch_params, "f"),
357
+ prompt: __classPrivateFieldGet(this, _AISearch_prompt, "f"),
358
+ indexName: __classPrivateFieldGet(this, _AISearch_indexName, "f")
359
+ });
360
+ }
361
+ else {
362
+ const errorMessage = error instanceof Error ? error.message : 'Unknown error';
363
+ contentError = new types.DotErrorAISearch({
364
+ message: `AI Search failed (fetch): ${errorMessage}`,
365
+ httpError: undefined,
366
+ params: __classPrivateFieldGet(this, _AISearch_params, "f"),
367
+ prompt: __classPrivateFieldGet(this, _AISearch_prompt, "f"),
368
+ indexName: __classPrivateFieldGet(this, _AISearch_indexName, "f")
369
+ });
370
+ }
371
+ if (typeof onrejected === 'function') {
372
+ const result = onrejected(contentError);
373
+ // Ensure we always return a value, fallback to original error if callback returns undefined
374
+ return result ?? contentError;
375
+ }
376
+ // Throw the wrapped error to trigger .catch()
377
+ throw contentError;
378
+ });
379
+ }
380
+ fetch() {
381
+ const searchParams = this.buildSearchParams(__classPrivateFieldGet(this, _AISearch_prompt, "f"), __classPrivateFieldGet(this, _AISearch_params, "f"));
382
+ const url = new URL('/api/v1/ai/search', this.dotcmsUrl);
383
+ url.search = searchParams.toString();
384
+ return this.httpClient.request(url.toString(), {
385
+ ...this.requestOptions,
386
+ headers: {
387
+ ...this.requestOptions.headers
388
+ },
389
+ method: 'GET'
390
+ });
391
+ }
392
+ /**
393
+ * Builds URLSearchParams from the SDK interface, mapping to backend parameter names.
394
+ * Only includes parameters that have values.
395
+ *
396
+ * @param params - Search parameters with SDK naming
397
+ * @returns URLSearchParams with backend parameter names
398
+ * @private
399
+ */
400
+ buildSearchParams(prompt, params = {}) {
401
+ const searchParams = new URLSearchParams();
402
+ const { query = {}, config = {} } = params;
403
+ const combinedQuery = {
404
+ ...DEFAULT_QUERY,
405
+ siteId: this.siteId,
406
+ ...query
407
+ };
408
+ const combinedConfig = {
409
+ ...DEFAULT_AI_CONFIG,
410
+ ...config
411
+ };
412
+ const entriesQueryParameters = [
413
+ ['searchLimit', 'limit'],
414
+ ['searchOffset', 'offset'],
415
+ ['site', 'siteId'],
416
+ ['language', 'languageId'],
417
+ ['contentType']
418
+ ];
419
+ // Map SDK query parameters to backend parameter names
420
+ appendMappedParams(searchParams, combinedQuery, entriesQueryParameters);
421
+ // Map config parameters using the same key names
422
+ appendMappedParams(searchParams, combinedConfig, Object.keys(combinedConfig).map((key) => [key]));
423
+ // Add search-specific parameters
424
+ searchParams.append('indexName', __classPrivateFieldGet(this, _AISearch_indexName, "f"));
425
+ searchParams.append('query', prompt);
426
+ return searchParams;
427
+ }
428
+ }
429
+ _AISearch_params = new WeakMap(), _AISearch_prompt = new WeakMap(), _AISearch_indexName = new WeakMap();
430
+
431
+ /**
432
+ * Client for interacting with the DotCMS AI API.
433
+ * Provides methods to interact with AI features.
434
+ * @experimental This client is experimental and may be subject to change.
435
+ */
436
+ class AIClient extends BaseApiClient {
437
+ /**
438
+ * Creates a new AIClient instance.
439
+ *
440
+ * @param {DotCMSClientConfig} config - Configuration options for the DotCMS client
441
+ * @param {DotRequestOptions} requestOptions - Options for fetch requests including authorization headers
442
+ * @param {DotHttpClient} httpClient - HTTP client for making requests
443
+ * @example
444
+ * ```typescript
445
+ * const aiClient = new AIClient(
446
+ * {
447
+ * dotcmsUrl: 'https://demo.dotcms.com',
448
+ * authToken: 'your-auth-token',
449
+ * siteId: 'demo.dotcms.com'
450
+ * },
451
+ * {
452
+ * headers: {
453
+ * Authorization: 'Bearer your-auth-token'
454
+ * }
455
+ * },
456
+ * httpClient
457
+ * );
458
+ * ```
459
+ */
460
+ constructor(config, requestOptions, httpClient) {
461
+ super(config, requestOptions, httpClient);
462
+ }
463
+ /**
464
+ * Performs an AI-powered search.
465
+ *
466
+ * @param params - Search parameters with query and AI configuration
467
+ * @returns Promise with search results
468
+ * @experimental This method is experimental and may be subject to change.
469
+ * @template T - The type of the contentlet.
470
+ * @param prompt - The prompt for the search.
471
+ * @param indexName - The name of the index you want to search in.
472
+ * @param params - Search parameters with query and AI configuration.
473
+ * @example
474
+ * @example
475
+ * ```typescript
476
+ * const response = await client.ai.search('machine learning articles', 'content_index', {
477
+ * query: {
478
+ * limit: 20,
479
+ * contentType: 'BlogPost',
480
+ * languageId: "1" // or 1
481
+ * },
482
+ * config: {
483
+ * threshold: 0.7
484
+ * }
485
+ * });
486
+ * ```
487
+ * @example
488
+ * ```typescript
489
+ * client.ai.search('machine learning articles', 'content_index', {
490
+ * query: {
491
+ * limit: 20,
492
+ * contentType: 'BlogPost',
493
+ * languageId: "1" // or 1
494
+ * },
495
+ * config: {
496
+ * threshold: 0.7,
497
+ * distanceFunction: DISTANCE_FUNCTIONS.cosine
498
+ * }
499
+ * }).then((response) => {
500
+ * console.log(response.results);
501
+ * }).catch((error) => {
502
+ * console.error(error);
503
+ * });
504
+ */
505
+ search(prompt, indexName, params = {}) {
506
+ return new AISearch(this.config, this.requestOptions, this.httpClient, prompt, indexName, params);
507
+ }
508
+ }
509
+
150
510
  /**
151
511
  * Default variant identifier used in the application.
152
512
  */
@@ -186,7 +546,9 @@ const CONTENT_API_URL = '/api/content/_search';
186
546
  * @returns {string} The sanitized query string.
187
547
  */
188
548
  function sanitizeQueryForContentType(query, contentType) {
189
- return query.replace(/\+([^+:]*?):/g, (original, field) => {
549
+ // Match field names that start with letter/underscore, followed by alphanumeric/underscore/dot
550
+ // This excludes Lucene grouping operators like +(...)
551
+ return query.replace(/\+([a-zA-Z_][a-zA-Z0-9_.]*):/g, (original, field) => {
190
552
  return !CONTENT_TYPE_MAIN_FIELDS.includes(field) // Fields that are not content type fields
191
553
  ? `+${contentType}.${field}:` // Should have this format: +contentTypeVar.field:
192
554
  : original; // Return the field if it is a content type field
@@ -746,7 +1108,7 @@ class QueryBuilder {
746
1108
  }
747
1109
  _QueryBuilder_query = new WeakMap();
748
1110
 
749
- var _CollectionBuilder_page, _CollectionBuilder_limit, _CollectionBuilder_depth, _CollectionBuilder_render, _CollectionBuilder_sortBy, _CollectionBuilder_contentType, _CollectionBuilder_defaultQuery, _CollectionBuilder_query, _CollectionBuilder_rawQuery, _CollectionBuilder_languageId, _CollectionBuilder_draft, _CollectionBuilder_requestOptions, _CollectionBuilder_httpClient, _CollectionBuilder_config;
1111
+ var _CollectionBuilder_page, _CollectionBuilder_limit, _CollectionBuilder_depth, _CollectionBuilder_render, _CollectionBuilder_sortBy, _CollectionBuilder_contentType, _CollectionBuilder_defaultQuery, _CollectionBuilder_query, _CollectionBuilder_rawQuery, _CollectionBuilder_languageId, _CollectionBuilder_draft;
750
1112
  /**
751
1113
  * Creates a Builder to filter and fetch content from the content API for a specific content type.
752
1114
  *
@@ -754,7 +1116,7 @@ var _CollectionBuilder_page, _CollectionBuilder_limit, _CollectionBuilder_depth,
754
1116
  * @class CollectionBuilder
755
1117
  * @template T Represents the type of the content type to fetch. Defaults to unknown.
756
1118
  */
757
- class CollectionBuilder {
1119
+ class CollectionBuilder extends BaseApiClient {
758
1120
  /**
759
1121
  * Creates an instance of CollectionBuilder.
760
1122
  * @param {ClientOptions} requestOptions Options for the client request.
@@ -764,6 +1126,7 @@ class CollectionBuilder {
764
1126
  * @memberof CollectionBuilder
765
1127
  */
766
1128
  constructor(requestOptions, config, contentType, httpClient) {
1129
+ super(config, requestOptions, httpClient);
767
1130
  _CollectionBuilder_page.set(this, 1);
768
1131
  _CollectionBuilder_limit.set(this, 10);
769
1132
  _CollectionBuilder_depth.set(this, 0);
@@ -775,14 +1138,7 @@ class CollectionBuilder {
775
1138
  _CollectionBuilder_rawQuery.set(this, void 0);
776
1139
  _CollectionBuilder_languageId.set(this, 1);
777
1140
  _CollectionBuilder_draft.set(this, false);
778
- _CollectionBuilder_requestOptions.set(this, void 0);
779
- _CollectionBuilder_httpClient.set(this, void 0);
780
- _CollectionBuilder_config.set(this, void 0);
781
- __classPrivateFieldSet(this, _CollectionBuilder_requestOptions, requestOptions, "f");
782
- __classPrivateFieldSet(this, _CollectionBuilder_config, config, "f");
783
1141
  __classPrivateFieldSet(this, _CollectionBuilder_contentType, contentType, "f");
784
- __classPrivateFieldSet(this, _CollectionBuilder_httpClient, httpClient, "f");
785
- __classPrivateFieldSet(this, _CollectionBuilder_config, config, "f");
786
1142
  // Build the default query with the contentType field
787
1143
  __classPrivateFieldSet(this, _CollectionBuilder_defaultQuery, new QueryBuilder().field('contentType').equals(__classPrivateFieldGet(this, _CollectionBuilder_contentType, "f")), "f");
788
1144
  }
@@ -814,17 +1170,7 @@ class CollectionBuilder {
814
1170
  * @memberof CollectionBuilder
815
1171
  */
816
1172
  get url() {
817
- return `${__classPrivateFieldGet(this, _CollectionBuilder_config, "f").dotcmsUrl}${CONTENT_API_URL}`;
818
- }
819
- /**
820
- * Returns the site ID from the configuration.
821
- *
822
- * @readonly
823
- * @private
824
- * @memberof CollectionBuilder
825
- */
826
- get siteId() {
827
- return __classPrivateFieldGet(this, _CollectionBuilder_config, "f").siteId;
1173
+ return `${this.config.dotcmsUrl}${CONTENT_API_URL}`;
828
1174
  }
829
1175
  /**
830
1176
  * Returns the current query built.
@@ -1076,11 +1422,11 @@ class CollectionBuilder {
1076
1422
  const finalQuery = this.getFinalQuery();
1077
1423
  const sanitizedQuery = sanitizeQueryForContentType(finalQuery, __classPrivateFieldGet(this, _CollectionBuilder_contentType, "f"));
1078
1424
  const query = __classPrivateFieldGet(this, _CollectionBuilder_rawQuery, "f") ? `${sanitizedQuery} ${__classPrivateFieldGet(this, _CollectionBuilder_rawQuery, "f")}` : sanitizedQuery;
1079
- return __classPrivateFieldGet(this, _CollectionBuilder_httpClient, "f").request(this.url, {
1080
- ...__classPrivateFieldGet(this, _CollectionBuilder_requestOptions, "f"),
1425
+ return this.httpClient.request(this.url, {
1426
+ ...this.requestOptions,
1081
1427
  method: 'POST',
1082
1428
  headers: {
1083
- ...__classPrivateFieldGet(this, _CollectionBuilder_requestOptions, "f").headers,
1429
+ ...this.requestOptions.headers,
1084
1430
  'Content-Type': 'application/json'
1085
1431
  },
1086
1432
  body: JSON.stringify({
@@ -1089,7 +1435,8 @@ class CollectionBuilder {
1089
1435
  sort: this.sort,
1090
1436
  limit: __classPrivateFieldGet(this, _CollectionBuilder_limit, "f"),
1091
1437
  offset: this.offset,
1092
- depth: __classPrivateFieldGet(this, _CollectionBuilder_depth, "f")
1438
+ depth: __classPrivateFieldGet(this, _CollectionBuilder_depth, "f"),
1439
+ languageId: __classPrivateFieldGet(this, _CollectionBuilder_languageId, "f")
1093
1440
  //userId: This exist but we currently don't use it
1094
1441
  //allCategoriesInfo: This exist but we currently don't use it
1095
1442
  })
@@ -1118,7 +1465,7 @@ class CollectionBuilder {
1118
1465
  *
1119
1466
  * @example
1120
1467
  * // For draft content without site constraint:
1121
- * // Returns: "+contentType:Blog +languageId:1 +live:false"
1468
+ * // Returns: "+contentType:Blog +languageId:1 +(live:false AND working:true AND deleted:false)"
1122
1469
  *
1123
1470
  * @example
1124
1471
  * // For content with explicit exclusion of current site (site ID 123):
@@ -1131,26 +1478,30 @@ class CollectionBuilder {
1131
1478
  * // Returns: "+contentType:Blog -conhost:456 +languageId:1 +live:true +conhost:123" (site ID still added)
1132
1479
  */
1133
1480
  getFinalQuery() {
1134
- // Build base query with language and live/draft constraints
1135
- const baseQuery = this.currentQuery
1136
- .field('languageId')
1137
- .equals(__classPrivateFieldGet(this, _CollectionBuilder_languageId, "f").toString())
1138
- .field('live')
1139
- .equals((!__classPrivateFieldGet(this, _CollectionBuilder_draft, "f")).toString())
1140
- .build();
1481
+ // Build base query with language and live/draft constraints.
1482
+ // NOTE: languageId is intentionally sent in BOTH places:
1483
+ // - in the Lucene query (backend requires this)
1484
+ // - as a top-level request body field (backend also requires this)
1485
+ let baseQuery = this.currentQuery.field('languageId').equals(__classPrivateFieldGet(this, _CollectionBuilder_languageId, "f").toString());
1486
+ if (__classPrivateFieldGet(this, _CollectionBuilder_draft, "f")) {
1487
+ baseQuery = baseQuery.raw('+(live:false AND working:true AND deleted:false)');
1488
+ }
1489
+ else {
1490
+ baseQuery = baseQuery.field('live').equals('true');
1491
+ }
1492
+ const builtQuery = baseQuery.build();
1141
1493
  // Check if site ID constraint should be added using utility function
1142
- const shouldAddSiteId = shouldAddSiteIdConstraint(baseQuery, this.siteId);
1494
+ const shouldAddSiteId = shouldAddSiteIdConstraint(builtQuery, this.siteId);
1143
1495
  // Add site ID constraint if needed
1144
1496
  if (shouldAddSiteId) {
1145
- const queryWithSiteId = `${baseQuery} +conhost:${this.siteId}`;
1497
+ const queryWithSiteId = `${builtQuery} +conhost:${this.siteId}`;
1146
1498
  return sanitizeQuery(queryWithSiteId);
1147
1499
  }
1148
- return baseQuery;
1500
+ return builtQuery;
1149
1501
  }
1150
1502
  }
1151
- _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_requestOptions = new WeakMap(), _CollectionBuilder_httpClient = new WeakMap(), _CollectionBuilder_config = new WeakMap();
1503
+ _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();
1152
1504
 
1153
- var _Content_requestOptions, _Content_httpClient, _Content_config;
1154
1505
  /**
1155
1506
  * Creates a builder to filter and fetch a collection of content items.
1156
1507
  * @param contentType - The content type to retrieve.
@@ -1200,20 +1551,15 @@ var _Content_requestOptions, _Content_httpClient, _Content_config;
1200
1551
  * });
1201
1552
  * ```
1202
1553
  */
1203
- class Content {
1554
+ class Content extends BaseApiClient {
1204
1555
  /**
1205
1556
  * Creates an instance of Content.
1557
+ * @param {DotCMSClientConfig} config - Configuration options for the DotCMS client
1206
1558
  * @param {DotRequestOptions} requestOptions - The options for the client request.
1207
- * @param {string} serverUrl - The server URL.
1208
1559
  * @param {DotHttpClient} httpClient - HTTP client for making requests.
1209
1560
  */
1210
1561
  constructor(config, requestOptions, httpClient) {
1211
- _Content_requestOptions.set(this, void 0);
1212
- _Content_httpClient.set(this, void 0);
1213
- _Content_config.set(this, void 0);
1214
- __classPrivateFieldSet(this, _Content_requestOptions, requestOptions, "f");
1215
- __classPrivateFieldSet(this, _Content_config, config, "f");
1216
- __classPrivateFieldSet(this, _Content_httpClient, httpClient, "f");
1562
+ super(config, requestOptions, httpClient);
1217
1563
  }
1218
1564
  /**
1219
1565
  * Takes a content type and returns a builder to filter and fetch the collection.
@@ -1281,16 +1627,20 @@ class Content {
1281
1627
  *
1282
1628
  */
1283
1629
  getCollection(contentType) {
1284
- return new CollectionBuilder(__classPrivateFieldGet(this, _Content_requestOptions, "f"), __classPrivateFieldGet(this, _Content_config, "f"), contentType, __classPrivateFieldGet(this, _Content_httpClient, "f"));
1630
+ return new CollectionBuilder(this.requestOptions, this.config, contentType, this.httpClient);
1285
1631
  }
1286
1632
  }
1287
- _Content_requestOptions = new WeakMap(), _Content_httpClient = new WeakMap(), _Content_config = new WeakMap();
1288
1633
 
1289
- class NavigationClient {
1634
+ class NavigationClient extends BaseApiClient {
1635
+ /**
1636
+ * Creates a new NavigationClient instance.
1637
+ * @param {DotCMSClientConfig} config - Configuration options for the DotCMS client
1638
+ * @param {DotRequestOptions} requestOptions - Options for fetch requests including authorization headers
1639
+ * @param {DotHttpClient} httpClient - HTTP client for making requests
1640
+ */
1290
1641
  constructor(config, requestOptions, httpClient) {
1291
- this.requestOptions = requestOptions;
1642
+ super(config, requestOptions, httpClient);
1292
1643
  this.BASE_URL = `${config?.dotcmsUrl}/api/v1/nav`;
1293
- this.httpClient = httpClient;
1294
1644
  }
1295
1645
  /**
1296
1646
  * Retrieves information about the dotCMS file and folder tree.
@@ -1420,6 +1770,8 @@ const buildPageQuery = ({ page, fragments, additionalQueries }) => {
1420
1770
  canLock
1421
1771
  canRead
1422
1772
  runningExperimentId
1773
+ lockedBy
1774
+ lockedByName
1423
1775
  urlContentMap {
1424
1776
  _map
1425
1777
  }
@@ -1485,6 +1837,7 @@ const buildPageQuery = ({ page, fragments, additionalQueries }) => {
1485
1837
  }
1486
1838
  }
1487
1839
  viewAs {
1840
+ variantId
1488
1841
  visitor {
1489
1842
  persona {
1490
1843
  modDate
@@ -1587,7 +1940,7 @@ async function fetchGraphQL({ baseURL, body, headers, httpClient }) {
1587
1940
  * Client for interacting with the DotCMS Page API.
1588
1941
  * Provides methods to retrieve and manipulate pages.
1589
1942
  */
1590
- class PageClient {
1943
+ class PageClient extends BaseApiClient {
1591
1944
  /**
1592
1945
  * Creates a new PageClient instance.
1593
1946
  *
@@ -1612,10 +1965,7 @@ class PageClient {
1612
1965
  * ```
1613
1966
  */
1614
1967
  constructor(config, requestOptions, httpClient) {
1615
- this.requestOptions = requestOptions;
1616
- this.siteId = config.siteId || '';
1617
- this.dotcmsUrl = config.dotcmsUrl;
1618
- this.httpClient = httpClient;
1968
+ super(config, requestOptions, httpClient);
1619
1969
  }
1620
1970
  /**
1621
1971
  * Retrieves a page from DotCMS using GraphQL.
@@ -1703,12 +2053,25 @@ class PageClient {
1703
2053
  response.errors.forEach((error) => {
1704
2054
  consola.consola.error('[DotCMS GraphQL Error]: ', error.message);
1705
2055
  });
2056
+ const pageError = response.errors.find((error) => error.message.includes('DotPage'));
2057
+ if (pageError) {
2058
+ // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2059
+ throw new types.DotHttpError({
2060
+ status: 400,
2061
+ statusText: 'Bad Request',
2062
+ message: `GraphQL query failed for URL '${url}': ${pageError.message}`,
2063
+ data: response.errors
2064
+ });
2065
+ }
1706
2066
  }
1707
2067
  const pageResponse = internal.graphqlToPageEntity(response.data.page);
1708
2068
  if (!pageResponse) {
1709
- throw new types.DotErrorPage(`Page ${url} not found. Check the page URL and permissions.`, undefined, {
1710
- query: completeQuery,
1711
- variables: requestVariables
2069
+ // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2070
+ throw new types.DotHttpError({
2071
+ status: 404,
2072
+ statusText: 'Not Found',
2073
+ message: `Page ${url} not found. Check the page URL and permissions.`,
2074
+ data: response.errors
1712
2075
  });
1713
2076
  }
1714
2077
  const contentResponse = mapContentResponse(response.data, Object.keys(content));
@@ -1722,7 +2085,7 @@ class PageClient {
1722
2085
  };
1723
2086
  }
1724
2087
  catch (error) {
1725
- // Handle DotHttpError instances from httpClient.request
2088
+ // Handle DotHttpError instances
1726
2089
  if (error instanceof types.DotHttpError) {
1727
2090
  throw new types.DotErrorPage(`Page request failed for URL '${url}': ${error.message}`, error, {
1728
2091
  query: completeQuery,
@@ -1780,6 +2143,7 @@ class DotCMSClient {
1780
2143
  this.page = new PageClient(this.config, this.requestOptions, this.httpClient);
1781
2144
  this.nav = new NavigationClient(this.config, this.requestOptions, this.httpClient);
1782
2145
  this.content = new Content(this.config, this.requestOptions, this.httpClient);
2146
+ this.ai = new AIClient(this.config, this.requestOptions, this.httpClient);
1783
2147
  }
1784
2148
  /**
1785
2149
  * Creates request options with authentication headers.