@dotcms/client 1.0.1 → 1.0.2

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 (52) hide show
  1. package/dotcms-client-1.0.1.tgz +0 -0
  2. package/index.cjs.d.ts +1 -0
  3. package/index.cjs.default.js +1 -0
  4. package/index.cjs.js +1592 -0
  5. package/index.cjs.mjs +2 -0
  6. package/index.esm.d.ts +1 -0
  7. package/index.esm.js +1590 -0
  8. package/internal.cjs.d.ts +1 -0
  9. package/internal.cjs.default.js +1 -0
  10. package/internal.cjs.js +85 -0
  11. package/internal.cjs.mjs +2 -0
  12. package/internal.esm.d.ts +1 -0
  13. package/internal.esm.js +83 -0
  14. package/package.json +24 -7
  15. package/src/lib/client/client.d.ts +56 -0
  16. package/src/lib/client/content/builders/collection/{collection.ts → collection.d.ts} +19 -210
  17. package/src/lib/client/content/builders/query/lucene-syntax/{Equals.ts → Equals.d.ts} +11 -45
  18. package/src/lib/client/content/builders/query/lucene-syntax/{Field.ts → Field.d.ts} +5 -13
  19. package/src/lib/client/content/builders/query/lucene-syntax/{NotOperand.ts → NotOperand.d.ts} +5 -13
  20. package/src/lib/client/content/builders/query/lucene-syntax/{Operand.ts → Operand.d.ts} +7 -21
  21. package/src/lib/client/content/builders/query/{query.ts → query.d.ts} +5 -16
  22. package/src/lib/client/content/builders/query/utils/{index.ts → index.d.ts} +12 -49
  23. package/src/lib/client/content/{content-api.ts → content-api.d.ts} +4 -14
  24. package/src/lib/client/content/shared/{const.ts → const.d.ts} +3 -5
  25. package/src/lib/client/content/shared/{types.ts → types.d.ts} +2 -18
  26. package/src/lib/client/content/shared/{utils.ts → utils.d.ts} +1 -9
  27. package/src/lib/client/models/{index.ts → index.d.ts} +1 -8
  28. package/src/lib/client/navigation/navigation-api.d.ts +14 -0
  29. package/src/lib/client/page/page-api.d.ts +95 -0
  30. package/src/lib/client/page/utils.d.ts +41 -0
  31. package/src/lib/utils/graphql/transforms.d.ts +13 -0
  32. package/.eslintrc.json +0 -18
  33. package/jest.config.ts +0 -15
  34. package/project.json +0 -73
  35. package/src/lib/client/client.spec.ts +0 -147
  36. package/src/lib/client/client.ts +0 -125
  37. package/src/lib/client/content/builders/collection/collection.spec.ts +0 -514
  38. package/src/lib/client/content/builders/query/query.spec.ts +0 -159
  39. package/src/lib/client/navigation/navigation-api.spec.ts +0 -167
  40. package/src/lib/client/navigation/navigation-api.ts +0 -62
  41. package/src/lib/client/page/page-api.spec.ts +0 -359
  42. package/src/lib/client/page/page-api.ts +0 -197
  43. package/src/lib/client/page/utils.ts +0 -291
  44. package/src/lib/utils/graphql/transforms.spec.ts +0 -250
  45. package/src/lib/utils/graphql/transforms.ts +0 -128
  46. package/tsconfig.json +0 -22
  47. package/tsconfig.lib.json +0 -13
  48. package/tsconfig.spec.json +0 -9
  49. /package/src/{index.ts → index.d.ts} +0 -0
  50. /package/src/{internal.ts → internal.d.ts} +0 -0
  51. /package/src/lib/client/content/builders/query/lucene-syntax/{index.ts → index.d.ts} +0 -0
  52. /package/src/lib/utils/{index.ts → index.d.ts} +0 -0
