core-services-sdk 1.3.83 → 1.3.84

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "core-services-sdk",
3
- "version": "1.3.83",
3
+ "version": "1.3.84",
4
4
  "main": "src/index.js",
5
5
  "type": "module",
6
6
  "types": "types/index.d.ts",
@@ -1,7 +1,8 @@
1
1
  export const HTTP_METHODS = Object.freeze({
2
2
  GET: 'GET',
3
- POST: 'POST',
4
3
  PUT: 'PUT',
4
+ HEAD: 'HEAD',
5
+ POST: 'POST',
5
6
  PATCH: 'PATCH',
6
7
  DELETE: 'DELETE',
7
8
  })
package/src/http/http.js CHANGED
@@ -55,6 +55,13 @@
55
55
  * @property {ResponseTypeValue} [expectedType] - Expected response type.
56
56
  */
57
57
 
58
+ /**
59
+ * @typedef {Object} HttpHeadOptions
60
+ * @property {string} url - The URL to send the request to.
61
+ * @property {Record<string, string>} [headers] - Optional HTTP headers.
62
+ * @property {RequestInit} [extraParams] - Additional fetch options.
63
+ */
64
+
58
65
  import httpStatus from 'http-status'
59
66
  import { parseStringPromise } from 'xml2js'
60
67
 
