@raketa-cloud/admin 1.8.10 → 1.8.11

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 (105) hide show
  1. package/dist/application.css +109 -0
  2. package/package.json +4 -2
  3. package/src/HonoAdapter.js +22 -13
  4. package/src/Logger.js +7 -8
  5. package/src/RaketaContext.js +1 -0
  6. package/src/cipher.js +2 -2
  7. package/src/cloud/ContentTasks.js +31 -0
  8. package/src/cloud/RaketaClient.js +1 -1
  9. package/src/cloud/Redirects.js +2 -2
  10. package/src/cloud/ResourceChanges.js +1 -1
  11. package/src/cloud/ResourceRevisions.js +2 -2
  12. package/src/cloud/Resources.js +28 -12
  13. package/src/cloud/Tags.js +4 -4
  14. package/src/cloud/documents/common.js +16 -0
  15. package/src/cloud/documents/contentTasksDocuments.js +59 -0
  16. package/src/cloud/documents/resourcesDocuments.js +12 -0
  17. package/src/filters.js +3 -3
  18. package/src/handlers/TagsHandler.js +2 -2
  19. package/src/handlers/_shared/getResourceUpdateDestination.js +1 -1
  20. package/src/handlers/categories/index.js +3 -3
  21. package/src/handlers/content_tasks/ContentTasksHandler.js +32 -0
  22. package/src/handlers/resource_revisions/LocksHandler.js +4 -1
  23. package/src/handlers/resources/ClonesHandler.js +1 -3
  24. package/src/handlers/resources/ExportsHandler.js +1 -5
  25. package/src/handlers/resources/ResourcesHandler.js +1 -1
  26. package/src/handlers/resources/TranslationsHandler.js +28 -19
  27. package/src/handlers/resources/URLsHandler.js +3 -1
  28. package/src/helpers/AuthHelper.js +1 -1
  29. package/src/helpers/FormBuilder.js +14 -14
  30. package/src/helpers/Pagination.js +5 -5
  31. package/src/helpers/historyUtils.js +3 -3
  32. package/src/helpers/utils.js +6 -1
  33. package/src/index.js +1 -0
  34. package/src/routeMember.js +9 -4
  35. package/src/routeNestedCollection.js +14 -29
  36. package/src/routeNestedMember.js +17 -6
  37. package/src/routeStandard.js +5 -1
  38. package/src/setupAuthentication.js +1 -1
  39. package/src/setupCloud.js +5 -0
  40. package/src/tests/Adapter.test.js +2 -2
  41. package/src/tests/HonoAdapter.coverage.test.js +44 -22
  42. package/src/tests/HonoAdapter.filter.test.js +28 -18
  43. package/src/tests/HonoAdapter.test.js +3 -3
  44. package/src/tests/RaketaClient.test.js +427 -413
  45. package/src/tests/RaketaContext.test.js +1 -1
  46. package/src/tests/buildResourcePath.test.js +1 -1
  47. package/src/tests/cipher.test.js +16 -16
  48. package/src/tests/filters.test.js +24 -24
  49. package/src/tests/handlers/RedirectsHandler.test/destroy.test.js +1 -1
  50. package/src/tests/handlers/TagsHandler.test/create.test.js +2 -2
  51. package/src/tests/handlers/TagsHandler.test/destroy.test.js +1 -1
  52. package/src/tests/handlers/TagsHandler.test/update.test.js +2 -2
  53. package/src/tests/handlers/categories/create.test.js +2 -2
  54. package/src/tests/handlers/categories/destroy.test.js +1 -1
  55. package/src/tests/handlers/content_tasks/ContentTasksHandler.test/index.test.js +161 -0
  56. package/src/tests/handlers/resource_revisions/CancelSchedulesHandler.test/create.test.js +2 -2
  57. package/src/tests/handlers/resource_revisions/CodeHandler.test/update.test.js +1 -1
  58. package/src/tests/handlers/resource_revisions/GeneralHandler.test/update.test.js +1 -1
  59. package/src/tests/handlers/resource_revisions/LocksHandler.test/create.test.js +5 -5
  60. package/src/tests/handlers/resource_revisions/LocksHandler.test/create_form.test.js +6 -2
  61. package/src/tests/handlers/resource_revisions/MetaHandler.test/update.test.js +1 -1
  62. package/src/tests/handlers/resource_revisions/PublishesHandler.test/create.test.js +5 -5
  63. package/src/tests/handlers/resource_revisions/ResourceRevisionsHandler.test/create.test.js +2 -2
  64. package/src/tests/handlers/resource_revisions/ResourceRevisionsHandler.test/destroy.test.js +1 -1
  65. package/src/tests/handlers/resource_revisions/RevertsHandler.test/create.test.js +18 -3
  66. package/src/tests/handlers/resource_revisions/TagHandler.test/update.test.js +1 -1
  67. package/src/tests/handlers/resource_revisions/UnlocksHandler.test/create.test.js +2 -2
  68. package/src/tests/handlers/resource_revisions/VisualHandler.test/update.test.js +1 -1
  69. package/src/tests/handlers/resource_revisions/WidgetHandler.test/update.test.js +2 -2
  70. package/src/tests/handlers/resources/ChangeHandler.test/show.test.js +7 -2
  71. package/src/tests/handlers/resources/ClonesHandler.test/create.test.js +1 -3
  72. package/src/tests/handlers/resources/ExportsHandler.test/index.test.js +8 -8
  73. package/src/tests/handlers/resources/HistoryHandler.test/index.test.js +1 -1
  74. package/src/tests/handlers/resources/ResourcesAPIHandler.test/index.test.js +1 -5
  75. package/src/tests/handlers/resources/ResourcesHandler.test/create.test.js +2 -2
  76. package/src/tests/handlers/resources/ResourcesHandler.test/show.test.js +1 -1
  77. package/src/tests/handlers/resources/TranslationsHandler.test/create.test.js +24 -14
  78. package/src/tests/handlers/resources/TranslationsHandler.test/create_form.test.js +1 -1
  79. package/src/tests/handlers/resources/TranslationsHandler.test/index.test.js +3 -3
  80. package/src/tests/handlers/resources/URLsHandler.test/create.test.js +4 -6
  81. package/src/tests/helpers/AuthHelper.test.js +11 -12
  82. package/src/tests/helpers/CSVExportHelper.test.js +3 -3
  83. package/src/tests/helpers/FormBuilder.test.js +21 -21
  84. package/src/tests/helpers/HTMLBuilder.test.js +4 -4
  85. package/src/tests/helpers/Inflector.test.js +1 -1
  86. package/src/tests/helpers/Pagination.test.js +1 -1
  87. package/src/tests/helpers/utils.test.js +46 -0
  88. package/src/tests/routeCategoriesModule.test.js +10 -5
  89. package/src/tests/routeCollection.test.js +1 -1
  90. package/src/tests/routeMember.test.js +2 -2
  91. package/src/tests/routeNestedCollection.test.js +3 -3
  92. package/src/tests/routeNestedMember.test.js +3 -3
  93. package/src/tests/routeResourceModule.test.js +15 -16
  94. package/src/tests/routeSettings.test.js +3 -3
  95. package/src/tests/routeStandard.test.js +27 -9
  96. package/src/tests/setupAuthentication.test.js +9 -6
  97. package/src/tests/support/factory.js +33 -0
  98. package/src/tests/utils.test.js +19 -19
  99. package/src/views/content_tasks/index.ejs +191 -0
  100. package/src/views/layouts/application.ejs +2 -1
  101. package/src/views/resources/_shared/_toolbar.ejs +33 -2
  102. package/src/views/resources/_shared/_translations_strip.ejs +71 -0
  103. package/src/views/resources/index.ejs +5 -0
  104. package/src/views/resources/show.ejs +1 -29
  105. package/src/views/resources/translations/create_form.ejs +13 -0
