@dotcms/client 1.5.1-next.1964 → 1.5.1-next.1972

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/README.md CHANGED
@@ -699,13 +699,14 @@ createDotCMSClient(config: DotCMSClientConfig): DotCMSClient
699
699
 
700
700
  #### Parameters
701
701
 
702
- | Option | Type | Required | Description |
703
- | ---------------- | ----------------- | -------- | ------------------------------------------------------------- |
704
- | `dotcmsUrl` | string | ✅ | Your dotCMS instance URL |
705
- | `authToken` | string | ✅ | Authentication token |
706
- | `siteId` | string | ❌ | Site identifier (falls back to default site if not specified) |
707
- | `requestOptions` | DotRequestOptions | ❌ | Additional request options |
708
- | `httpClient` | DotHttpClient | ❌ | Custom HTTP client implementation |
702
+ | Option | Type | Required | Description |
703
+ | ---------------- | -------------------------- | -------- | ------------------------------------------------------------- |
704
+ | `dotcmsUrl` | string | ✅ | Your dotCMS instance URL |
705
+ | `authToken` | string | ✅ | Authentication token |
706
+ | `siteId` | string | ❌ | Site identifier (falls back to default site if not specified) |
707
+ | `requestOptions` | DotRequestOptions | ❌ | Additional request options |
708
+ | `httpClient` | DotHttpClient | ❌ | Custom HTTP client implementation |
709
+ | `logLevel` | `'default'` \| `'verbose'` | ❌ | Controls log verbosity. `'verbose'` adds status, code, and variables to error logs. Defaults to `'default'` |
709
710
 
710
711
  #### Example
711
712
  ```typescript
@@ -713,10 +714,14 @@ const client = createDotCMSClient({
713
714
  dotcmsUrl: 'https://your-dotcms-instance.com',
714
715
  authToken: 'your-auth-token',
715
716
  siteId: 'your-site-id',
716
- httpClient: customHttpClient // Optional: provide custom HTTP client
717
+ httpClient: customHttpClient, // Optional: provide custom HTTP client
718
+ logLevel: 'verbose' // Optional: enable detailed error logs
717
719
  });
718
720
  ```
719
721
 
722
+ > [!TIP]
723
+ > Enable `logLevel: 'verbose'` during development to see HTTP status codes, error codes, and request variables in error logs. In verbose mode, error logs also include a hint to access the full GraphQL query via `error.graphql.query`. Keep it at `'default'` (or omit it) in production to avoid noisy logs.
724
+
720
725
  ### HTTP Client Configuration
721
726
 
722
727
  The SDK now supports custom HTTP client implementations for advanced use cases. By default, it uses the built-in `FetchHttpClient` based on the native Fetch API.
package/index.cjs.js CHANGED
@@ -2107,8 +2107,8 @@ const DEFAULT_PAGE_CONTENTLETS_CONTENT = `
2107
2107
  * @param {string} additionalQueries - Additional GraphQL queries to include in the main query
2108
2108
  * @returns {string} Complete GraphQL query string for page content
2109
2109
  */
2110
- const buildPageQuery = ({ page, fragments, additionalQueries }) => {
2111
- if (!page) {
2110
+ const buildPageQuery = ({ page, fragments, additionalQueries, verbose = false }) => {
2111
+ if (!page && verbose) {
2112
2112
  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.");
2113
2113
  }
2114
2114
  return `
@@ -2309,6 +2309,49 @@ function mapContentResponse(responseData, keys) {
2309
2309
  return accumulator;
2310
2310
  }, {});
2311
2311
  }
