core-services-sdk 1.3.82 → 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 +1 -1
- package/src/http/http-method.js +2 -1
- package/src/http/http.js +42 -1
- package/tests/http/http-method.unit.test.js +2 -1
- package/tests/http/http.unit.test.js +211 -0
- package/types/http/http-method.d.ts +2 -1
- package/types/http/http.d.ts +153 -35
- package/types/postgresql/index.d.ts +2 -0
- package/types/postgresql/pagination/paginate.d.ts +1 -0
- package/types/postgresql/repositories/BaseRepository.d.ts +50 -0
- package/types/postgresql/repositories/TenantScopedRepository.d.ts +11 -0
package/package.json
CHANGED
package/src/http/http-method.js
CHANGED
package/src/http/http.js
CHANGED
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
* @property {string} url - The URL to send the request to.
|
|
25
25
|
* @property {any} body - The request body to send.
|
|
26
26
|
* @property {Record<string, string>} [headers] - Optional HTTP headers.
|
|
27
|
+
* @property {RequestInit} [extraParams] - Additional fetch options.
|
|
27
28
|
* @property {ResponseTypeValue} [expectedType] - Expected response type.
|
|
28
29
|
*/
|
|
29
30
|
|
|
@@ -32,6 +33,7 @@
|
|
|
32
33
|
* @property {string} url - The URL to send the request to.
|
|
33
34
|
* @property {any} body - The request body to send.
|
|
34
35
|
* @property {Record<string, string>} [headers] - Optional HTTP headers.
|
|
36
|
+
* @property {RequestInit} [extraParams] - Additional fetch options.
|
|
35
37
|
* @property {ResponseTypeValue} [expectedType] - Expected response type.
|
|
36
38
|
*/
|
|
37
39
|
|
|
@@ -40,6 +42,7 @@
|
|
|
40
42
|
* @property {string} url - The URL to send the request to.
|
|
41
43
|
* @property {any} body - The request body to send.
|
|
42
44
|
* @property {Record<string, string>} [headers] - Optional HTTP headers.
|
|
45
|
+
* @property {RequestInit} [extraParams] - Additional fetch options.
|
|
43
46
|
* @property {ResponseTypeValue} [expectedType] - Expected response type.
|
|
44
47
|
*/
|
|
45
48
|
|
|
@@ -48,9 +51,17 @@
|
|
|
48
51
|
* @property {string} url - The URL to send the request to.
|
|
49
52
|
* @property {any} [body] - Optional request body to send.
|
|
50
53
|
* @property {Record<string, string>} [headers] - Optional HTTP headers.
|
|
54
|
+
* @property {RequestInit} [extraParams] - Additional fetch options.
|
|
51
55
|
* @property {ResponseTypeValue} [expectedType] - Expected response type.
|
|
52
56
|
*/
|
|
53
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
|
+
|
|
54
65
|
import httpStatus from 'http-status'
|
|
55
66
|
import { parseStringPromise } from 'xml2js'
|
|
56
67
|
|
|
@@ -205,9 +216,11 @@ export const post = async ({
|
|
|
205
216
|
url,
|
|
206
217
|
body,
|
|
207
218
|
headers = {},
|
|
219
|
+
extraParams = {},
|
|
208
220
|
expectedType = ResponseType.json,
|
|
209
221
|
}) => {
|
|
210
222
|
const response = await fetch(url, {
|
|
223
|
+
...extraParams,
|
|
211
224
|
method: HTTP_METHODS.POST,
|
|
212
225
|
headers: { ...JSON_HEADER, ...headers },
|
|
213
226
|
body: JSON.stringify(body),
|
|
@@ -227,9 +240,11 @@ export const put = async ({
|
|
|
227
240
|
url,
|
|
228
241
|
body,
|
|
229
242
|
headers = {},
|
|
243
|
+
extraParams = {},
|
|
230
244
|
expectedType = ResponseType.json,
|
|
231
245
|
}) => {
|
|
232
246
|
const response = await fetch(url, {
|
|
247
|
+
...extraParams,
|
|
233
248
|
method: HTTP_METHODS.PUT,
|
|
234
249
|
headers: { ...JSON_HEADER, ...headers },
|
|
235
250
|
body: expectedType === ResponseType.json ? JSON.stringify(body) : body,
|
|
@@ -249,9 +264,11 @@ export const patch = async ({
|
|
|
249
264
|
url,
|
|
250
265
|
body,
|
|
251
266
|
headers = {},
|
|
267
|
+
extraParams = {},
|
|
252
268
|
expectedType = ResponseType.json,
|
|
253
269
|
}) => {
|
|
254
270
|
const response = await fetch(url, {
|
|
271
|
+
...extraParams,
|
|
255
272
|
method: HTTP_METHODS.PATCH,
|
|
256
273
|
headers: { ...JSON_HEADER, ...headers },
|
|
257
274
|
body: JSON.stringify(body),
|
|
@@ -271,9 +288,11 @@ export const deleteApi = async ({
|
|
|
271
288
|
url,
|
|
272
289
|
body,
|
|
273
290
|
headers = {},
|
|
291
|
+
extraParams = {},
|
|
274
292
|
expectedType = ResponseType.json,
|
|
275
293
|
}) => {
|
|
276
294
|
const response = await fetch(url, {
|
|
295
|
+
...extraParams,
|
|
277
296
|
method: HTTP_METHODS.DELETE,
|
|
278
297
|
headers: { ...JSON_HEADER, ...headers },
|
|
279
298
|
...(body ? { body: JSON.stringify(body) } : {}),
|
|
@@ -282,6 +301,25 @@ export const deleteApi = async ({
|
|
|
282
301
|
return getResponsePayload(response, expectedType)
|
|
283
302
|
}
|
|
284
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
|
+
|
|
285
323
|
/**
|
|
286
324
|
* Consolidated HTTP client with methods for common HTTP operations.
|
|
287
325
|
*
|
|
@@ -290,13 +328,16 @@ export const deleteApi = async ({
|
|
|
290
328
|
* put: (options: HttpPutOptions) => Promise<any>,
|
|
291
329
|
* post: (options: HttpPostOptions) => Promise<any>,
|
|
292
330
|
* patch: (options: HttpPatchOptions) => Promise<any>,
|
|
293
|
-
* deleteApi: (options: HttpDeleteOptions) => Promise<any
|
|
331
|
+
* deleteApi: (options: HttpDeleteOptions) => Promise<any>,
|
|
332
|
+
* head: (options: HttpHeadOptions) => Promise<Response>
|
|
294
333
|
* }}
|
|
295
334
|
*/
|
|
335
|
+
|
|
296
336
|
export const http = {
|
|
297
337
|
get,
|
|
298
338
|
put,
|
|
299
339
|
post,
|
|
300
340
|
patch,
|
|
301
341
|
deleteApi,
|
|
342
|
+
head,
|
|
302
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
|
}
|
|
@@ -185,3 +186,213 @@ describe('http client (native fetch)', () => {
|
|
|
185
186
|
})
|
|
186
187
|
})
|
|
187
188
|
})
|
|
189
|
+
|
|
190
|
+
describe('extraParams support', () => {
|
|
191
|
+
it('should pass extraParams to fetch in GET', async () => {
|
|
192
|
+
mockFetch.mockResolvedValueOnce(
|
|
193
|
+
createMockResponse({ body: JSON.stringify({ ok: true }) }),
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const controller = new AbortController()
|
|
197
|
+
|
|
198
|
+
await http.get({
|
|
199
|
+
url: 'http://test.com',
|
|
200
|
+
extraParams: {
|
|
201
|
+
signal: controller.signal,
|
|
202
|
+
redirect: 'follow',
|
|
203
|
+
},
|
|
204
|
+
})
|
|
205
|
+
|
|
206
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
207
|
+
'http://test.com',
|
|
208
|
+
expect.objectContaining({
|
|
209
|
+
method: HTTP_METHODS.GET,
|
|
210
|
+
signal: controller.signal,
|
|
211
|
+
redirect: 'follow',
|
|
212
|
+
}),
|
|
213
|
+
)
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
it('should pass extraParams to fetch in POST', async () => {
|
|
217
|
+
mockFetch.mockResolvedValueOnce(
|
|
218
|
+
createMockResponse({ body: JSON.stringify({ ok: true }) }),
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
await http.post({
|
|
222
|
+
url: 'http://test.com',
|
|
223
|
+
body: { a: 1 },
|
|
224
|
+
extraParams: {
|
|
225
|
+
credentials: 'include',
|
|
226
|
+
},
|
|
227
|
+
})
|
|
228
|
+
|
|
229
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
230
|
+
'http://test.com',
|
|
231
|
+
expect.objectContaining({
|
|
232
|
+
method: HTTP_METHODS.POST,
|
|
233
|
+
credentials: 'include',
|
|
234
|
+
}),
|
|
235
|
+
)
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
it('should pass extraParams to fetch in DELETE', async () => {
|
|
239
|
+
mockFetch.mockResolvedValueOnce(
|
|
240
|
+
createMockResponse({ body: JSON.stringify({ ok: true }) }),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
await http.deleteApi({
|
|
244
|
+
url: 'http://test.com',
|
|
245
|
+
extraParams: {
|
|
246
|
+
keepalive: true,
|
|
247
|
+
},
|
|
248
|
+
})
|
|
249
|
+
|
|
250
|
+
expect(mockFetch).toHaveBeenCalledWith(
|
|
251
|
+
'http://test.com',
|
|
252
|
+
expect.objectContaining({
|
|
253
|
+
method: HTTP_METHODS.DELETE,
|
|
254
|
+
keepalive: true,
|
|
255
|
+
}),
|
|
256
|
+
)
|
|
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
|
+
})
|
package/types/http/http.d.ts
CHANGED
|
@@ -3,60 +3,178 @@ export function get({
|
|
|
3
3
|
headers,
|
|
4
4
|
extraParams,
|
|
5
5
|
expectedType,
|
|
6
|
-
}:
|
|
7
|
-
url: any
|
|
8
|
-
headers?: {}
|
|
9
|
-
extraParams?: {}
|
|
10
|
-
expectedType?: 'json'
|
|
11
|
-
}): Promise<any>
|
|
6
|
+
}: HttpGetOptions): Promise<any>
|
|
12
7
|
export function post({
|
|
13
8
|
url,
|
|
14
9
|
body,
|
|
15
10
|
headers,
|
|
11
|
+
extraParams,
|
|
16
12
|
expectedType,
|
|
17
|
-
}:
|
|
18
|
-
url: any
|
|
19
|
-
body: any
|
|
20
|
-
headers?: {}
|
|
21
|
-
expectedType?: 'json'
|
|
22
|
-
}): Promise<any>
|
|
13
|
+
}: HttpPostOptions): Promise<any>
|
|
23
14
|
export function put({
|
|
24
15
|
url,
|
|
25
16
|
body,
|
|
26
17
|
headers,
|
|
18
|
+
extraParams,
|
|
27
19
|
expectedType,
|
|
28
|
-
}:
|
|
29
|
-
url: any
|
|
30
|
-
body: any
|
|
31
|
-
headers?: {}
|
|
32
|
-
expectedType?: 'json'
|
|
33
|
-
}): Promise<any>
|
|
20
|
+
}: HttpPutOptions): Promise<any>
|
|
34
21
|
export function patch({
|
|
35
22
|
url,
|
|
36
23
|
body,
|
|
37
24
|
headers,
|
|
25
|
+
extraParams,
|
|
38
26
|
expectedType,
|
|
39
|
-
}:
|
|
40
|
-
url: any
|
|
41
|
-
body: any
|
|
42
|
-
headers?: {}
|
|
43
|
-
expectedType?: 'json'
|
|
44
|
-
}): Promise<any>
|
|
27
|
+
}: HttpPatchOptions): Promise<any>
|
|
45
28
|
export function deleteApi({
|
|
46
29
|
url,
|
|
47
30
|
body,
|
|
48
31
|
headers,
|
|
32
|
+
extraParams,
|
|
49
33
|
expectedType,
|
|
50
|
-
}:
|
|
51
|
-
|
|
34
|
+
}: HttpDeleteOptions): Promise<any>
|
|
35
|
+
export function head({
|
|
36
|
+
url,
|
|
37
|
+
headers,
|
|
38
|
+
extraParams,
|
|
39
|
+
}: HttpHeadOptions): Promise<Response>
|
|
40
|
+
/**
|
|
41
|
+
* Consolidated HTTP client with methods for common HTTP operations.
|
|
42
|
+
*
|
|
43
|
+
* @type {{
|
|
44
|
+
* get: (options: HttpGetOptions) => Promise<any>,
|
|
45
|
+
* put: (options: HttpPutOptions) => Promise<any>,
|
|
46
|
+
* post: (options: HttpPostOptions) => Promise<any>,
|
|
47
|
+
* patch: (options: HttpPatchOptions) => Promise<any>,
|
|
48
|
+
* deleteApi: (options: HttpDeleteOptions) => Promise<any>,
|
|
49
|
+
* head: (options: HttpHeadOptions) => Promise<Response>
|
|
50
|
+
* }}
|
|
51
|
+
*/
|
|
52
|
+
export const http: {
|
|
53
|
+
get: (options: HttpGetOptions) => Promise<any>
|
|
54
|
+
put: (options: HttpPutOptions) => Promise<any>
|
|
55
|
+
post: (options: HttpPostOptions) => Promise<any>
|
|
56
|
+
patch: (options: HttpPatchOptions) => Promise<any>
|
|
57
|
+
deleteApi: (options: HttpDeleteOptions) => Promise<any>
|
|
58
|
+
head: (options: HttpHeadOptions) => Promise<Response>
|
|
59
|
+
}
|
|
60
|
+
export type ResponseTypeValue = 'json' | 'xml' | 'text' | 'raw' | 'file'
|
|
61
|
+
export type HttpGetOptions = {
|
|
62
|
+
/**
|
|
63
|
+
* - The URL to send the request to.
|
|
64
|
+
*/
|
|
65
|
+
url: string
|
|
66
|
+
/**
|
|
67
|
+
* - Optional HTTP headers.
|
|
68
|
+
*/
|
|
69
|
+
headers?: Record<string, string>
|
|
70
|
+
/**
|
|
71
|
+
* - Additional fetch options.
|
|
72
|
+
*/
|
|
73
|
+
extraParams?: RequestInit
|
|
74
|
+
/**
|
|
75
|
+
* - Expected response type.
|
|
76
|
+
*/
|
|
77
|
+
expectedType?: ResponseTypeValue
|
|
78
|
+
}
|
|
79
|
+
export type HttpPostOptions = {
|
|
80
|
+
/**
|
|
81
|
+
* - The URL to send the request to.
|
|
82
|
+
*/
|
|
83
|
+
url: string
|
|
84
|
+
/**
|
|
85
|
+
* - The request body to send.
|
|
86
|
+
*/
|
|
87
|
+
body: any
|
|
88
|
+
/**
|
|
89
|
+
* - Optional HTTP headers.
|
|
90
|
+
*/
|
|
91
|
+
headers?: Record<string, string>
|
|
92
|
+
/**
|
|
93
|
+
* - Additional fetch options.
|
|
94
|
+
*/
|
|
95
|
+
extraParams?: RequestInit
|
|
96
|
+
/**
|
|
97
|
+
* - Expected response type.
|
|
98
|
+
*/
|
|
99
|
+
expectedType?: ResponseTypeValue
|
|
100
|
+
}
|
|
101
|
+
export type HttpPutOptions = {
|
|
102
|
+
/**
|
|
103
|
+
* - The URL to send the request to.
|
|
104
|
+
*/
|
|
105
|
+
url: string
|
|
106
|
+
/**
|
|
107
|
+
* - The request body to send.
|
|
108
|
+
*/
|
|
52
109
|
body: any
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
110
|
+
/**
|
|
111
|
+
* - Optional HTTP headers.
|
|
112
|
+
*/
|
|
113
|
+
headers?: Record<string, string>
|
|
114
|
+
/**
|
|
115
|
+
* - Additional fetch options.
|
|
116
|
+
*/
|
|
117
|
+
extraParams?: RequestInit
|
|
118
|
+
/**
|
|
119
|
+
* - Expected response type.
|
|
120
|
+
*/
|
|
121
|
+
expectedType?: ResponseTypeValue
|
|
122
|
+
}
|
|
123
|
+
export type HttpPatchOptions = {
|
|
124
|
+
/**
|
|
125
|
+
* - The URL to send the request to.
|
|
126
|
+
*/
|
|
127
|
+
url: string
|
|
128
|
+
/**
|
|
129
|
+
* - The request body to send.
|
|
130
|
+
*/
|
|
131
|
+
body: any
|
|
132
|
+
/**
|
|
133
|
+
* - Optional HTTP headers.
|
|
134
|
+
*/
|
|
135
|
+
headers?: Record<string, string>
|
|
136
|
+
/**
|
|
137
|
+
* - Additional fetch options.
|
|
138
|
+
*/
|
|
139
|
+
extraParams?: RequestInit
|
|
140
|
+
/**
|
|
141
|
+
* - Expected response type.
|
|
142
|
+
*/
|
|
143
|
+
expectedType?: ResponseTypeValue
|
|
144
|
+
}
|
|
145
|
+
export type HttpDeleteOptions = {
|
|
146
|
+
/**
|
|
147
|
+
* - The URL to send the request to.
|
|
148
|
+
*/
|
|
149
|
+
url: string
|
|
150
|
+
/**
|
|
151
|
+
* - Optional request body to send.
|
|
152
|
+
*/
|
|
153
|
+
body?: any
|
|
154
|
+
/**
|
|
155
|
+
* - Optional HTTP headers.
|
|
156
|
+
*/
|
|
157
|
+
headers?: Record<string, string>
|
|
158
|
+
/**
|
|
159
|
+
* - Additional fetch options.
|
|
160
|
+
*/
|
|
161
|
+
extraParams?: RequestInit
|
|
162
|
+
/**
|
|
163
|
+
* - Expected response type.
|
|
164
|
+
*/
|
|
165
|
+
expectedType?: ResponseTypeValue
|
|
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
|
|
62
180
|
}
|
|
@@ -5,4 +5,6 @@ export * from './filters/apply-filter.js'
|
|
|
5
5
|
export * from './modifiers/apply-order-by.js'
|
|
6
6
|
export * from './start-stop-postgres-docker.js'
|
|
7
7
|
export * from './modifiers/apply-pagination.js'
|
|
8
|
+
export * from './repositories/BaseRepository.js'
|
|
8
9
|
export * from './filters/apply-filter-snake-case.js'
|
|
10
|
+
export * from './repositories/TenantScopedRepository.js'
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BaseRepository
|
|
3
|
+
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - tableName getter (static + instance support)
|
|
6
|
+
* - baseQuery(options)
|
|
7
|
+
* - constructor-level query shaping (optional)
|
|
8
|
+
* - generic find() with pagination
|
|
9
|
+
*
|
|
10
|
+
* Does NOT enforce tenant isolation.
|
|
11
|
+
*/
|
|
12
|
+
export class BaseRepository {
|
|
13
|
+
constructor({ db, log, baseQueryBuilder }?: {})
|
|
14
|
+
db: any
|
|
15
|
+
log: any
|
|
16
|
+
_baseQueryBuilder: any
|
|
17
|
+
/**
|
|
18
|
+
* Each concrete repository must define:
|
|
19
|
+
* static tableName = 'table_name'
|
|
20
|
+
*/
|
|
21
|
+
get tableName(): any
|
|
22
|
+
/**
|
|
23
|
+
* Builds the base knex query.
|
|
24
|
+
* Applies constructor-level baseQueryBuilder if provided.
|
|
25
|
+
*/
|
|
26
|
+
baseQuery(options: {}, params: any): any
|
|
27
|
+
/**
|
|
28
|
+
* Generic paginated find
|
|
29
|
+
*/
|
|
30
|
+
find({
|
|
31
|
+
page,
|
|
32
|
+
limit,
|
|
33
|
+
filter,
|
|
34
|
+
orderBy,
|
|
35
|
+
options,
|
|
36
|
+
mapRow,
|
|
37
|
+
...restParams
|
|
38
|
+
}: {
|
|
39
|
+
[x: string]: any
|
|
40
|
+
page?: number
|
|
41
|
+
limit?: number
|
|
42
|
+
filter?: {}
|
|
43
|
+
orderBy?: {
|
|
44
|
+
column: string
|
|
45
|
+
direction: string
|
|
46
|
+
}
|
|
47
|
+
options?: {}
|
|
48
|
+
mapRow?: (row: any) => any
|
|
49
|
+
}): Promise<any>
|
|
50
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export class TenantScopedRepository extends BaseRepository {
|
|
2
|
+
/**
|
|
3
|
+
* Extracts and validates tenantId from filter
|
|
4
|
+
*/
|
|
5
|
+
getRequiredTenantId(filter?: {}): any
|
|
6
|
+
/**
|
|
7
|
+
* Overrides find to enforce tenant presence
|
|
8
|
+
*/
|
|
9
|
+
find(params?: {}): Promise<any>
|
|
10
|
+
}
|
|
11
|
+
import { BaseRepository } from './BaseRepository.js'
|