@@ -1,636 +1,650 @@
1
- import RaketaClient from '../cloud/RaketaClient'
2
- import { request } from 'graphql-request'
1
+ import RaketaClient from "../cloud/RaketaClient";
2
+ import { request } from "graphql-request";
3
3
 
4
- jest.mock('graphql-request', () => ({
4
+ jest.mock("graphql-request", () => ({
5
5
  request: jest.fn(),
6
- }))
6
+ }));
7
7
 
8
- describe('RaketaClient', () => {
8
+ describe("RaketaClient", () => {
9
9
  function buildMockConfig(overrides = {}) {
10
10
  return {
11
11
  cloud: {
12
- gateway_url: 'https://api.example.com',
13
- gateway_project: 'test-project',
14
- dxp_service_private: 'test-service',
12
+ gateway_url: "https://api.example.com",
13
+ gateway_project: "test-project",
14
+ dxp_service_private: "test-service",
15
15
  },
16
16
  ...overrides,
17
- }
17
+ };
18
18
  }
19
19
 
20
- function buildClient(config = buildMockConfig(), token = 'test-token') {
21
- const getConfig = () => config
22
- return new RaketaClient(getConfig, token)
20
+ function buildClient(config = buildMockConfig(), token = "test-token") {
21
+ const getConfig = () => config;
22
+ return new RaketaClient(getConfig, token);
23
23
  }
24
24
 
25
25
  beforeEach(() => {
26
- jest.clearAllMocks()
27
- })
28
-
29
- describe('constructor', () => {
30
- test('initializes with getConfig and token', () => {
31
- const getConfig = jest.fn(() => buildMockConfig())
32
- const client = new RaketaClient(getConfig, 'my-token')
33
-
34
- expect(client.getConfig).toBe(getConfig)
35
- expect(client.token).toBe('my-token')
36
- })
37
- })
38
-
39
- describe('gqlRequest', () => {
40
- test('makes GraphQL request with correct parameters', async () => {
41
- const client = buildClient()
42
- const query = 'query { test }'
43
- const variables = { id: '123' }
44
- const headers = { 'x-custom': 'value' }
45
-
46
- request.mockResolvedValue({ data: 'response' })
47
-
48
- await client.gqlRequest('https://api.example.com/graphql', query, variables, headers)
26
+ jest.clearAllMocks();
27
+ });
28
+
29
+ describe("constructor", () => {
30
+ test("initializes with getConfig and token", () => {
31
+ const getConfig = jest.fn(() => buildMockConfig());
32
+ const client = new RaketaClient(getConfig, "my-token");
33
+
34
+ expect(client.getConfig).toBe(getConfig);
35
+ expect(client.token).toBe("my-token");
36
+ });
37
+ });
38
+
39
+ describe("gqlRequest", () => {
40
+ test("makes GraphQL request with correct parameters", async () => {
41
+ const client = buildClient();
42
+ const query = "query { test }";
43
+ const variables = { id: "123" };
44
+ const headers = { "x-custom": "value" };
45
+
46
+ request.mockResolvedValue({ data: "response" });
47
+
48
+ await client.gqlRequest(
49
+ "https://api.example.com/graphql",
50
+ query,
51
+ variables,
52
+ headers,
53
+ );
49
54
 
50
55
  expect(request).toHaveBeenCalledWith({
51
- url: 'https://api.example.com/graphql',
56
+ url: "https://api.example.com/graphql",
52
57
  document: query,
53
58
  variables: variables,
54
59
  requestHeaders: headers,
55
- })
56
- })
60
+ });
61
+ });
57
62
 
58
- test('makes request with default empty variables and headers', async () => {
59
- const client = buildClient()
60
- const query = 'query { test }'
63
+ test("makes request with default empty variables and headers", async () => {
64
+ const client = buildClient();
65
+ const query = "query { test }";
61
66
 
62
- request.mockResolvedValue({ data: 'response' })
67
+ request.mockResolvedValue({ data: "response" });
63
68
 
64
- await client.gqlRequest('https://api.example.com/graphql', query)
69
+ await client.gqlRequest("https://api.example.com/graphql", query);
65
70
 
66
71
  expect(request).toHaveBeenCalledWith({
67
- url: 'https://api.example.com/graphql',
72
+ url: "https://api.example.com/graphql",
68
73
  document: query,
69
74
  variables: {},
70
75
  requestHeaders: {},
71
- })
72
- })
73
- })
76
+ });
77
+ });
78
+ });
74
79
 