2312
+ /**
2313
+ * Loads style editor schemas from GET /api/v1/page/{pageId}/contenttype-schema.
2314
+ * Requires READ on the page; failures are silently ignored so callers still work without auth.
2315
+ *
2316
+ * @internal
2317
+ */
2318
+ async function fetchStyleEditorSchemas(pageId, config, requestOptions, httpClient) {
2319
+ if (typeof window === 'undefined') {
2320
+ return [];
2321
+ }
2322
+ if (!pageId) {
2323
+ consola.consola.warn('[DotCMS PageClient]: fetchStyleEditorSchemas called without a pageId — ' +
2324
+ 'make sure "identifier" is included in your GraphQL page fragment.');
2325
+ return [];
2326
+ }
2327
+ try {
2328
+ const url = new URL(config.dotcmsUrl);
2329
+ url.pathname = `/api/v1/page/${encodeURIComponent(pageId)}/contenttype-schema`;
2330
+ const data = await httpClient.request(url.toString(), {
2331
+ ...requestOptions,
2332
+ method: 'GET',
2333
+ headers: {
2334
+ Accept: 'application/json',
2335
+ ...requestOptions.headers
2336
+ }
2337
+ });
2338
+ const { entity } = data ?? {};
2339
+ if (!Array.isArray(entity)) {
2340
+ return [];
2341
+ }
2342
+ return entity;
2343
+ }
2344
+ catch (error) {
2345
+ if (error instanceof types.DotHttpError && (error.status === 401 || error.status === 403)) {
2346
+ consola.consola.warn(`[DotCMS PageClient]: Style editor schemas request failed with ${error.status} — ` +
2347
+ 'make sure your DotCMS client is configured with a valid authToken that has READ access to the page.');
2348
+ }
2349
+ else {
2350
+ consola.consola.debug('[DotCMS PageClient]: Skipping style editor schemas:', error);
2351
+ }
2352
+ return [];
2353
+ }
2354
+ }
2312
2355
  /**
2313
2356
  * Executes a GraphQL query against the DotCMS API.
2314
2357
  *
@@ -2330,6 +2373,11 @@ async function fetchGraphQL({ baseURL, body, headers, httpClient }) {
2330
2373
  });
2331
2374
  }
2332
2375
 
2376
+ function logVerboseError(url, message, details) {
2377
+ const statusLine = details.status !== undefined ? `\n status: ${details.status} | code: ${details.code}` : '';
2378
+ const variables = JSON.stringify(details.variables, null, 2).replace(/\n/g, '\n ');
2379
+ consola.consola.error(`[DotCMS GraphQL Error] ${url}: ${message}${statusLine}\n\n variables:\n ${variables}\n\n (full query available at error.graphql.query)`);
2380
+ }
2333
2381
  /**
2334
2382
  * Client for interacting with the DotCMS Page API.
2335
2383
  * Provides methods to retrieve and manipulate pages.
@@ -2415,15 +2463,18 @@ class PageClient extends BaseApiClient {
2415
2463
  async get(url, options) {
2416
2464
  const { languageId = '1', mode = 'LIVE', siteId = this.siteId, fireRules = false, personaId, publishDate, variantName, graphql = {} } = options || {};
2417
2465
  const { page, content = {}, variables, fragments } = graphql;
2466
+ const verbose = this.config.logLevel === 'verbose';
2418
2467
  const contentQuery = buildQuery(content);
2419
2468
  const completeQuery = buildPageQuery({
2420
2469
  page,
2421
2470
  fragments,
2422
- additionalQueries: contentQuery
2471
+ additionalQueries: contentQuery,
2472
+ verbose
2423
2473
  });
2474
+ const normalizedUrl = url.startsWith('/') ? url : `/${url}`;
2424
2475
  const requestVariables = {
2425
2476
  // The url is expected to have a leading slash to comply on VanityURL Matching, some frameworks like Angular will not add the leading slash
2426
- url: url.startsWith('/') ? url : `/${url}`,
2477
+ url: normalizedUrl,
2427
2478
  mode,
2428
2479
  languageId,
2429
2480
  personaId,
@@ -2442,32 +2493,77 @@ class PageClient extends BaseApiClient {
2442
2493
  headers: requestHeaders,
2443
2494
  httpClient: this.httpClient
2444
2495
  });
2445
- // The GQL endpoint can return errors and data, we need to handle both
2446
- if (response.errors) {
2447
- response.errors.forEach((error) => {
2448
- consola.consola.error('[DotCMS GraphQL Error]: ', error.message);
2496
+ // 1. Log unstructured GraphQL errors (structured ones are logged with enriched messages below)
2497
+ if (response.errors?.length) {
2498
+ response.errors
2499
+ .filter((error) => !error.extensions?.code)
2500
+ .forEach((error) => {
2501
+ if (verbose) {
2502
+ logVerboseError(normalizedUrl, error.message, {
2503
+ variables: requestVariables
2504
+ });
2505
+ }
2506
+ else {
2507
+ consola.consola.error(`[DotCMS GraphQL Error] ${normalizedUrl}: `, error.message);
2508
+ }
2449
2509
  });
2450
- const pageError = response.errors.find((error) => error.message.includes('DotPage'));
2451
- if (pageError) {
2452
- // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2453
- throw new types.DotHttpError({
2454
- status: 400,
2455
- statusText: 'Bad Request',
2456
- message: `GraphQL query failed for URL '${url}': ${pageError.message}`,
2457
- data: response.errors
2510
+ }
2511
+ // 2. BAD QUERY — data is null/undefined means the entire query failed
2512
+ // (syntax error, unknown type, validation error)
2513
+ // Must check BEFORE accessing response.data.page
2514
+ if (!response.data) {
2515
+ const firstError = response.errors?.[0];
2516
+ throw new types.DotErrorPage(firstError?.message ?? 'GraphQL query failed', 400, 'BAD_REQUEST', new types.DotHttpError({
2517
+ status: 400,
2518
+ statusText: 'Bad Request',
2519
+ message: firstError?.message ?? 'GraphQL query failed',
2520
+ data: response.errors
2521
+ }), { query: completeQuery, variables: requestVariables });
2522
+ }
2523
+ // 3. STRUCTURED ERRORS — check extensions.code for NOT_FOUND, PERMISSION_DENIED, etc.
2524
+ // Only fatal when the page itself failed (data.page is null/undefined).
2525
+ // If data.page exists, partial errors (e.g. secondary content) surface via errors[].
2526
+ if (response.errors?.length && !response.data.page) {
2527
+ const structuredError = response.errors.find((error) => error.extensions?.code);
2528
+ if (structuredError) {
2529
+ const code = structuredError.extensions.code;
2530
+ const status = structuredError.extensions.status ??
2531
+ (code === 'NOT_FOUND' ? 404 : code === 'PERMISSION_DENIED' ? 403 : 400);
2532
+ const message = code === 'NOT_FOUND'
2533
+ ? `Page '${normalizedUrl}' was not found`
2534
+ : code === 'PERMISSION_DENIED'
2535
+ ? `Permission denied: you do not have access to page '${normalizedUrl}'. Verify the page permissions in dotCMS and that the auth token has sufficient access.`
2536
+ : `Page '${normalizedUrl}' could not be loaded (${code})`;
2537
+ if (verbose) {
2538
+ logVerboseError(normalizedUrl, message, {
2539
+ status,
2540
+ code,
2541
+ variables: requestVariables
2542
+ });
2543
+ }
2544
+ else {
2545
+ consola.consola.error(`[DotCMS GraphQL Error] ${normalizedUrl}: `, message);
2546
+ }
2547
+ throw new types.DotErrorPage(message, status, code, undefined, {
2548
+ query: completeQuery,
2549
+ variables: requestVariables
2458
2550
  });
2459
2551
  }
2460
2552
  }
2461
- const pageResponse = internal.graphqlToPageEntity(response.data.page);
2553
+ // 4. Transform and check page — null page with no structured error = 404
2554
+ const pageResponse = response.data.page
2555
+ ? internal.graphqlToPageEntity(response.data.page)
2556
+ : null;
2462
2557
  if (!pageResponse) {
2463
- // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2464
- throw new types.DotHttpError({
2558
+ throw new types.DotErrorPage(`Page '${normalizedUrl}' was not found`, 404, 'NOT_FOUND', new types.DotHttpError({
2465
2559
  status: 404,
2466
2560
  statusText: 'Not Found',
2467
- message: `Page ${url} not found. Check the page URL and permissions.`,
2561
+ message: `Page '${normalizedUrl}' was not found`,
2468
2562
  data: response.errors
2469
- });
2563
+ }), { query: completeQuery, variables: requestVariables });
2470
2564
  }
2565
+ const styleEditorSchemas = await fetchStyleEditorSchemas(pageResponse.page.identifier, this.config, this.requestOptions, this.httpClient);
2566
+ // 5. Build response — include any non-fatal errors for consumers to inspect
2471
2567
  const contentResponse = mapContentResponse(response.data, Object.keys(content));
2472
2568
  return {
2473
2569
  pageAsset: pageResponse,
@@ -2475,22 +2571,19 @@ class PageClient extends BaseApiClient {
2475
2571
  graphql: {
2476
2572
  query: completeQuery,
2477
2573
  variables: requestVariables
2478
- }
2574
+ },
2575
+ errors: response.errors?.length ? response.errors : undefined,
2576
+ ...(styleEditorSchemas.length > 0 && { styleEditorSchemas })
2479
2577
  };
2480
2578
  }
2481
2579
  catch (error) {
2482
- // Handle DotHttpError instances
2580
+ if (error instanceof types.DotErrorPage) {
2581
+ throw error;
2582
+ }
2483
2583
  if (error instanceof types.DotHttpError) {
2484
- throw new types.DotErrorPage(`Page request failed for URL '${url}': ${error.message}`, error, {
2485
- query: completeQuery,
2486
- variables: requestVariables
2487
- });
2584
+ throw new types.DotErrorPage(`Page request failed for URL '${normalizedUrl}': ${error.message}`, error.status, 'UNKNOWN', error, { query: completeQuery, variables: requestVariables });
2488
2585
  }
2489
- // Handle other errors (GraphQL errors, validation errors, etc.)
2490
- throw new types.DotErrorPage(`Page request failed for URL '${url}': ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, {
2491
- query: completeQuery,
2492
- variables: requestVariables
2493
- });
2586
+ throw new types.DotErrorPage(`Page request failed for URL '${normalizedUrl}': ${error instanceof Error ? error.message : 'Unknown error'}`, 500, 'UNKNOWN', undefined, { query: completeQuery, variables: requestVariables });
2494
2587
  }
2495
2588
  }
2496
2589
  }
package/index.esm.js CHANGED
@@ -2105,8 +2105,8 @@ const DEFAULT_PAGE_CONTENTLETS_CONTENT = `
2105
2105
  * @param {string} additionalQueries - Additional GraphQL queries to include in the main query
2106
2106
  * @returns {string} Complete GraphQL query string for page content
2107
2107
  */
