@unito/integration-sdk 0.1.11 → 1.0.0

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 (36) hide show
  1. package/dist/src/handler.d.ts +39 -0
  2. package/dist/src/handler.js +9 -0
  3. package/dist/src/httpErrors.d.ts +29 -0
  4. package/dist/src/httpErrors.js +30 -0
  5. package/dist/src/index.cjs +274 -16
  6. package/dist/src/index.d.ts +1 -0
  7. package/dist/src/integration.d.ts +49 -0
  8. package/dist/src/integration.js +51 -0
  9. package/dist/src/middlewares/filters.d.ts +11 -2
  10. package/dist/src/middlewares/secrets.d.ts +5 -0
  11. package/dist/src/middlewares/signal.d.ts +15 -0
  12. package/dist/src/middlewares/signal.js +22 -0
  13. package/dist/src/resources/cache.d.ts +51 -1
  14. package/dist/src/resources/cache.js +51 -1
  15. package/dist/src/resources/context.d.ts +42 -13
  16. package/dist/src/resources/logger.d.ts +17 -0
  17. package/dist/src/resources/logger.js +17 -0
  18. package/dist/src/resources/provider.d.ts +90 -5
  19. package/dist/src/resources/provider.js +92 -11
  20. package/dist/test/middlewares/signal.test.d.ts +1 -0
  21. package/dist/test/middlewares/signal.test.js +20 -0
  22. package/dist/test/resources/provider.test.js +116 -21
  23. package/package.json +4 -4
  24. package/src/handler.ts +48 -0
  25. package/src/httpErrors.ts +30 -0
  26. package/src/index.ts +1 -0
  27. package/src/integration.ts +51 -0
  28. package/src/middlewares/filters.ts +11 -2
  29. package/src/middlewares/secrets.ts +5 -0
  30. package/src/middlewares/signal.ts +41 -0
  31. package/src/resources/cache.ts +51 -1
  32. package/src/resources/context.ts +50 -33
  33. package/src/resources/logger.ts +17 -0
  34. package/src/resources/provider.ts +115 -16
  35. package/test/middlewares/signal.test.ts +28 -0
  36. package/test/resources/provider.test.ts +122 -21
@@ -1,9 +1,19 @@
1
1
  import { buildHttpError } from '../errors.js';