75
- describe('query', () => {
76
- test('makes request to gateway with proper headers', async () => {
77
- const client = buildClient()
78
- const query = 'query { users }'
79
- const variables = { limit: 10 }
80
+ describe("query", () => {
81
+ test("makes request to gateway with proper headers", async () => {
82
+ const client = buildClient();
83
+ const query = "query { users }";
84
+ const variables = { limit: 10 };
80
85
 
81
- request.mockResolvedValue({ data: { users: [] } })
86
+ request.mockResolvedValue({ data: { users: [] } });
82
87
 
83
- await client.query(query, variables)
88
+ await client.query(query, variables);
84
89
 
85
90
  expect(request).toHaveBeenCalledWith({
86
- url: 'https://api.example.com/dispatch',
91
+ url: "https://api.example.com/dispatch",
87
92
  document: query,
88
93
  variables: variables,
89
94
  requestHeaders: {
90
- 'x-raketa-project': 'test-project',
91
- 'x-raketa-service': 'test-service',
92
- 'x-raketa-identity': 'test-token',
95
+ "x-raketa-project": "test-project",
96
+ "x-raketa-service": "test-service",
97
+ "x-raketa-identity": "test-token",
93
98
  },
94
- })
95
- })
99
+ });
100
+ });
96
101
 
97
- test('uses token from constructor in headers', async () => {
98
- const client = buildClient(buildMockConfig(), 'custom-token-123')
99
- const query = 'query { test }'
102
+ test("uses token from constructor in headers", async () => {
103
+ const client = buildClient(buildMockConfig(), "custom-token-123");
104
+ const query = "query { test }";
100
105
 
101
- request.mockResolvedValue({ data: {} })
106
+ request.mockResolvedValue({ data: {} });
102
107
 
103
- await client.query(query)
108
+ await client.query(query);
104
109
 
105
110
  expect(request).toHaveBeenCalledWith(
106
111
  expect.objectContaining({
107
112
  requestHeaders: expect.objectContaining({
108
- 'x-raketa-identity': 'custom-token-123',
113
+ "x-raketa-identity": "custom-token-123",
109
114
  }),
110
- })
111
- )
112
- })
113
- })
115
+ }),
116
+ );
117
+ });
118
+ });
114
119
 
115
- describe('logError', () => {
116
- test('throws error with message', () => {
117
- const client = buildClient()
118
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
120
+ describe("logError", () => {
121
+ test("throws error with message", () => {
122
+ const client = buildClient();
123
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
119
124
 
120
- expect(() => client.logError('Something went wrong')).toThrow('Something went wrong')
125
+ expect(() => client.logError("Something went wrong")).toThrow(
126
+ "Something went wrong",
127
+ );
121
128
 
122
- consoleSpy.mockRestore()
123
- })
129
+ consoleSpy.mockRestore();
130
+ });
124
131
 
125
- test('logs context to console when provided', () => {
126
- const client = buildClient()
127
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
128
- const context = { code: 'ERR_001', details: 'Invalid input' }
132
+ test("logs context to console when provided", () => {
133
+ const client = buildClient();
134
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
135
+ const context = { code: "ERR_001", details: "Invalid input" };
129
136
 
130
- expect(() => client.logError('Error occurred', context)).toThrow('Error occurred')
131
- expect(consoleSpy).toHaveBeenCalledWith(context)
137
+ expect(() => client.logError("Error occurred", context)).toThrow(
138
+ "Error occurred",
139
+ );
140
+ expect(consoleSpy).toHaveBeenCalledWith(context);
132
141
 
133
- consoleSpy.mockRestore()
134
- })
142
+ consoleSpy.mockRestore();
143
+ });
135
144
 
136
- test('does not log when context is not provided', () => {
137
- const client = buildClient()
138
- const consoleSpy = jest.spyOn(console, 'error').mockImplementation()
145
+ test("does not log when context is not provided", () => {
146
+ const client = buildClient();
147
+ const consoleSpy = jest.spyOn(console, "error").mockImplementation();
139
148
 
140
- expect(() => client.logError('Error occurred')).toThrow('Error occurred')
141
- expect(consoleSpy).not.toHaveBeenCalled()
149
+ expect(() => client.logError("Error occurred")).toThrow("Error occurred");
150
+ expect(consoleSpy).not.toHaveBeenCalled();
142
151
 
143
- consoleSpy.mockRestore()
144
- })
145
- })
152
+ consoleSpy.mockRestore();
153
+ });
154
+ });
146
155
 