2108
- const buildPageQuery = ({ page, fragments, additionalQueries }) => {
2109
- if (!page) {
2108
+ const buildPageQuery = ({ page, fragments, additionalQueries, verbose = false }) => {
2109
+ if (!page && verbose) {
2110
2110
  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.");
2111
2111
  }
2112
2112
  return `
@@ -2307,6 +2307,49 @@ function mapContentResponse(responseData, keys) {
2307
2307
  return accumulator;
2308
2308
  }, {});
2309
2309
  }
2310
+ /**
2311
+ * Loads style editor schemas from GET /api/v1/page/{pageId}/contenttype-schema.
2312
+ * Requires READ on the page; failures are silently ignored so callers still work without auth.
2313
+ *
2314
+ * @internal
2315
+ */
2316
+ async function fetchStyleEditorSchemas(pageId, config, requestOptions, httpClient) {
2317
+ if (typeof window === 'undefined') {
2318
+ return [];
2319
+ }
2320
+ if (!pageId) {
2321
+ consola.warn('[DotCMS PageClient]: fetchStyleEditorSchemas called without a pageId — ' +
2322
+ 'make sure "identifier" is included in your GraphQL page fragment.');
2323
+ return [];
2324
+ }
2325
+ try {
2326
+ const url = new URL(config.dotcmsUrl);
2327
+ url.pathname = `/api/v1/page/${encodeURIComponent(pageId)}/contenttype-schema`;
2328
+ const data = await httpClient.request(url.toString(), {
2329
+ ...requestOptions,
2330
+ method: 'GET',
2331
+ headers: {
2332
+ Accept: 'application/json',
2333
+ ...requestOptions.headers
2334
+ }
2335
+ });
2336
+ const { entity } = data ?? {};
2337
+ if (!Array.isArray(entity)) {
2338
+ return [];
2339
+ }
2340
+ return entity;
2341
+ }
2342
+ catch (error) {
2343
+ if (error instanceof DotHttpError && (error.status === 401 || error.status === 403)) {
2344
+ consola.warn(`[DotCMS PageClient]: Style editor schemas request failed with ${error.status} — ` +
2345
+ 'make sure your DotCMS client is configured with a valid authToken that has READ access to the page.');
2346
+ }
2347
+ else {
2348
+ consola.debug('[DotCMS PageClient]: Skipping style editor schemas:', error);
2349
+ }
2350
+ return [];
2351
+ }
2352
+ }
2310
2353
  /**
2311
2354
  * Executes a GraphQL query against the DotCMS API.
2312
2355
  *
@@ -2328,6 +2371,11 @@ async function fetchGraphQL({ baseURL, body, headers, httpClient }) {
2328
2371
  });
2329
2372
  }
2330
2373
 
2374
+ function logVerboseError(url, message, details) {
2375
+ const statusLine = details.status !== undefined ? `\n status: ${details.status} | code: ${details.code}` : '';
2376
+ const variables = JSON.stringify(details.variables, null, 2).replace(/\n/g, '\n ');
2377
+ consola.error(`[DotCMS GraphQL Error] ${url}: ${message}${statusLine}\n\n variables:\n ${variables}\n\n (full query available at error.graphql.query)`);
2378
+ }
2331
2379
  /**
2332
2380
  * Client for interacting with the DotCMS Page API.
2333
2381
  * Provides methods to retrieve and manipulate pages.
@@ -2413,15 +2461,18 @@ class PageClient extends BaseApiClient {
2413
2461
  async get(url, options) {
2414
2462
  const { languageId = '1', mode = 'LIVE', siteId = this.siteId, fireRules = false, personaId, publishDate, variantName, graphql = {} } = options || {};
2415
2463
  const { page, content = {}, variables, fragments } = graphql;
2464
+ const verbose = this.config.logLevel === 'verbose';
2416
2465
  const contentQuery = buildQuery(content);
2417
2466
  const completeQuery = buildPageQuery({
2418
2467
  page,
2419
2468
  fragments,
2420
- additionalQueries: contentQuery
2469
+ additionalQueries: contentQuery,
2470
+ verbose
2421
2471
  });
2472
+ const normalizedUrl = url.startsWith('/') ? url : `/${url}`;
2422
2473
  const requestVariables = {
2423
2474
  // The url is expected to have a leading slash to comply on VanityURL Matching, some frameworks like Angular will not add the leading slash
2424
- url: url.startsWith('/') ? url : `/${url}`,
2475
+ url: normalizedUrl,
2425
2476
  mode,
2426
2477
  languageId,
2427
2478
  personaId,
@@ -2440,32 +2491,77 @@ class PageClient extends BaseApiClient {
2440
2491
  headers: requestHeaders,
2441
2492
  httpClient: this.httpClient
2442
2493
  });
2443
- // The GQL endpoint can return errors and data, we need to handle both
2444
- if (response.errors) {
2445
- response.errors.forEach((error) => {
2446
- consola.error('[DotCMS GraphQL Error]: ', error.message);
2494
+ // 1. Log unstructured GraphQL errors (structured ones are logged with enriched messages below)
2495
+ if (response.errors?.length) {
2496
+ response.errors
2497
+ .filter((error) => !error.extensions?.code)
2498
+ .forEach((error) => {
2499
+ if (verbose) {
2500
+ logVerboseError(normalizedUrl, error.message, {
2501
+ variables: requestVariables
2502
+ });
2503
+ }
2504
+ else {
2505
+ consola.error(`[DotCMS GraphQL Error] ${normalizedUrl}: `, error.message);
2506
+ }
2447
2507
  });
2448
- const pageError = response.errors.find((error) => error.message.includes('DotPage'));
2449
- if (pageError) {
2450
- // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2451
- throw new DotHttpError({
2452
- status: 400,
2453
- statusText: 'Bad Request',
2454
- message: `GraphQL query failed for URL '${url}': ${pageError.message}`,
2455
- data: response.errors
2508
+ }
2509
+ // 2. BAD QUERY — data is null/undefined means the entire query failed
2510
+ // (syntax error, unknown type, validation error)
2511
+ // Must check BEFORE accessing response.data.page
2512
+ if (!response.data) {
2513
+ const firstError = response.errors?.[0];
2514
+ throw new DotErrorPage(firstError?.message ?? 'GraphQL query failed', 400, 'BAD_REQUEST', new DotHttpError({
2515
+ status: 400,
2516
+ statusText: 'Bad Request',
2517
+ message: firstError?.message ?? 'GraphQL query failed',
2518
+ data: response.errors
2519
+ }), { query: completeQuery, variables: requestVariables });
2520
+ }
2521
+ // 3. STRUCTURED ERRORS — check extensions.code for NOT_FOUND, PERMISSION_DENIED, etc.
2522
+ // Only fatal when the page itself failed (data.page is null/undefined).
2523
+ // If data.page exists, partial errors (e.g. secondary content) surface via errors[].
2524
+ if (response.errors?.length && !response.data.page) {
2525
+ const structuredError = response.errors.find((error) => error.extensions?.code);
2526
+ if (structuredError) {
2527
+ const code = structuredError.extensions.code;
2528
+ const status = structuredError.extensions.status ??
2529
+ (code === 'NOT_FOUND' ? 404 : code === 'PERMISSION_DENIED' ? 403 : 400);
2530
+ const message = code === 'NOT_FOUND'
2531
+ ? `Page '${normalizedUrl}' was not found`
2532
+ : code === 'PERMISSION_DENIED'
2533
+ ? `Permission denied: you do not have access to page '${normalizedUrl}'. Verify the page permissions in dotCMS and that the auth token has sufficient access.`
2534
+ : `Page '${normalizedUrl}' could not be loaded (${code})`;
2535
+ if (verbose) {
2536
+ logVerboseError(normalizedUrl, message, {
2537
+ status,
2538
+ code,
2539
+ variables: requestVariables
2540
+ });
2541
+ }
2542
+ else {
2543
+ consola.error(`[DotCMS GraphQL Error] ${normalizedUrl}: `, message);
2544
+ }
2545
+ throw new DotErrorPage(message, status, code, undefined, {
2546
+ query: completeQuery,
2547
+ variables: requestVariables
2456
2548
  });
2457
2549
  }
2458
2550
  }
2459
- const pageResponse = graphqlToPageEntity(response.data.page);
2551
+ // 4. Transform and check page — null page with no structured error = 404
2552
+ const pageResponse = response.data.page
2553
+ ? graphqlToPageEntity(response.data.page)
2554
+ : null;
2460
2555
  if (!pageResponse) {
2461
- // Throw HTTP error - will be caught and wrapped in DotErrorPage below
2462
- throw new DotHttpError({
2556
+ throw new DotErrorPage(`Page '${normalizedUrl}' was not found`, 404, 'NOT_FOUND', new DotHttpError({
2463
2557
  status: 404,
2464
2558
  statusText: 'Not Found',
2465
- message: `Page ${url} not found. Check the page URL and permissions.`,
2559
+ message: `Page '${normalizedUrl}' was not found`,
2466
2560
  data: response.errors
2467
- });
2561
+ }), { query: completeQuery, variables: requestVariables });
2468
2562
  }
2563
+ const styleEditorSchemas = await fetchStyleEditorSchemas(pageResponse.page.identifier, this.config, this.requestOptions, this.httpClient);
2564
+ // 5. Build response — include any non-fatal errors for consumers to inspect
2469
2565
  const contentResponse = mapContentResponse(response.data, Object.keys(content));
2470
2566
  return {
2471
2567
  pageAsset: pageResponse,
@@ -2473,22 +2569,19 @@ class PageClient extends BaseApiClient {
2473
2569
  graphql: {
2474
2570
  query: completeQuery,
2475
2571
  variables: requestVariables
2476
- }
2572
+ },
2573
+ errors: response.errors?.length ? response.errors : undefined,
2574
+ ...(styleEditorSchemas.length > 0 && { styleEditorSchemas })
2477
2575
  };
2478
2576
  }
2479
2577
  catch (error) {
2480
- // Handle DotHttpError instances
2578
+ if (error instanceof DotErrorPage) {
2579
+ throw error;
2580
+ }
2481
2581
  if (error instanceof DotHttpError) {
2482
- throw new DotErrorPage(`Page request failed for URL '${url}': ${error.message}`, error, {
2483
- query: completeQuery,
2484
- variables: requestVariables
2485
- });
2582
+ throw new DotErrorPage(`Page request failed for URL '${normalizedUrl}': ${error.message}`, error.status, 'UNKNOWN', error, { query: completeQuery, variables: requestVariables });
2486
2583
  }
2487
- // Handle other errors (GraphQL errors, validation errors, etc.)
2488
- throw new DotErrorPage(`Page request failed for URL '${url}': ${error instanceof Error ? error.message : 'Unknown error'}`, undefined, {
2489
- query: completeQuery,
2490
- variables: requestVariables
2491
- });
2584
+ throw new DotErrorPage(`Page request failed for URL '${normalizedUrl}': ${error instanceof Error ? error.message : 'Unknown error'}`, 500, 'UNKNOWN', undefined, { query: completeQuery, variables: requestVariables });
2492
2585
  }
2493
2586
  }
2494
2587
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dotcms/client",
3
- "version": "1.5.1-next.1964",
3
+ "version": "1.5.1-next.1972",
4
4
  "description": "Official JavaScript library for interacting with DotCMS REST APIs.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,4 +1,4 @@
1
- import { DotCMSClientConfig, DotCMSPageRequestParams, DotCMSPageResponse, DotCMSExtendedPageResponse, DotCMSComposedPageResponse, DotHttpClient, DotRequestOptions } from '@dotcms/types';
1
+ import { DotCMSClientConfig, DotCMSComposedPageResponse, DotCMSExtendedPageResponse, DotCMSPageRequestParams, DotCMSPageResponse, DotHttpClient, DotRequestOptions } from '@dotcms/types';
2
2
  import { BaseApiClient } from '../base/api/base-api';
3
3
  /**
4
4
  * Client for interacting with the DotCMS Page API.
@@ -1,4 +1,5 @@
1
- import { DotGraphQLApiResponse, DotHttpClient } from '@dotcms/types';
1
+ import { DotCMSClientConfig, DotGraphQLApiResponse, DotHttpClient, DotRequestOptions } from '@dotcms/types';
2
+ import { StyleEditorFormSchema } from '@dotcms/types/internal';
2
3
  /**
3
4
  * Builds a GraphQL query for retrieving page content from DotCMS.
4
5
  *
@@ -6,10 +7,11 @@ import { DotGraphQLApiResponse, DotHttpClient } from '@dotcms/types';
6
7
  * @param {string} additionalQueries - Additional GraphQL queries to include in the main query
7
8
  * @returns {string} Complete GraphQL query string for page content
8
9
  */
9
- export declare const buildPageQuery: ({ page, fragments, additionalQueries }: {
10
+ export declare const buildPageQuery: ({ page, fragments, additionalQueries, verbose }: {
10
11
  page?: string;
11
12
  fragments?: string[];
12
13
  additionalQueries?: string;
14
+ verbose?: boolean;
13
15
  }) => string;
14
16
  /**
15
17
  * Converts a record of query strings into a single GraphQL query string.
@@ -26,6 +28,13 @@ export declare function buildQuery(queryData: Record<string, string>): string;
26
28
  * @returns {Record<string, unknown> | undefined} New object containing only the specified keys
27
29
  */
28
30
  export declare function mapContentResponse(responseData: Record<string, unknown> | undefined, keys: string[]): Record<string, unknown> | undefined;
31
+ /**
32
+ * Loads style editor schemas from GET /api/v1/page/{pageId}/contenttype-schema.
33
+ * Requires READ on the page; failures are silently ignored so callers still work without auth.
34
+ *
35
+ * @internal
36
+ */
37
+ export declare function fetchStyleEditorSchemas(pageId: string | undefined, config: DotCMSClientConfig, requestOptions: DotRequestOptions, httpClient: DotHttpClient): Promise<StyleEditorFormSchema[]>;
29
38
  /**
30
39
  * Executes a GraphQL query against the DotCMS API.
31
40
  *