2
+ /**
3
+ * The Provider class is a wrapper around the fetch function to call a provider's HTTP API.
4
+ *
5
+ * Defines methods for the following HTTP methods: GET, POST, PUT, PATCH, DELETE.
6
+ *
7
+ * Needs to be initialized with a prepareRequest function to define the Provider's base URL and any specific headers to
8
+ * add to the requests, and can also be configured to use a provided rate limiting function.
9
+ * @see {@link RateLimiter}
10
+ * @see {@link prepareRequest}
11
+ */
2
12
  export class Provider {
3
13
  rateLimiter = undefined;
4
14
  prepareRequest;
5
15
  /**
6
- * Initialize a Provider with the given options.
16
+ * Initializes a Provider with the given options.
7
17
  *
8
18
  * @property prepareRequest - function to define the Provider's base URL and specific headers to add to the request.
9
19
  * @property rateLimiter - function to limit the rate of calls to the provider based on the caller's credentials.
@@ -12,52 +22,108 @@ export class Provider {
12
22
  this.prepareRequest = options.prepareRequest;
13
23
  this.rateLimiter = options.rateLimiter;
14
24
  }
25
+ /**
26
+ * Performs a GET request to the provider.
27
+ *
28
+ * Uses the prepareRequest function to get the base URL and any specific headers to add to the request and by default
29
+ * adds the following headers:
30
+ * - Accept: application/json
31
+ *
32
+ * @param endpoint Path to the provider's resource. Will be added to the URL returned by the prepareRequest function.
33
+ * @param options RequestOptions used to adjust the call made to the provider (use to override default headers).
34
+ * @returns The {@link Response} extracted from the provider.
35
+ */
15
36
  async get(endpoint, options) {
16
37
  return this.fetchWrapper(endpoint, null, {
17
38
  ...options,
18
39
  method: 'GET',
19
40
  defaultHeaders: {
20
- 'Content-Type': 'application/json',
21
41
  Accept: 'application/json',
22
42
  },
23
43
  });
24
44
  }
45
+ /**
46
+ * Performs a POST request to the provider.
47
+ *
48
+ * Uses the prepareRequest function to get the base URL and any specific headers to add to the request and by default
49
+ * adds the following headers:
50
+ * - Content-Type: application/json',
51
+ * - Accept: application/json
52
+ *
53
+ * @param endpoint Path to the provider's resource. Will be added to the URL returned by the prepareRequest function.
54
+ * @param options RequestOptions used to adjust the call made to the provider (use to override default headers).
55
+ * @returns The {@link Response} extracted from the provider.
56
+ */
25
57
  async post(endpoint, body, options) {
26
58
  return this.fetchWrapper(endpoint, body, {
27
59
  ...options,
28
60
  method: 'POST',
29
61
  defaultHeaders: {
30
- 'Content-Type': 'application/x-www-form-urlencoded',
62
+ 'Content-Type': 'application/json',
31
63
  Accept: 'application/json',
32
64
  },
33
65
  });
34
66
  }
67
+ /**
68
+ * Performs a PUT request to the provider.
69
+ *
70
+ * Uses the prepareRequest function to get the base URL and any specific headers to add to the request and by default
71
+ * adds the following headers:
72
+ * - Content-Type: application/json',
73
+ * - Accept: application/json
74
+ *
75
+ * @param endpoint Path to the provider's resource. Will be added to the URL returned by the prepareRequest function.
76
+ * @param options RequestOptions used to adjust the call made to the provider (use to override default headers).
77
+ * @returns The {@link Response} extracted from the provider.
78
+ */
35
79
  async put(endpoint, body, options) {
36
80
  return this.fetchWrapper(endpoint, body, {
37
81
  ...options,
38
82
  method: 'PUT',
39
83
  defaultHeaders: {
40
- 'Content-Type': 'application/x-www-form-urlencoded',
84
+ 'Content-Type': 'application/json',
41
85
  Accept: 'application/json',
42
86
  },
43
87
  });
44
88
  }
89
+ /**
90
+ * Performs a PATCH request to the provider.
91
+ *
92
+ * Uses the prepareRequest function to get the base URL and any specific headers to add to the request and by default
93
+ * adds the following headers:
94
+ * - Content-Type: application/json',
95
+ * - Accept: application/json
96
+ *
97
+ * @param endpoint Path to the provider's resource. Will be added to the URL returned by the prepareRequest function.
98
+ * @param options RequestOptions used to adjust the call made to the provider (use to override default headers).
99
+ * @returns The {@link Response} extracted from the provider.
100
+ */
45
101
  async patch(endpoint, body, options) {
46
102
  return this.fetchWrapper(endpoint, body, {
47
103
  ...options,
48
104
  method: 'PATCH',
49
105
  defaultHeaders: {
50
- 'Content-Type': 'application/x-www-form-urlencoded',
106
+ 'Content-Type': 'application/json',
51
107
  Accept: 'application/json',
52
108
  },
53
109
  });
54
110
  }
111
+ /**
112
+ * Performs a DELETE request to the provider.
113
+ *
114
+ * Uses the prepareRequest function to get the base URL and any specific headers to add to the request and by default
115
+ * adds the following headers:
116
+ * - Accept: application/json
117
+ *
118
+ * @param endpoint Path to the provider's resource. Will be added to the URL returned by the prepareRequest function.
119
+ * @param options RequestOptions used to adjust the call made to the provider (use to override default headers).
120
+ * @returns The {@link Response} extracted from the provider.
121
+ */
55
122
  async delete(endpoint, options) {
56
123
  return this.fetchWrapper(endpoint, null, {
57
124
  ...options,
58
125
  method: 'DELETE',
59
126
  defaultHeaders: {
60
- 'Content-Type': 'application/x-www-form-urlencoded',
61
127
  Accept: 'application/json',
62
128
  },
63
129
  });
@@ -79,11 +145,26 @@ export class Provider {
79
145
  }
80
146
  }
81
147
  const callToProvider = async () => {
82
- const response = await fetch(absoluteUrl, {
83
- method: options.method,
84
- headers,
85
- body: stringifiedBody,
86
- });
148
+ let response;
149
+ try {
150
+ response = await fetch(absoluteUrl, {
151
+ method: options.method,
152
+ signal: options.signal,
153
+ headers,
154
+ body: stringifiedBody,
155
+ });
156
+ }
157
+ catch (error) {
158
+ if (error instanceof Error) {
159
+ switch (error.name) {
160
+ case 'AbortError':
161
+ throw buildHttpError(408, 'Request aborted');
162
+ case 'TimeoutError':
163
+ throw buildHttpError(408, 'Request timeout');
164
+ }
165
+ }
166
+ throw buildHttpError(500, `Unexpected error while calling the provider: "${error}"`);
167
+ }
87
168
  if (response.status >= 400) {
88
169
  const textResult = await response.text();
89
170
  throw buildHttpError(response.status, textResult);
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,20 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import middleware from '../../src/middlewares/signal.js';
4
+ describe('signal middleware', () => {
5
+ it('uses header', () => {
6
+ const deadline = Math.floor((Date.now() + 5000) / 1000);
7
+ const request = { header: (_key) => deadline };
8
+ const response = { locals: {} };
9
+ middleware(request, response, () => { });
10
+ assert.ok(response.locals.signal instanceof AbortSignal);
11
+ assert.equal(response.locals.signal.aborted, false);
12
+ });
13
+ it('defaults', () => {
14
+ const request = { header: (_key) => undefined };
15
+ const response = { locals: {} };
16
+ middleware(request, response, () => { });
17
+ assert.ok(response.locals.signal instanceof AbortSignal);
18
+ assert.equal(response.locals.signal.aborted, false);
19
+ });
20
+ });
@@ -1,6 +1,7 @@
1
1
  import assert from 'node:assert/strict';
2
2
  import { describe, it } from 'node:test';
3
3
  import { Provider } from '../../src/resources/provider.js';
4
+ import * as HttpErrors from '../../src/httpErrors.js';
4
5
  import Logger from '../../src/resources/logger.js';
5
6
  describe('Provider', () => {
6
7
  const provider = new Provider({
@@ -24,6 +25,7 @@ describe('Provider', () => {
24
25
  const actualResponse = await provider.get('/endpoint', {
25
26
  credentials: { apiKey: 'apikey#1111' },
26
27
  logger: logger,
28
+ signal: new AbortController().signal,
27
29
  additionnalheaders: { 'X-Additional-Header': 'value1' },
28
30
  });
29
31
  assert.equal(fetchMock.mock.calls.length, 1);
@@ -32,8 +34,8 @@ describe('Provider', () => {
32
34
  {
33
35
  method: 'GET',
34
36
  body: null,
37
+ signal: new AbortController().signal,
35
38
  headers: {
36
- 'Content-Type': 'application/json',
37
39
  Accept: 'application/json',
38
40
  'X-Custom-Provider-Header': 'value',
39
41
  'X-Provider-Credential-Header': 'apikey#1111',
@@ -54,7 +56,8 @@ describe('Provider', () => {
54
56
  }, {
55
57
  credentials: { apiKey: 'apikey#1111' },
56
58
  logger: logger,
57
- additionnalheaders: { 'X-Additional-Header': 'value1' },
59
+ signal: new AbortController().signal,
60
+ additionnalheaders: { 'Content-Type': 'application/x-www-form-urlencoded', 'X-Additional-Header': 'value1' },
58
61
  });
59
62
  assert.equal(fetchMock.mock.calls.length, 1);
60
63
  assert.deepEqual(fetchMock.mock.calls[0]?.arguments, [
@@ -62,6 +65,7 @@ describe('Provider', () => {
62
65
  {
63
66
  method: 'POST',
64
67
  body: 'data=createdItemInfo',
68
+ signal: new AbortController().signal,
65
69
  headers: {
66
70
  'Content-Type': 'application/x-www-form-urlencoded',
67
71
  Accept: 'application/json',
@@ -85,6 +89,7 @@ describe('Provider', () => {
85
89
  }, {
86
90
  credentials: { apiKey: 'apikey#1111' },
87
91
  logger: logger,
92
+ signal: new AbortController().signal,
88
93
  additionnalheaders: { 'X-Additional-Header': 'value1', 'Content-Type': 'application/json' },
89
94
  });
90
95
  assert.equal(fetchMock.mock.calls.length, 1);
@@ -93,6 +98,7 @@ describe('Provider', () => {
93
98
  {
94
99
  method: 'PUT',
95
100
  body: JSON.stringify({ data: 'updatedItemInfo' }),
101
+ signal: new AbortController().signal,
96
102
  headers: {
97
103
  'Content-Type': 'application/json',
98
104
  Accept: 'application/json',
@@ -115,8 +121,9 @@ describe('Provider', () => {
115
121
  }, {
116
122
  credentials: { apiKey: 'apikey#1111' },
117
123
  logger: logger,
124
+ signal: new AbortController().signal,
118
125
  queryParams: { param1: 'value1', param2: 'value2' },
119
- additionnalheaders: { 'X-Additional-Header': 'value1', 'Content-Type': 'application/json' },
126
+ additionnalheaders: { 'X-Additional-Header': 'value1' },
120
127
  });
121
128
  assert.equal(fetchMock.mock.calls.length, 1);
122
129
  assert.deepEqual(fetchMock.mock.calls[0]?.arguments, [
@@ -124,6 +131,7 @@ describe('Provider', () => {
124
131
  {
125
132
  method: 'PATCH',
126
133
  body: JSON.stringify({ data: 'updatedItemInfo' }),
134
+ signal: new AbortController().signal,
127
135
  headers: {
128
136
  'Content-Type': 'application/json',
129
137
  Accept: 'application/json',
@@ -144,7 +152,8 @@ describe('Provider', () => {
144
152
  const actualResponse = await provider.delete('/endpoint/123', {
145
153
  credentials: { apiKey: 'apikey#1111' },
146
154
  logger: logger,
147
- additionnalheaders: { 'X-Additional-Header': 'value1', 'Content-Type': 'application/json' },
155
+ signal: new AbortController().signal,
156
+ additionnalheaders: { 'X-Additional-Header': 'value1' },
148
157
  });
149
158
  assert.equal(fetchMock.mock.calls.length, 1);
150
159
  assert.deepEqual(fetchMock.mock.calls[0]?.arguments, [
@@ -152,8 +161,8 @@ describe('Provider', () => {
152
161
  {
153
162
  method: 'DELETE',
154
163
  body: null,
164
+ signal: new AbortController().signal,
155
165
  headers: {
156
- 'Content-Type': 'application/json',
157
166
  Accept: 'application/json',
158
167
  'X-Custom-Provider-Header': 'value',
159
168
  'X-Provider-Credential-Header': 'apikey#1111',
@@ -185,7 +194,8 @@ describe('Provider', () => {
185
194
  const options = {
186
195
  credentials: { apiKey: 'apikey#1111' },
187
196
  logger: logger,
188
- additionnalheaders: { 'X-Additional-Header': 'value1', 'Content-Type': 'application/json' },
197
+ signal: new AbortController().signal,
198
+ additionnalheaders: { 'X-Additional-Header': 'value1' },
189
199
  };
190
200
  const actualResponse = await rateLimitedProvider.delete('/endpoint/123', options);
191
201
  assert.equal(mockRateLimiter.mock.calls.length, 1);
@@ -196,8 +206,8 @@ describe('Provider', () => {
196
206
  {
197
207
  method: 'DELETE',
198
208
  body: null,
209
+ signal: new AbortController().signal,
199
210
  headers: {
200
- 'Content-Type': 'application/json',
201
211
  Accept: 'application/json',
202
212
  'X-Custom-Provider-Header': 'value',
203
213
  'X-Provider-Credential-Header': 'apikey#1111',
@@ -212,29 +222,114 @@ describe('Provider', () => {
212
222
  status: 200,
213
223
  });
214
224
  context.mock.method(global, 'fetch', () => Promise.resolve(response));
215
- assert.rejects(() => provider.get('/endpoint/123', {
216
- credentials: { apiKey: 'apikey#1111' },
217
- logger: logger,
218
- }));
225
+ let error;
226
+ try {
227
+ await provider.get('/endpoint/123', {
228
+ credentials: { apiKey: 'apikey#1111' },
229
+ logger: logger,
230
+ signal: new AbortController().signal,
231
+ });
232
+ }
233
+ catch (e) {
234
+ error = e;
235
+ }
236
+ assert.ok(error instanceof HttpErrors.BadRequestError);
237
+ assert.equal(error.message, 'Invalid JSON response');
219
238
  });
220
239
  it('throws on status 400', async (context) => {
221
- const response = new Response(undefined, {
240
+ const response = new Response('response body', {
222
241
  status: 400,
223
242
  });
224
243
  context.mock.method(global, 'fetch', () => Promise.resolve(response));
225
- assert.rejects(() => provider.get('/endpoint/123', {
226
- credentials: { apiKey: 'apikey#1111' },
227
- logger: logger,
228
- }));
244
+ let error;
245
+ try {
246
+ await provider.get('/endpoint/123', {
247
+ credentials: { apiKey: 'apikey#1111' },
248
+ signal: new AbortController().signal,
249
+ logger: logger,
250
+ });
251
+ }
252
+ catch (e) {
253
+ error = e;
254
+ }
255
+ assert.ok(error instanceof HttpErrors.BadRequestError);
256
+ assert.equal(error.message, 'response body');
257
+ });
258
+ it('throws on timeout', async (context) => {
259
+ context.mock.method(global, 'fetch', () => {
260
+ const error = new Error();
261
+ error.name = 'TimeoutError';
262
+ throw error;
263
+ });
264
+ let error;
265
+ try {
266
+ await provider.get('/endpoint/123', {
267
+ credentials: { apiKey: 'apikey#1111' },
268
+ signal: new AbortController().signal,
269
+ logger: logger,
270
+ });
271
+ }
272
+ catch (e) {
273
+ error = e;
274
+ }
275
+ assert.ok(error instanceof HttpErrors.TimeoutError);
276
+ assert.equal(error.message, 'Request timeout');
277
+ });
278
+ it('throws on abort', async (context) => {
279
+ context.mock.method(global, 'fetch', () => {
280
+ const error = new Error();
281
+ error.name = 'AbortError';
282
+ throw error;
283
+ });
284
+ let error;
285
+ try {
286
+ await provider.get('/endpoint/123', {
287
+ credentials: { apiKey: 'apikey#1111' },
288
+ signal: new AbortController().signal,
289
+ logger: logger,
290
+ });
291
+ }
292
+ catch (e) {
293
+ error = e;
294
+ }
295
+ assert.ok(error instanceof HttpErrors.TimeoutError);
296
+ assert.equal(error.message, 'Request aborted');
297
+ });
298
+ it('throws on unknown errors', async (context) => {
299
+ context.mock.method(global, 'fetch', () => {
300
+ throw new Error('foo');
301
+ });
302
+ let error;
303
+ try {
304
+ await provider.get('/endpoint/123', {
305
+ credentials: { apiKey: 'apikey#1111' },
306
+ signal: new AbortController().signal,
307
+ logger: logger,
308
+ });
309
+ }
310
+ catch (e) {
311
+ error = e;
312
+ }
313
+ assert.ok(error instanceof HttpErrors.HttpError);
314
+ assert.equal(error.message, 'Unexpected error while calling the provider: "Error: foo"');
229
315
  });
230
316
  it('throws on status 429', async (context) => {
231
- const response = new Response(undefined, {
317
+ const response = new Response('response body', {
232
318
  status: 429,
233
319
  });
234
320
  context.mock.method(global, 'fetch', () => Promise.resolve(response));
235
- assert.rejects(() => provider.get('/endpoint/123', {
236
- credentials: { apiKey: 'apikey#1111' },
237
- logger: logger,
238
- }));
321
+ let error;
322
+ try {
323
+ await provider.get('/endpoint/123', {
324
+ credentials: { apiKey: 'apikey#1111' },
325
+ signal: new AbortController().signal,
326
+ logger: logger,
327
+ });
328
+ }
329
+ catch (e) {
330
+ error = e;
331
+ }
332
+ assert.ok(error instanceof HttpErrors.RateLimitExceededError);
333
+ assert.equal(error.message, 'response body');
239
334
  });
240
335
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-sdk",
3
- "version": "0.1.11",
3
+ "version": "1.0.0",
4
4
  "description": "Integration SDK",
5
5
  "type": "module",
6
6
  "types": "dist/src/index.d.ts",
@@ -36,8 +36,8 @@
36
36
  "@types/express": "4.x",
37
37
  "@types/node": "20.x",
38
38
  "@types/uuid": "9.x",
39
- "@typescript-eslint/eslint-plugin": "6.x",
40
- "@typescript-eslint/parser": "6.x",
39
+ "@typescript-eslint/eslint-plugin": "7.x",
40
+ "@typescript-eslint/parser": "7.x",
41
41
  "c8": "9.x",
42
42
  "eslint": "8.x",
43
43
  "prettier": "3.x",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@unito/integration-api": "0.x",
51
- "cachette": "1.x",
51
+ "cachette": "2.x",
52
52
  "express": "^5.0.0-beta.1",
53
53
  "uuid": "9.x"
54
54
  },
package/src/handler.ts CHANGED
@@ -16,31 +16,48 @@ import {
16
16
 
17
17
  /**
18
18
  * Handler called to get an individual item.
19
+ *
20
+ * @param context {@link GetItemContext}
21
+ * @returns The requested {@link API.Item}.
19
22
  */
20
23
  export type GetItemHandler = (context: GetItemContext<any, any>) => Promise<API.Item>;
21
24
 
22
25
  /**
23
26
  * Handler called to retrieve a collection of items.
27
+ *
28
+ * @param context {@link GetCollectionContext}
29
+ * @return An {@link API.Collection} containing requested items and a link to the next page, if applicable.
24
30
  */
25
31
  export type GetCollectionHandler = (context: GetCollectionContext<any, any>) => Promise<API.Collection>;
26
32
 
27
33
  /**
28
34
  * Handler called to create an item.
35
+ *
36
+ * @param context {@link CreateItemContext}
37
+ * @returns An {@link API.ItemSummary} containing a path to the created item.
29
38
  */
30
39
  export type CreateItemHandler = (context: CreateItemContext<any, any, any>) => Promise<API.ItemSummary>;
31
40
 
32
41
  /**
33
42
  * Handler called to update an item.
43
+ *
44
+ * @param context {@link UpdateItemContext}
45
+ * @returns The updated {@link API.Item}.
34
46
  */
35
47
  export type UpdateItemHandler = (context: UpdateItemContext<any, any, any>) => Promise<API.Item>;
36
48
 
37
49
  /**
38
50
  * Handler called to delete an item.
51
+ *
52
+ * @param context {@link DeleteItemContext}
39
53
  */
40
54
  export type DeleteItemHandler = (context: DeleteItemContext<any, any>) => Promise<void>;
41
55
 
42
56
  /**
43
57
  * Handler called to retrieve the account details associated with the credentials.
58
+ *
59
+ * @param context {@link GetCredentialAccountContext}
60
+ * @returns The {@link API.CredentialAccount} associated with the credentials.
44
61
  */
45
62
  export type GetCredentialAccountHandler = (
46
63
  context: GetCredentialAccountContext<any, any>,
@@ -48,6 +65,9 @@ export type GetCredentialAccountHandler = (
48
65
 
49
66
  /**
50
67
  * Handler called to parse the content of an incoming webhook.
68
+ *
69
+ * @param context {@link ParseWebhooksContext}
70
+ * @returns The parsed content of the webhook as a {@link API.WebhookParseResponsePayload}.
51
71
  */
52
72
  export type ParseWebhooksHandler = (
53
73
  context: ParseWebhooksContext<any, any, any>,
@@ -55,6 +75,8 @@ export type ParseWebhooksHandler = (
55
75
 
56
76
  /**
57
77
  * Handler called to subscribe or unsubscribe to a particular webhook.
78
+ *
79
+ * @param context {@link UpdateWebhookSubscriptionsContext}
58
80
  */
59
81
  export type UpdateWebhookSubscriptionsHandler = (
60
82
  context: UpdateWebhookSubscriptionsContext<any, any, any>,
@@ -62,11 +84,28 @@ export type UpdateWebhookSubscriptionsHandler = (
62
84
 
63
85
  /**
64
86
  * Handler called to acknowledge the reception of a webhook.
87
+ *
88
+ * @param context {@link AcknowledgeWebhooksContext}
89
+ * @returns The {@link API.WebhookAcknowledgeResponsePayload} to be sent back to the webhook provider.
65
90
  */
66
91
  export type AcknowledgeWebhooksHandler = (
67
92
  context: AcknowledgeWebhooksContext<any, any, any>,
68
93
  ) => Promise<API.WebhookAcknowledgeResponsePayload>;
69
94
 
95
+ /**
96
+ * Defines the implementation of the operations available for a given `Item`.
97
+ * - In some cases (e.g. defining the `root` or {@link https://dev.unito.io/docs/connectors/apiSpecification/credentialAccount | me}
98
+ * handlers), only a {@link GetItemHandler | getItem} handler is necessary.
99
+ * - In most cases, you will want to define {@link GetCollectionHandler | getCollection},
100
+ * most likely {@link GetItemHandler | getItem}, and any other handlers relevant to the item.
101
+ *
102
+ * The `ItemHandlers` object can contain any of the following:
103
+ * - {@link GetItemHandler | getItem}: A handler called to get an individual item.
104
+ * - {@link GetCollectionHandler | getCollection}: A handler called to retrieve a collection of items.
105
+ * - {@link CreateItemHandler | createItem}: A handler called to create an item.
106
+ * - {@link UpdateItemHandler | updateItem}: A handler called to update an item.
107
+ * - {@link DeleteItemHandler | deleteItem}: A handler called to delete an item.
108
+ */
70
109
  export type ItemHandlers = {
71
110
  getItem?: GetItemHandler;
72
111
  getCollection?: GetCollectionHandler;
@@ -234,6 +273,7 @@ export class Handler {
234
273
  selects: res.locals.selects,
235
274
  filters: res.locals.filters,
236
275
  logger: res.locals.logger,
276
+ signal: res.locals.signal,
237
277
  params: req.params,
238
278
  query: req.query,
239
279
  });
@@ -259,6 +299,7 @@ export class Handler {
259
299
  secrets: res.locals.secrets,
260
300
  body: req.body,
261
301
  logger: res.locals.logger,
302
+ signal: res.locals.signal,
262
303
  params: req.params,
263
304
  query: req.query,
264
305
  });
@@ -281,6 +322,7 @@ export class Handler {
281
322
  credentials: res.locals.credentials,
282
323
  secrets: res.locals.secrets,
283
324
  logger: res.locals.logger,
325
+ signal: res.locals.signal,
284
326
  params: req.params,
285
327
  query: req.query,
286
328
  });
@@ -306,6 +348,7 @@ export class Handler {
306
348
  secrets: res.locals.secrets,
307
349
  body: req.body,
308
350
  logger: res.locals.logger,
351
+ signal: res.locals.signal,
309
352
  params: req.params,
310
353
  query: req.query,
311
354
  });
@@ -328,6 +371,7 @@ export class Handler {
328
371
  credentials: res.locals.credentials,
329
372
  secrets: res.locals.secrets,
330
373
  logger: res.locals.logger,
374
+ signal: res.locals.signal,
331
375
  params: req.params,
332
376
  query: req.query,
333
377
  });
@@ -350,6 +394,7 @@ export class Handler {
350
394
  credentials: res.locals.credentials,
351
395
  secrets: res.locals.secrets,
352
396
  logger: res.locals.logger,
397
+ signal: res.locals.signal,
353
398
  params: req.params,
354
399
  query: req.query,
355
400
  });
@@ -369,6 +414,7 @@ export class Handler {
369
414
  const response = await handler({
370
415
  secrets: res.locals.secrets,
371
416
  logger: res.locals.logger,
417
+ signal: res.locals.signal,
372
418
  params: req.params,
373
419
  query: req.query,
374
420
  body: req.body,
@@ -389,6 +435,7 @@ export class Handler {
389
435
  const response = await handler({
390
436
  secrets: res.locals.secrets,
391
437
  logger: res.locals.logger,
438
+ signal: res.locals.signal,
392
439
  params: req.params,
393
440
  query: req.query,
394
441
  body: req.body,
@@ -415,6 +462,7 @@ export class Handler {
415
462
  credentials: res.locals.credentials,
416
463
  body: req.body,
417
464
  logger: res.locals.logger,
465
+ signal: res.locals.signal,
418
466
  params: req.params,
419
467
  query: req.query,
420
468
  });