147
- describe('formatErrors', () => {
148
- test('formats single error into object', () => {
149
- const client = buildClient()
150
- const errors = [{ key: 'email', message: 'Email is invalid' }]
156
+ describe("formatErrors", () => {
157
+ test("formats single error into object", () => {
158
+ const client = buildClient();
159
+ const errors = [{ key: "email", message: "Email is invalid" }];
151
160
 
152
- const result = client.formatErrors(errors)
161
+ const result = client.formatErrors(errors);
153
162
 
154
163
  expect(result).toEqual({
155
- email: 'Email is invalid',
156
- })
157
- })
164
+ email: "Email is invalid",
165
+ });
166
+ });
158
167
 
159
- test('formats multiple errors for different keys', () => {
160
- const client = buildClient()
168
+ test("formats multiple errors for different keys", () => {
169
+ const client = buildClient();
161
170
  const errors = [
162
- { key: 'email', message: 'Email is required' },
163
- { key: 'password', message: 'Password is too short' },
164
- { key: 'username', message: 'Username is taken' },
165
- ]
171
+ { key: "email", message: "Email is required" },
172
+ { key: "password", message: "Password is too short" },
173
+ { key: "username", message: "Username is taken" },
174
+ ];
166
175
 
167
- const result = client.formatErrors(errors)
176
+ const result = client.formatErrors(errors);
168
177
 
169
178
  expect(result).toEqual({
170
- email: 'Email is required',
171
- password: 'Password is too short',
172
- username: 'Username is taken',
173
- })
174
- })
175
-
176
- test('concatenates multiple messages for same key', () => {
177
- const client = buildClient()
179
+ email: "Email is required",
180
+ password: "Password is too short",
181
+ username: "Username is taken",
182
+ });
183
+ });
184
+
185
+ test("concatenates multiple messages for same key", () => {
186
+ const client = buildClient();
178
187
  const errors = [
179
- { key: 'email', message: 'Email is required' },
180
- { key: 'email', message: 'Email format is invalid' },
181
- { key: 'password', message: 'Password is required' },
182
- ]
188
+ { key: "email", message: "Email is required" },
189
+ { key: "email", message: "Email format is invalid" },
190
+ { key: "password", message: "Password is required" },
191
+ ];
183
192
 
184
- const result = client.formatErrors(errors)
193
+ const result = client.formatErrors(errors);
185
194
 
186
195
  expect(result).toEqual({
187
- email: 'Email is required, Email format is invalid',
188
- password: 'Password is required',
189
- })
190
- })
196
+ email: "Email is required, Email format is invalid",
197
+ password: "Password is required",
198
+ });
199
+ });
191
200
 
192
- test('remaps generalError to specified key', () => {
193
- const client = buildClient()
201
+ test("remaps generalError to specified key", () => {
202
+ const client = buildClient();
194
203
  const errors = [
195
- { key: 'generalError', message: 'Something went wrong' },
196
- { key: 'email', message: 'Email is invalid' },
197
- ]
204
+ { key: "generalError", message: "Something went wrong" },
205
+ { key: "email", message: "Email is invalid" },
206
+ ];
198
207
 
199
- const result = client.formatErrors(errors, 'base')
208
+ const result = client.formatErrors(errors, "base");
200
209
 
201
210
  expect(result).toEqual({
202
- base: 'Something went wrong',
203
- email: 'Email is invalid',
204
- })
205
- })
211
+ base: "Something went wrong",
212
+ email: "Email is invalid",
213
+ });
214
+ });
206
215
 
207
- test('keeps generalError key when no remap specified', () => {
208
- const client = buildClient()
209
- const errors = [{ key: 'generalError', message: 'Operation failed' }]
216
+ test("keeps generalError key when no remap specified", () => {
217
+ const client = buildClient();
218
+ const errors = [{ key: "generalError", message: "Operation failed" }];
210
219
 
211
- const result = client.formatErrors(errors)
220
+ const result = client.formatErrors(errors);
212
221
 
213
222
  expect(result).toEqual({
214
- generalError: 'Operation failed',
215
- })
216
- })
223
+ generalError: "Operation failed",
224
+ });
225
+ });
217
226
 
218
- test('handles empty errors array', () => {
219
- const client = buildClient()
220
- const result = client.formatErrors([])
227
+ test("handles empty errors array", () => {
228
+ const client = buildClient();
229
+ const result = client.formatErrors([]);
221
230
 
222
- expect(result).toEqual({})
223
- })
224
- })
231
+ expect(result).toEqual({});
232
+ });
233
+ });
225
234
 