@@ -294,6 +301,25 @@ export const deleteApi = async ({
294
301
  return getResponsePayload(response, expectedType)
295
302
  }
296
303
 
304
+ /**
305
+ * Sends an HTTP HEAD request.
306
+ *
307
+ * @param {HttpHeadOptions} options - The request options.
308
+ * @returns {Promise<Response>} The raw fetch response (headers only).
309
+ * @throws {HttpError} If the response status is not successful.
310
+ */
311
+ export const head = async ({ url, headers = {}, extraParams = {} }) => {
312
+ const response = await fetch(url, {
313
+ ...extraParams,
314
+ method: HTTP_METHODS.HEAD,
315
+ headers: { ...JSON_HEADER, ...headers },
316
+ })
317
+
318
+ await checkStatus(response)
319
+
320
+ return response
321
+ }
322
+
297
323
  /**
298
324
  * Consolidated HTTP client with methods for common HTTP operations.
299
325
  *
@@ -302,13 +328,16 @@ export const deleteApi = async ({
302
328
  * put: (options: HttpPutOptions) => Promise<any>,
303
329
  * post: (options: HttpPostOptions) => Promise<any>,
304
330
  * patch: (options: HttpPatchOptions) => Promise<any>,
305
- * deleteApi: (options: HttpDeleteOptions) => Promise<any>
331
+ * deleteApi: (options: HttpDeleteOptions) => Promise<any>,
332
+ * head: (options: HttpHeadOptions) => Promise<Response>
306
333
  * }}
307
334
  */
335
+
308
336
  export const http = {
309
337
  get,
310
338
  put,
311
339
  post,
312
340
  patch,
313
341
  deleteApi,
342
+ head,
314
343
  }
@@ -6,9 +6,10 @@ import { HTTP_METHODS } from '../../src/http/http-method.js'
6
6
  describe('HTTP_METHODS constant', () => {
7
7
  it('should include all standard HTTP methods', () => {
8
8
  expect(HTTP_METHODS).toEqual({
9
+ PUT: 'PUT',
9
10
  GET: 'GET',
11
+ HEAD: 'HEAD',
10
12
  POST: 'POST',
11
- PUT: 'PUT',
12
13
  PATCH: 'PATCH',
13
14
  DELETE: 'DELETE',
14
15
  })
@@ -20,6 +20,7 @@ const createMockResponse = ({
20
20
  statusText,
21
21
  text: vi.fn().mockResolvedValue(body),
22
22
  headers: {
23
+ // @ts-ignore
23
24
  get: vi.fn().mockImplementation((k) => headers[k]),
24
25
  },
25
26
  }
@@ -255,3 +256,143 @@ describe('extraParams support', () => {
255
256
  )
256
257
  })
257
258
  })
259
+
260
+ describe('HEAD', () => {
261
+ it('should send a HEAD request and return response object', async () => {
262
+ const mockResponse = createMockResponse({
263
+ status: 200,
264
+ headers: { 'content-length': '1234' },
265
+ })
266
+
267
+ mockFetch.mockResolvedValueOnce(mockResponse)
268
+
269
+ const result = await http.head({
270
+ url: 'http://test.com',
271
+ })
272
+
273
+ expect(result).toBe(mockResponse)
274
+
275
+ expect(mockFetch).toHaveBeenCalledWith(
276
+ 'http://test.com',
277
+ expect.objectContaining({
278
+ method: HTTP_METHODS.HEAD,
279
+ }),
280
+ )
281
+ })
282
+
283
+ it('should expose response headers', async () => {
284
+ const mockResponse = createMockResponse({
285
+ headers: { etag: 'abc123' },
286
+ })
287
+
288
+ mockFetch.mockResolvedValueOnce(mockResponse)
289
+
290
+ const result = await http.head({
291
+ url: 'http://test.com',
292
+ })
293
+
294
+ expect(result.headers.get('etag')).toBe('abc123')
295
+ })
296
+
297
+ it('should throw HttpError on non-2xx status', async () => {
298
+ mockFetch.mockResolvedValueOnce(
299
+ createMockResponse({
300
+ status: 500,
301
+ body: 'server error',
302
+ }),
303
+ )
304
+
305
+ await expect(
306
+ http.head({
307
+ url: 'http://test.com',
308
+ }),
309
+ ).rejects.toThrow(HttpError)
310
+ })
311
+ })
312
+
313
+ describe('edge cases', () => {
314
+ it('should fallback to text when JSON parsing fails', async () => {
315
+ const invalidJson = '{invalid json'
316
+
317
+ mockFetch.mockResolvedValueOnce(createMockResponse({ body: invalidJson }))
318
+
319
+ const result = await http.get({
320
+ url: 'http://test.com',
321
+ expectedType: ResponseType.json,
322
+ })
323
+
324
+ expect(result).toBe(invalidJson)
325
+ })
326
+
327
+ it('should fallback to text when XML parsing fails', async () => {
328
+ const invalidXml = '<note><invalid></note>'
329
+
330
+ mockFetch.mockResolvedValueOnce(createMockResponse({ body: invalidXml }))
331
+
332
+ const result = await http.get({
333
+ url: 'http://test.com',
334
+ expectedType: ResponseType.xml,
335
+ })
336
+
337
+ expect(result).toBe(invalidXml)
338
+ })
339
+
340
+ it('should allow overriding headers', async () => {
341
+ mockFetch.mockResolvedValueOnce(
342
+ createMockResponse({ body: JSON.stringify({ ok: true }) }),
343
+ )
344
+
345
+ await http.get({
346
+ url: 'http://test.com',
347
+ headers: {
348
+ Authorization: 'Bearer token123',
349
+ },
350
+ })
351
+
352
+ expect(mockFetch).toHaveBeenCalledWith(
353
+ 'http://test.com',
354
+ expect.objectContaining({
355
+ headers: expect.objectContaining({
356
+ Authorization: 'Bearer token123',
357
+ }),
358
+ }),
359
+ )
360
+ })
361
+
362
+ it('should send DELETE request without body', async () => {
363
+ mockFetch.mockResolvedValueOnce(
364
+ createMockResponse({ body: JSON.stringify({ ok: true }) }),
365
+ )
366
+
367
+ await http.deleteApi({
368
+ url: 'http://test.com',
369
+ })
370
+
371
+ expect(mockFetch).toHaveBeenCalledWith(
372
+ 'http://test.com',
373
+ expect.objectContaining({
374
+ method: HTTP_METHODS.DELETE,
375
+ }),
376
+ )
377
+ })
378
+
379
+ it('should include default JSON content-type header', async () => {
380
+ mockFetch.mockResolvedValueOnce(
381
+ createMockResponse({ body: JSON.stringify({ ok: true }) }),
382
+ )
383
+
384
+ await http.post({
385
+ url: 'http://test.com',
386
+ body: { a: 1 },
387
+ })
388
+
389
+ expect(mockFetch).toHaveBeenCalledWith(
390
+ 'http://test.com',
391
+ expect.objectContaining({
392
+ headers: expect.objectContaining({
393
+ 'Content-Type': 'application/json',
394
+ }),
395
+ }),
396
+ )
397
+ })
398
+ })
@@ -1,7 +1,8 @@
1
1
  export const HTTP_METHODS: Readonly<{
2
2
  GET: 'GET'
3
- POST: 'POST'
4
3
  PUT: 'PUT'
4
+ HEAD: 'HEAD'
5
+ POST: 'POST'
5
6
  PATCH: 'PATCH'
6
7
  DELETE: 'DELETE'
7
8
  }>
@@ -32,6 +32,11 @@ export function deleteApi({
32
32
  extraParams,
33
33
  expectedType,
34
34
  }: HttpDeleteOptions): Promise<any>
35
+ export function head({
36
+ url,
37
+ headers,
38
+ extraParams,
39
+ }: HttpHeadOptions): Promise<Response>
35
40
  /**
36
41
  * Consolidated HTTP client with methods for common HTTP operations.
37
42
  *
@@ -40,7 +45,8 @@ export function deleteApi({
40
45
  * put: (options: HttpPutOptions) => Promise<any>,
41
46
  * post: (options: HttpPostOptions) => Promise<any>,
42
47
  * patch: (options: HttpPatchOptions) => Promise<any>,
43
- * deleteApi: (options: HttpDeleteOptions) => Promise<any>
48
+ * deleteApi: (options: HttpDeleteOptions) => Promise<any>,
49
+ * head: (options: HttpHeadOptions) => Promise<Response>
44
50
  * }}
45
51
  */
46
52
  export const http: {
@@ -49,6 +55,7 @@ export const http: {
49
55
  post: (options: HttpPostOptions) => Promise<any>
50
56
  patch: (options: HttpPatchOptions) => Promise<any>
51
57
  deleteApi: (options: HttpDeleteOptions) => Promise<any>
58
+ head: (options: HttpHeadOptions) => Promise<Response>
52
59
  }
53
60
  export type ResponseTypeValue = 'json' | 'xml' | 'text' | 'raw' | 'file'
54
61
  export type HttpGetOptions = {
@@ -157,3 +164,17 @@ export type HttpDeleteOptions = {
157
164
  */
158
165
  expectedType?: ResponseTypeValue
159
166
  }
167
+ export type HttpHeadOptions = {
168
+ /**
169
+ * - The URL to send the request to.
170
+ */
171
+ url: string
172
+ /**
173
+ * - Optional HTTP headers.
174
+ */
175
+ headers?: Record<string, string>
176
+ /**
177
+ * - Additional fetch options.
178
+ */
179
+ extraParams?: RequestInit
180
+ }