@@ -1,167 +0,0 @@
1
- import { DotCMSClientConfig, RequestOptions } from '@dotcms/types';
2
-
3
- import { NavigationClient } from './navigation-api';
4
-
5
- describe('NavigationClient', () => {
6
- const mockFetch = jest.fn();
7
- const originalFetch = global.fetch;
8
-
9
- const validConfig: DotCMSClientConfig = {
10
- dotcmsUrl: 'https://demo.dotcms.com',
11
- authToken: 'test-token',
12
- siteId: 'test-site'
13
- };
14
-
15
- const requestOptions: RequestOptions = {
16
- headers: {
17
- Authorization: 'Bearer test-token'
18
- }
19
- };
20
-
21
- const mockNavigationData = {
22
- entity: {
23
- title: 'Main Navigation',
24
- items: [
25
- { label: 'Home', url: '/' },
26
- { label: 'About', url: '/about' },
27
- { label: 'Contact', url: '/contact' }
28
- ]
29
- }
30
- };
31
-
32
- beforeEach(() => {
33
- mockFetch.mockReset();
34
- global.fetch = mockFetch;
35
- mockFetch.mockResolvedValue({
36
- ok: true,
37
- json: async () => mockNavigationData
38
- });
39
- });
40
-
41
- afterAll(() => {
42
- global.fetch = originalFetch;
43
- });
44
-
45
- it('should fetch navigation successfully', async () => {
46
- const navClient = new NavigationClient(validConfig, requestOptions);
47
- const result = await navClient.get('/');
48
-
49
- expect(mockFetch).toHaveBeenCalledWith(
50
- 'https://demo.dotcms.com/api/v1/nav/',
51
- requestOptions
52
- );
53
-
54
- expect(result).toEqual(mockNavigationData.entity);
55
- });
56
-
57
- it('should fetch navigation with custom path', async () => {
58
- const navClient = new NavigationClient(validConfig, requestOptions);
59
- const path = '/products';
60
-
61
- await navClient.get(path);
62
-
63
- expect(mockFetch).toHaveBeenCalledWith(
64
- 'https://demo.dotcms.com/api/v1/nav/products',
65
- expect.anything()
66
- );
67
- });
68
-
69
- it('should fetch navigation with custom depth', async () => {
70
- const navClient = new NavigationClient(validConfig, requestOptions);
71
- const depth = 3;
72
-
73
- await navClient.get('/', { depth });
74
-
75
- expect(mockFetch).toHaveBeenCalledWith(
76
- 'https://demo.dotcms.com/api/v1/nav/?depth=3',
77
- expect.anything()
78
- );
79
- });
80
-
81
- it('should normalize path by removing leading slash', async () => {
82
- const navClient = new NavigationClient(validConfig, requestOptions);
83
-
84
- await navClient.get('/about/');
85
-
86
- expect(mockFetch).toHaveBeenCalledWith(
87
- 'https://demo.dotcms.com/api/v1/nav/about/',
88
- expect.anything()
89
- );
90
- });
91
-
92
- it('should handle root path correctly', async () => {
93
- const navClient = new NavigationClient(validConfig, requestOptions);
94
-
95
- await navClient.get('/');
96
-
97
- expect(mockFetch).toHaveBeenCalledWith(
98
- 'https://demo.dotcms.com/api/v1/nav/',
99
- expect.anything()
100
- );
101
- });
102
-
103
- it('should handle fetch errors', async () => {
104
- mockFetch.mockRejectedValue(new Error('Network error'));
105
-
106
- const navClient = new NavigationClient(validConfig, requestOptions);
107
-
108
- await expect(navClient.get('/')).rejects.toThrow('Network error');
109
- });
110
-
111
- it('should handle non-OK responses', async () => {
112
- mockFetch.mockResolvedValue({
113
- ok: false,
114
- status: 404,
115
- statusText: 'Not Found'
116
- });
117
-
118
- const navClient = new NavigationClient(validConfig, requestOptions);
119
-
120
- await expect(navClient.get('/')).rejects.toThrow(
121
- `Failed to fetch navigation data: Not Found - 404`
122
- );
123
- });
124
-
125
- it('should include authorization headers in request', async () => {
126
- const navClient = new NavigationClient(validConfig, requestOptions);
127
-
128
- await navClient.get('/');
129
-
130
- expect(mockFetch).toHaveBeenCalledWith(
131
- expect.any(String),
132
- expect.objectContaining({
133
- headers: expect.objectContaining({
134
- Authorization: 'Bearer test-token'
135
- })
136
- })
137
- );
138
- });
139
-
140
- it('should merge additional request options', async () => {
141
- const optionsWithCache: RequestOptions = {
142
- ...requestOptions,
143
- cache: 'no-cache',
144
- credentials: 'include'
145
- };
146
-
147
- const navClient = new NavigationClient(validConfig, optionsWithCache);
148
-
149
- await navClient.get('/');
150
-
151
- expect(mockFetch).toHaveBeenCalledWith(
152
- 'https://demo.dotcms.com/api/v1/nav/',
153
- optionsWithCache
154
- );
155
- });
156
-
157
- it('should fetch navigation with multiple options', async () => {
158
- const navClient = new NavigationClient(validConfig, requestOptions);
159
-
160
- await navClient.get('/', { depth: 3, languageId: 2 });
161
-
162
- expect(mockFetch).toHaveBeenCalledWith(
163
- 'https://demo.dotcms.com/api/v1/nav/?depth=3&language_id=2',
164
- requestOptions
165
- );
166
- });
167
- });
@@ -1,62 +0,0 @@
1
- import {
2
- DotCMSClientConfig,
3
- DotCMSNavigationRequestParams,
4
- RequestOptions,
5
- DotCMSNavigationItem
6
- } from '@dotcms/types';
7
-
8
- export class NavigationClient {
9
- private requestOptions: RequestOptions;
10
-
11
- private BASE_URL: string;
12
-
13
- constructor(config: DotCMSClientConfig, requestOptions: RequestOptions) {
14
- this.requestOptions = requestOptions;
15
- this.BASE_URL = `${config?.dotcmsUrl}/api/v1/nav`;
16
- }
17
-
18
- /**
19
- * Retrieves information about the dotCMS file and folder tree.
20
- * @param {NavigationApiOptions} options - The options for the Navigation API call. Defaults to `{ depth: 0, path: '/', languageId: 1 }`.
21
- * @returns {Promise<DotCMSNavigationItem[]>} - A Promise that resolves to the response from the DotCMS API.
22
- * @throws {Error} - Throws an error if the options are not valid.
23
- */
24
- async get(
25
- path: string,
26
- params?: DotCMSNavigationRequestParams
27
- ): Promise<DotCMSNavigationItem[]> {
28
- if (!path) {
29
- throw new Error("The 'path' parameter is required for the Navigation API");
30
- }
31
-
32
- const navParams = params ? this.mapToBackendParams(params) : {};
33
- const urlParams = new URLSearchParams(navParams).toString();
34
-
35
- const parsedPath = path.replace(/^\/+/, '/').replace(/\/+$/, '/');
36
- const url = `${this.BASE_URL}${parsedPath}${urlParams ? `?${urlParams}` : ''}`;
37
-
38
- const response = await fetch(url, this.requestOptions);
39
-
40
- if (!response.ok) {
41
- throw new Error(
42
- `Failed to fetch navigation data: ${response.statusText} - ${response.status}`
43
- );
44
- }
45
-
46
- return response.json().then((data) => data.entity);
47
- }
48
-
49
- private mapToBackendParams(params: DotCMSNavigationRequestParams): Record<string, string> {
50
- const backendParams: Record<string, string> = {};
51
-
52
- if (params.depth) {
53
- backendParams['depth'] = String(params.depth);
54
- }
55
-
56
- if (params.languageId) {
57
- backendParams['language_id'] = String(params.languageId);
58
- }
59
-
60
- return backendParams;
61
- }
62
- }
@@ -1,359 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- jest.mock('consola');
3
-
4
- import * as consola from 'consola';
5
-
6
- import {
7
- DotCMSClientConfig,
8
- DotCMSPageRequestParams,
9
- RequestOptions,
10
- DotCMSGraphQLPageResponse,
11
- DotCMSPageResponse
12
- } from '@dotcms/types';
13
-
14
- import { PageClient } from './page-api';
15
- import * as utils from './utils';
16
-
17
- import { graphqlToPageEntity } from '../../utils';
18
-
19
- describe('PageClient', () => {
20
- const mockFetchGraphQL = jest.fn();
21
-
22
- const validConfig: DotCMSClientConfig = {
23
- dotcmsUrl: 'https://demo.dotcms.com',
24
- authToken: 'test-token',
25
- siteId: 'test-site'
26
- };
27
-
28
- const requestOptions: RequestOptions = {
29
- headers: {
30
- Authorization: 'Bearer test-token'
31
- }
32
- };
33
-
34
- const mockGraphQLResponse = {
35
- data: {
36
- page: {
37
- title: 'GraphQL Page',
38
- url: '/graphql-page'
39
- },
40
- testContent: {
41
- items: [{ title: 'Content Item' }]
42
- },
43
- testNav: {
44
- items: [{ label: 'Nav Item', url: '/nav' }]
45
- }
46
- },
47
- errors: null
48
- };
49
-
50
- beforeEach(() => {
51
- mockFetchGraphQL.mockReset();
52
- global.console.error = jest.fn(); // Mock console.error to prevent actual errors from being logged in the console when running tests
53
-
54
- jest.spyOn(utils, 'fetchGraphQL').mockImplementation(mockFetchGraphQL);
55
- mockFetchGraphQL.mockResolvedValue(mockGraphQLResponse);
56
-
57
- jest.spyOn(utils, 'buildPageQuery').mockReturnValue('mock-page-query');
58
- jest.spyOn(utils, 'buildQuery').mockReturnValue('mock-query');
59
- jest.spyOn(utils, 'mapResponseData').mockImplementation((data, keys) => {
60
- const result: Record<string, any> = {};
61
-
62
- keys.forEach((key) => {
63
- result[key] = data[`test${key.charAt(0).toUpperCase() + key.slice(1)}`];
64
- });
65
-
66
- return result;
67
- });
68
- });
69
-
70
- afterEach(() => {
71
- jest.restoreAllMocks();
72
- });
73
-
74
- describe('GraphQL API', () => {
75
- it('should fetch page using GraphQL when query option is provided', async () => {
76
- const pageClient = new PageClient(validConfig, requestOptions);
77
-
78
- const graphQLOptions: DotCMSPageRequestParams = {
79
- graphql: {
80
- page: `containers {
81
- containerContentlets {
82
- contentlets {
83
- ... on Banner {
84
- title
85
- }
86
- }
87
- }
88
- }`,
89
- content: { content: 'query Content { items { title } }' }
90
- },
91
- languageId: '1',
92
- mode: 'LIVE'
93
- };
94
-
95
- const result = await pageClient.get('/graphql-page', graphQLOptions);
96
-
97
- expect(utils.buildPageQuery).toHaveBeenCalled();
98
- expect(utils.buildQuery).toHaveBeenCalledTimes(1);
99
- expect(utils.fetchGraphQL).toHaveBeenCalledWith({
100
- body: expect.any(String),
101
- headers: requestOptions.headers,
102
- baseURL: 'https://demo.dotcms.com'
103
- });
104
-
105
- expect(result).toEqual({
106
- pageAsset: graphqlToPageEntity(
107
- mockGraphQLResponse.data as unknown as DotCMSGraphQLPageResponse
108
- ),
109
- content: { content: mockGraphQLResponse.data.testContent },
110
- graphql: {
111
- query: expect.any(String),
112
- variables: expect.any(Object)
113
- },
114
- vanityUrl: undefined,
115
- runningExperimentId: undefined
116
- });
117
- });
118
-
119
- it('should print graphql errors ', async () => {
120
- const consolaSpy = jest.spyOn(consola, 'error');
121
- const pageClient = new PageClient(validConfig, requestOptions);
122
- const graphQLOptions = {
123
- graphql: {
124
- page: `containers {
125
- containerContentlets {
126
- contentlets {
127
- ... on Banner {
128
- title
129
- }
130
- }
131
- }
132
- }`,
133
- content: { content: 'query Content { items { title } }' }
134
- }
135
- };
136
-
137
- mockFetchGraphQL.mockResolvedValue({
138
- data: {
139
- page: {
140
- title: 'GraphQL Page'
141
- }
142
- },
143
- errors: [{ message: 'Some internal server error' }]
144
- });
145
-
146
- await pageClient.get('/graphql-page', graphQLOptions);
147
-
148
- expect(consolaSpy).toHaveBeenCalledWith(
149
- '[DotCMS GraphQL Error]: ',
150
- 'Some internal server error'
151
- );
152
- });
153
-
154
- it('should return an error if the page is not found', async () => {
155
- const pageClient = new PageClient(validConfig, requestOptions);
156
- const graphQLOptions = {
157
- graphql: {
158
- page: `containers {
159
- containerContentlets {
160
- contentlets {
161
- ... on Banner {
162
- title
163
- }
164
- }
165
- }
166
- }`,
167
- content: { content: 'query Content { items { title } }' }
168
- }
169
- };
170
-
171
- mockFetchGraphQL.mockResolvedValue({
172
- data: {
173
- page: null
174
- },
175
- errors: [{ message: 'No page data found' }]
176
- });
177
-
178
- try {
179
- await pageClient.get('/graphql-page', graphQLOptions);
180
- } catch (response: unknown) {
181
- const responseData = response as DotCMSPageResponse;
182
-
183
- expect(responseData.error?.message).toBe('No page data found');
184
- }
185
- });
186
-
187
- it('should add leading slash to url if it does not have it', async () => {
188
- const pageClient = new PageClient(validConfig, requestOptions);
189
- const graphQLOptions = {
190
- graphql: {
191
- page: `containers {
192
- containerContentlets {
193
- contentlets {
194
- ... on Banner {
195
- title
196
- }
197
- }
198
- }
199
- }`,
200
- content: { content: 'query Content { items { title } }' }
201
- }
202
- };
203
-
204
- // No leading slash
205
- const result = await pageClient.get('graphql-page', graphQLOptions as any);
206
-
207
- expect(result).toEqual({
208
- pageAsset: graphqlToPageEntity(
209
- mockGraphQLResponse.data as unknown as DotCMSGraphQLPageResponse
210
- ),
211
- content: { content: mockGraphQLResponse.data.testContent },
212
- graphql: {
213
- query: expect.any(String),
214
- variables: expect.objectContaining({
215
- url: '/graphql-page'
216
- })
217
- },
218
- vanityUrl: undefined,
219
- runningExperimentId: undefined
220
- });
221
- });
222
-
223
- it('should pass correct variables to GraphQL query', async () => {
224
- const pageClient = new PageClient(validConfig, requestOptions);
225
- const graphQLOptions = {
226
- graphql: {
227
- page: `containers {
228
- containerContentlets {
229
- contentlets {
230
- ... on Banner {
231
- title
232
- }
233
- }
234
- }
235
- }`,
236
- content: { content: 'query Content { items { title } }' }
237
- },
238
- languageId: '2',
239
- mode: 'PREVIEW_MODE'
240
- };
241
-
242
- await pageClient.get('/custom-page', graphQLOptions as any);
243
-
244
- const requestBody = JSON.parse(mockFetchGraphQL.mock.calls[0][0].body);
245
- expect(requestBody.variables).toEqual({
246
- url: '/custom-page',
247
- mode: 'PREVIEW_MODE',
248
- languageId: '2',
249
- fireRules: false,
250
- siteId: 'test-site'
251
- });
252
- });
253
-
254
- it('should handle GraphQL errors', async () => {
255
- mockFetchGraphQL.mockRejectedValue(new Error('GraphQL error'));
256
-
257
- const pageClient = new PageClient(validConfig, requestOptions);
258
- const graphQLOptions = {
259
- graphql: {
260
- page: `containers {
261
- containerContentlets {
262
- contentlets {
263
- ... on Banner {
264
- title
265
- }
266
- }
267
- }
268
- }`,
269
- content: { content: 'query Content { items { title } }' }
270
- }
271
- };
272
- try {
273
- await pageClient.get('/page', graphQLOptions);
274
- } catch (error: any) {
275
- expect(error.message).toBe('Failed to retrieve page data');
276
- }
277
- });
278
-
279
- it('should throw errors from GraphQL', async () => {
280
- mockFetchGraphQL.mockResolvedValue({
281
- errors: [{ message: 'GraphQL error' }]
282
- });
283
-
284
- const pageClient = new PageClient(validConfig, requestOptions);
285
- const graphQLOptions = {
286
- graphql: {
287
- page: `containers {
288
- containerContentlets {
289
- contentlets {
290
- ... on Banner {
291
- title
292
- }
293
- }`,
294
- content: { content: 'query Content { items { title } }' }
295
- }
296
- };
297
- try {
298
- await pageClient.get('/page', graphQLOptions);
299
- } catch (error: any) {
300
- expect(error.message).toBe('Failed to retrieve page data');
301
- }
302
- });
303
-
304
- it('should use default values for languageId and mode if not provided', async () => {
305
- const pageClient = new PageClient(validConfig, requestOptions);
306
- const graphQLOptions = {
307
- graphql: {
308
- page: `containers {
309
- containerContentlets {
310
- contentlets {
311
- ... on Banner {
312
- title
313
- }
314
- }`,
315
- content: { content: 'query Content { items { title } }' }
316
- }
317
- };
318
- await pageClient.get('/default-page', graphQLOptions);
319
-
320
- const requestBody = JSON.parse(mockFetchGraphQL.mock.calls[0][0].body);
321
- expect(requestBody.variables).toEqual({
322
- url: '/default-page',
323
- mode: 'LIVE',
324
- languageId: '1',
325
- fireRules: false,
326
- siteId: 'test-site'
327
- });
328
- });
329
-
330
- it('should fetch using graphQL even if there is no graphql option', async () => {
331
- const pageClient = new PageClient(validConfig, requestOptions);
332
-
333
- await pageClient.get('/why-obi-wan-had-the-high-ground');
334
-
335
- expect(mockFetchGraphQL).toHaveBeenCalled();
336
- expect(utils.buildPageQuery).toHaveBeenCalled();
337
- expect(utils.buildQuery).toHaveBeenCalledTimes(1);
338
- expect(utils.fetchGraphQL).toHaveBeenCalledWith({
339
- body: expect.stringContaining('"url":"/why-obi-wan-had-the-high-ground"'),
340
- headers: requestOptions.headers,
341
- baseURL: 'https://demo.dotcms.com'
342
- });
343
- });
344
- });
345
-
346
- describe('Client initialization', () => {
347
- it('should use siteId from config when not provided in params', async () => {
348
- const pageClient = new PageClient(validConfig, requestOptions);
349
-
350
- await pageClient.get('/test-page');
351
-
352
- expect(mockFetchGraphQL).toHaveBeenCalledWith({
353
- baseURL: 'https://demo.dotcms.com',
354
- body: expect.stringContaining('"siteId":"test-site"'),
355
- headers: requestOptions.headers
356
- });
357
- });
358
- });
359
- });