226
- describe('buildFiltersInput', () => {
227
- test('extracts filters with f: prefix', () => {
228
- const client = buildClient()
235
+ describe("buildFiltersInput", () => {
236
+ test("extracts filters with f: prefix", () => {
237
+ const client = buildClient();
229
238
  const query = {
230
- 'f:status': 'active',
231
- 'f:category': 'news',
232
- page: '2',
233
- order_by: 'created_at',
234
- }
239
+ "f:status": "active",
240
+ "f:category": "news",
241
+ page: "2",
242
+ order_by: "created_at",
243
+ };
235
244
 
236
- const result = client.buildFiltersInput(query)
245
+ const result = client.buildFiltersInput(query);
237
246
 
238
247
  expect(result).toEqual({
239
- status: 'active',
240
- category: 'news',
241
- })
242
- })
248
+ status: "active",
249
+ category: "news",
250
+ });
251
+ });
243
252
 
244
- test('ignores filters with empty values', () => {
245
- const client = buildClient()
253
+ test("ignores filters with empty values", () => {
254
+ const client = buildClient();
246
255
  const query = {
247
- 'f:status': 'active',
248
- 'f:category': '',
249
- 'f:tag': null,
250
- 'f:author': undefined,
251
- }
256
+ "f:status": "active",
257
+ "f:category": "",
258
+ "f:tag": null,
259
+ "f:author": undefined,
260
+ };
252
261
 
253
- const result = client.buildFiltersInput(query)
262
+ const result = client.buildFiltersInput(query);
254
263
 
255
264
  expect(result).toEqual({
256
- status: 'active',
257
- })
258
- })
265
+ status: "active",
266
+ });
267
+ });
259
268
 
260
- test('returns empty object when no filters present', () => {
261
- const client = buildClient()
269
+ test("returns empty object when no filters present", () => {
270
+ const client = buildClient();
262
271
  const query = {
263
- page: '1',
264
- order_by: 'title',
265
- }
272
+ page: "1",
273
+ order_by: "title",
274
+ };
266
275
 
267
- const result = client.buildFiltersInput(query)
276
+ const result = client.buildFiltersInput(query);
268
277
 
269
- expect(result).toEqual({})
270
- })
278
+ expect(result).toEqual({});
279
+ });
271
280
 
272
- test('returns empty object when query is null or undefined', () => {
273
- const client = buildClient()
281
+ test("returns empty object when query is null or undefined", () => {
282
+ const client = buildClient();
274
283
 
275
- expect(client.buildFiltersInput(null)).toEqual({})
276
- expect(client.buildFiltersInput(undefined)).toEqual({})
277
- })
284
+ expect(client.buildFiltersInput(null)).toEqual({});
285
+ expect(client.buildFiltersInput(undefined)).toEqual({});
286
+ });
278
287
 
279
- test('returns empty object when only page param exists', () => {
280
- const client = buildClient()
281
- const query = { page: '3' }
288
+ test("returns empty object when only page param exists", () => {
289
+ const client = buildClient();
290
+ const query = { page: "3" };
282
291
 
283
- const result = client.buildFiltersInput(query)
292
+ const result = client.buildFiltersInput(query);
284
293
 
285
- expect(result).toEqual({})
286
- })
287
- })
294
+ expect(result).toEqual({});
295
+ });
296
+ });
288
297
 
289
- describe('buildOrderInput', () => {
290
- test('builds order object with field and direction', () => {
291
- const client = buildClient()
298
+ describe("buildOrderInput", () => {
299
+ test("builds order object with field and direction", () => {
300
+ const client = buildClient();
292
301
  const query = {
293
- order_by: 'created_at',
294
- order_direction: 'DESC',
295
- }
302
+ order_by: "created_at",
303
+ order_direction: "DESC",
304
+ };
296
305
 
297
- const result = client.buildOrderInput(query)
306
+ const result = client.buildOrderInput(query);
298
307
 
299
308
  expect(result).toEqual({
300
- field: 'created_at',
301
- direction: 'DESC',
302
- })
303
- })
309
+ field: "created_at",
310
+ direction: "DESC",
311
+ });
312
+ });
304
313
 
305
- test('defaults to ASC when direction not provided', () => {
306
- const client = buildClient()
307
- const query = { order_by: 'title' }
314
+ test("defaults to ASC when direction not provided", () => {
315
+ const client = buildClient();
316
+ const query = { order_by: "title" };
308
317
 
309
- const result = client.buildOrderInput(query)
318
+ const result = client.buildOrderInput(query);
310
319
 
311
320
  expect(result).toEqual({
312
- field: 'title',
313
- direction: 'ASC',
314
- })
315
- })
321
+ field: "title",
322
+ direction: "ASC",
323
+ });
324
+ });
316
325
 
317
- test('returns null when order_by not provided', () => {
318
- const client = buildClient()
319
- const query = { order_direction: 'DESC' }
326
+ test("returns null when order_by not provided", () => {
327
+ const client = buildClient();
328
+ const query = { order_direction: "DESC" };
320
329
 
321
- const result = client.buildOrderInput(query)
330
+ const result = client.buildOrderInput(query);
322
331
 
323
- expect(result).toBeNull()
324
- })
332
+ expect(result).toBeNull();
333
+ });
325
334
 
326
- test('returns null when order_by is empty string', () => {
327
- const client = buildClient()
328
- const query = { order_by: '' }
335
+ test("returns null when order_by is empty string", () => {
336
+ const client = buildClient();
337
+ const query = { order_by: "" };
329
338
 
330
- const result = client.buildOrderInput(query)
339
+ const result = client.buildOrderInput(query);
331
340
 
332
- expect(result).toBeNull()
333
- })
334
- })
341
+ expect(result).toBeNull();
342
+ });
343
+ });
335
344
 
336
- describe('buildPaginationInput', () => {
337
- test('builds pagination with page number from query', () => {
338
- const client = buildClient()
339
- const query = { page: '3' }
345
+ describe("buildPaginationInput", () => {
346
+ test("builds pagination with page number from query", () => {
347
+ const client = buildClient();
348
+ const query = { page: "3" };
340
349
 
341
- const result = client.buildPaginationInput(query)
350
+ const result = client.buildPaginationInput(query);
342
351
 
343
352
  expect(result).toEqual({
344
353
  page: 3,
345
354
  pageSize: 25,
346
- })
347
- })
355
+ });
356
+ });
348
357
 
349
- test('defaults to page 1 when not provided', () => {
350
- const client = buildClient()
351
- const query = {}
358
+ test("defaults to page 1 when not provided", () => {
359
+ const client = buildClient();
360
+ const query = {};
352
361
 
353
- const result = client.buildPaginationInput(query)
362
+ const result = client.buildPaginationInput(query);
354
363
 
355
364
  expect(result).toEqual({
356
365
  page: 1,
357
366
  pageSize: 25,
358
- })
359
- })
367
+ });
368
+ });
360
369
 
361
- test('parses string page number to integer', () => {
362
- const client = buildClient()
363
- const query = { page: '10' }
370
+ test("parses string page number to integer", () => {
371
+ const client = buildClient();
372
+ const query = { page: "10" };
364
373
 
365
- const result = client.buildPaginationInput(query)
374
+ const result = client.buildPaginationInput(query);
366
375
 
367
- expect(result.page).toBe(10)
368
- expect(typeof result.page).toBe('number')
369
- })
376
+ expect(result.page).toBe(10);
377
+ expect(typeof result.page).toBe("number");
378
+ });
370
379
 
371
- test('handles invalid page values by defaulting to 1', () => {
372
- const client = buildClient()
380
+ test("handles invalid page values by defaulting to 1", () => {
381
+ const client = buildClient();
373
382
 
374
- expect(client.buildPaginationInput({ page: 'invalid' })).toEqual({
383
+ expect(client.buildPaginationInput({ page: "invalid" })).toEqual({
375
384
  page: NaN,
376
385
  pageSize: 25,
377
- })
378
- })
379
- })
386
+ });
387
+ });
388
+ });
380
389
 
381
- describe('buildListInput', () => {
382
- test('builds complete input with pagination, filters, orderBy, and locale', () => {
383
- const client = buildClient()
390
+ describe("buildListInput", () => {
391
+ test("builds complete input with pagination, filters, orderBy, and locale", () => {
392
+ const client = buildClient();
384
393
  const query = {
385
- page: '2',
386
- 'f:status': 'published',
387
- 'f:category': 'tech',
388
- order_by: 'created_at',
389
- order_direction: 'DESC',
390
- }
394
+ page: "2",
395
+ "f:status": "published",
396
+ "f:category": "tech",
397
+ order_by: "created_at",
398
+ order_direction: "DESC",
399
+ };
391
400
 
392
- const result = client.buildListInput(query, 'en')
401
+ const result = client.buildListInput(query, "en");
393
402
 
394
403
  expect(result).toEqual({
395
404
  input: {
396
405
  pagination: { page: 2, pageSize: 25 },
397
- filters: { status: 'published', category: 'tech' },
398
- orderBy: { field: 'created_at', direction: 'DESC' },
399
- locale: 'en',
406
+ filters: { status: "published", category: "tech" },
407
+ orderBy: { field: "created_at", direction: "DESC" },
408
+ locale: "en",
400
409
  },
401
- })
402
- })
410
+ });
411
+ });
403
412
 
404
- test('omits orderBy when not provided', () => {
405
- const client = buildClient()
406
- const query = { page: '1', 'f:status': 'active' }
413
+ test("omits orderBy when not provided", () => {
414
+ const client = buildClient();
415
+ const query = { page: "1", "f:status": "active" };
407
416
 
408
- const result = client.buildListInput(query)
417
+ const result = client.buildListInput(query);
409
418
 
410
419
  expect(result).toEqual({
411
420
  input: {
412
421
  pagination: { page: 1, pageSize: 25 },
413
- filters: { status: 'active' },
422
+ filters: { status: "active" },
414
423
  },
415
- })
416
- })
424
+ });
425
+ });
417
426
 
418
- test('omits locale when not provided', () => {
419
- const client = buildClient()
420
- const query = { page: '1' }
427
+ test("omits locale when not provided", () => {
428
+ const client = buildClient();
429
+ const query = { page: "1" };
421
430
 
422
- const result = client.buildListInput(query)
431
+ const result = client.buildListInput(query);
423
432
 
424
- expect(result.input).not.toHaveProperty('locale')
425
- })
433
+ expect(result.input).not.toHaveProperty("locale");
434
+ });
426
435
 
427
- test('includes locale when provided', () => {
428
- const client = buildClient()
429
- const query = { page: '1' }
436
+ test("includes locale when provided", () => {
437
+ const client = buildClient();
438
+ const query = { page: "1" };
430
439
 
431
- const result = client.buildListInput(query, 'de')
440
+ const result = client.buildListInput(query, "de");
432
441
 
433
- expect(result.input.locale).toBe('de')
434
- })
442
+ expect(result.input.locale).toBe("de");
443
+ });
435
444
 
436
- test('handles empty query object', () => {
437
- const client = buildClient()
445
+ test("handles empty query object", () => {
446
+ const client = buildClient();
438
447
 
439
- const result = client.buildListInput({})
448
+ const result = client.buildListInput({});
440
449
 
441
450
  expect(result).toEqual({
442
451
  input: {
443
452
  pagination: { page: 1, pageSize: 25 },
444
453
  filters: {},
445
454
  },
446
- })
447
- })
448
- })
455
+ });
456
+ });
457
+ });
449
458
 
450
- describe('buildAllInput', () => {
451
- test('builds input without pagination', () => {
452
- const client = buildClient()
459
+ describe("buildAllInput", () => {
460
+ test("builds input without pagination", () => {
461
+ const client = buildClient();
453
462
  const query = {
454
- page: '2',
455
- 'f:status': 'active',
456
- order_by: 'title',
457
- order_direction: 'ASC',
458
- }
463
+ page: "2",
464
+ "f:status": "active",
465
+ order_by: "title",
466
+ order_direction: "ASC",
467
+ };
459
468
 
460
- const result = client.buildAllInput(query, 'fr')
469
+ const result = client.buildAllInput(query, "fr");
461
470
 
462
471
  expect(result).toEqual({
463
472
  input: {
464
- filters: { status: 'active' },
465
- orderBy: { field: 'title', direction: 'ASC' },
466
- locale: 'fr',
473
+ filters: { status: "active" },
474
+ orderBy: { field: "title", direction: "ASC" },
475
+ locale: "fr",
467
476
  },
468
- })
469
- expect(result.input).not.toHaveProperty('pagination')
470
- })
477
+ });
478
+ expect(result.input).not.toHaveProperty("pagination");
479
+ });
471
480
 
472
- test('omits orderBy when not provided', () => {
473
- const client = buildClient()
474
- const query = { 'f:category': 'news' }
481
+ test("omits orderBy when not provided", () => {
482
+ const client = buildClient();
483
+ const query = { "f:category": "news" };
475
484
 
476
- const result = client.buildAllInput(query)
485
+ const result = client.buildAllInput(query);
477
486
 
478
487
  expect(result).toEqual({
479
488
  input: {
480
- filters: { category: 'news' },
489
+ filters: { category: "news" },
481
490
  },
482
- })
483
- })
491
+ });
492
+ });
484
493
 
485
- test('omits locale when not provided', () => {
486
- const client = buildClient()
487
- const query = {}
494
+ test("omits locale when not provided", () => {
495
+ const client = buildClient();
496
+ const query = {};
488
497
 
489
- const result = client.buildAllInput(query)
498
+ const result = client.buildAllInput(query);
490
499
 
491
- expect(result.input).not.toHaveProperty('locale')
492
- })
493
- })
500
+ expect(result.input).not.toHaveProperty("locale");
501
+ });
502
+ });
494
503
 
495
- describe('deepMerge', () => {
496
- test('merges two simple objects', () => {
497
- const client = buildClient()
498
- const target = { a: 1, b: 2 }
499
- const source = { b: 3, c: 4 }
504
+ describe("deepMerge", () => {
505
+ test("merges two simple objects", () => {
506
+ const client = buildClient();
507
+ const target = { a: 1, b: 2 };
508
+ const source = { b: 3, c: 4 };
500
509
 
501
- const result = client.deepMerge(target, source)
510
+ const result = client.deepMerge(target, source);
502
511
 
503
- expect(result).toEqual({ a: 1, b: 3, c: 4 })
512
+ expect(result).toEqual({ a: 1, b: 3, c: 4 });
504
513
  // Verify original is not modified
505
- expect(target).toEqual({ a: 1, b: 2 })
506
- })
514
+ expect(target).toEqual({ a: 1, b: 2 });
515
+ });
507
516
 
508
- test('merges nested objects deeply', () => {
509
- const client = buildClient()
517
+ test("merges nested objects deeply", () => {
518
+ const client = buildClient();
510
519
  const target = {
511
- settings: { theme: 'dark', locale: 'en' },
512
- profile: { name: 'John' },
513
- }
520
+ settings: { theme: "dark", locale: "en" },
521
+ profile: { name: "John" },
522
+ };
514
523
  const source = {
515
- settings: { locale: 'fr', notifications: true },
524
+ settings: { locale: "fr", notifications: true },
516
525
  profile: { age: 30 },
517
- }
526
+ };
518
527
 
519
- const result = client.deepMerge(target, source)
528
+ const result = client.deepMerge(target, source);
520
529
 
521
530
  expect(result).toEqual({
522
- settings: { theme: 'dark', locale: 'fr', notifications: true },
523
- profile: { name: 'John', age: 30 },
524
- })
525
- })
531
+ settings: { theme: "dark", locale: "fr", notifications: true },
532
+ profile: { name: "John", age: 30 },
533
+ });
534
+ });
526
535
 
527
- test('replaces arrays instead of merging', () => {
528
- const client = buildClient()
529
- const target = { tags: ['javascript', 'node'] }
530
- const source = { tags: ['typescript', 'deno'] }
536
+ test("replaces arrays instead of merging", () => {
537
+ const client = buildClient();
538
+ const target = { tags: ["javascript", "node"] };
539
+ const source = { tags: ["typescript", "deno"] };
531
540
 
532
- const result = client.deepMerge(target, source)
541
+ const result = client.deepMerge(target, source);
533
542
 
534
- expect(result).toEqual({ tags: ['typescript', 'deno'] })
535
- })
543
+ expect(result).toEqual({ tags: ["typescript", "deno"] });
544
+ });
536
545
 
537
- test('parses JSON strings in source', () => {
538
- const client = buildClient()
539
- const target = { config: {} }
540
- const source = { config: '{"enabled": true, "count": 5}' }
546
+ test("parses JSON strings in source", () => {
547
+ const client = buildClient();
548
+ const target = { config: {} };
549
+ const source = { config: '{"enabled": true, "count": 5}' };
541
550
 
542
- const result = client.deepMerge(target, source)
551
+ const result = client.deepMerge(target, source);
543
552
 
544
- expect(result.config).toEqual({ enabled: true, count: 5 })
545
- })
553
+ expect(result.config).toEqual({ enabled: true, count: 5 });
554
+ });
546
555
 
547
- test('parses JSON strings in nested objects', () => {
548
- const client = buildClient()
549
- const target = { settings: { meta: {} } }
550
- const source = { settings: { meta: '{"title": "Test", "tags": ["a", "b"]}' } }
556
+ test("parses JSON strings in nested objects", () => {
557
+ const client = buildClient();
558
+ const target = { settings: { meta: {} } };
559
+ const source = {
560
+ settings: { meta: '{"title": "Test", "tags": ["a", "b"]}' },
561
+ };
551
562
 
552
- const result = client.deepMerge(target, source)
563
+ const result = client.deepMerge(target, source);
553
564
 
554
- expect(result.settings.meta).toEqual({ title: 'Test', tags: ['a', 'b'] })
555
- })
565
+ expect(result.settings.meta).toEqual({ title: "Test", tags: ["a", "b"] });
566
+ });
556
567
 
557
- test('handles null values', () => {
558
- const client = buildClient()
559
- const target = { a: 1, b: null }
560
- const source = { b: 2, c: null }
568
+ test("handles null values", () => {
569
+ const client = buildClient();
570
+ const target = { a: 1, b: null };
571
+ const source = { b: 2, c: null };
561
572
 
562
- const result = client.deepMerge(target, source)
573
+ const result = client.deepMerge(target, source);
563
574
 
564
- expect(result).toEqual({ a: 1, b: 2, c: null })
565
- })
575
+ expect(result).toEqual({ a: 1, b: 2, c: null });
576
+ });
566
577
 
567
- test('does not modify target object', () => {
568
- const client = buildClient()
569
- const target = { nested: { value: 'original' } }
570
- const source = { nested: { value: 'modified' } }
578
+ test("does not modify target object", () => {
579
+ const client = buildClient();
580
+ const target = { nested: { value: "original" } };
581
+ const source = { nested: { value: "modified" } };
571
582
 
572
- client.deepMerge(target, source)
583
+ client.deepMerge(target, source);
573
584
 
574
- expect(target.nested.value).toBe('original')
575
- })
585
+ expect(target.nested.value).toBe("original");
586
+ });
576
587
 
577
- test('handles deeply nested JSON strings', () => {
578
- const client = buildClient()
588
+ test("handles deeply nested JSON strings", () => {
589
+ const client = buildClient();
579
590
  const target = {
580
591
  data: {
581
592
  user: {
582
593
  preferences: {},
583
594
  },
584
595
  },
585
- }
596
+ };
586
597
  const source = {
587
598
  data: {
588
599
  user: {
589
600
  preferences: '{"theme": "dark", "language": "en"}',
590
601
  },
591
602
  },
592
- }
603
+ };
593
604
 
594
- const result = client.deepMerge(target, source)
605
+ const result = client.deepMerge(target, source);
595
606
 
596
607
  expect(result.data.user.preferences).toEqual({
597
- theme: 'dark',
598
- language: 'en',
599
- })
600
- })
601
-
602
- test('handles array of objects with JSON strings', () => {
603
- const client = buildClient()
604
- const target = { items: [] }
608
+ theme: "dark",
609
+ language: "en",
610
+ });
611
+ });
612
+
613
+ test("handles array of objects with JSON strings", () => {
614
+ const client = buildClient();
615
+ const target = { items: [] };
605
616
  const source = {
606
- items: [{ id: 1, data: '{"active": true}' }, { id: 2, data: '{"active": false}' }],
607
- }
617
+ items: [
618
+ { id: 1, data: '{"active": true}' },
619
+ { id: 2, data: '{"active": false}' },
620
+ ],
621
+ };
608
622
 
609
- const result = client.deepMerge(target, source)
623
+ const result = client.deepMerge(target, source);
610
624
 
611
- expect(result.items[0].data).toEqual({ active: true })
612
- expect(result.items[1].data).toEqual({ active: false })
613
- })
625
+ expect(result.items[0].data).toEqual({ active: true });
626
+ expect(result.items[1].data).toEqual({ active: false });
627
+ });
614
628
 
615
- test('preserves non-JSON strings', () => {
616
- const client = buildClient()
617
- const target = { title: 'old' }
618
- const source = { title: 'new title', description: 'just a string' }
629
+ test("preserves non-JSON strings", () => {
630
+ const client = buildClient();
631
+ const target = { title: "old" };
632
+ const source = { title: "new title", description: "just a string" };
619
633
 
620
- const result = client.deepMerge(target, source)
634
+ const result = client.deepMerge(target, source);
621
635
 
622
636
  expect(result).toEqual({
623
- title: 'new title',
624
- description: 'just a string',
625
- })
626
- })
627
-
628
- test('handles empty objects', () => {
629
- const client = buildClient()
630
-
631
- expect(client.deepMerge({}, { a: 1 })).toEqual({ a: 1 })
632
- expect(client.deepMerge({ a: 1 }, {})).toEqual({ a: 1 })
633
- expect(client.deepMerge({}, {})).toEqual({})
634
- })
635
- })
636
- })
637
+ title: "new title",
638
+ description: "just a string",
639
+ });
640
+ });
641
+
642
+ test("handles empty objects", () => {
643
+ const client = buildClient();
644
+
645
+ expect(client.deepMerge({}, { a: 1 })).toEqual({ a: 1 });
646
+ expect(client.deepMerge({ a: 1 }, {})).toEqual({ a: 1 });
647
+ expect(client.deepMerge({}, {})).toEqual({});
648
+ });
649
+ });
650
+ });