@unito/integration-sdk 0.1.8 → 0.1.10

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.
@@ -1,6 +1,6 @@
1
1
  import { Router } from 'express';
2
2
  import * as API from '@unito/integration-api';
3
- import { GetItemContext, GetCollectionContext, CreateItemContext, UpdateItemContext, DeleteItemContext, GetCredentialAccountContext, ParseWebhooksContext, UpdateWebhookSubscriptionsContext, AckknowledgeWebhooksContext } from './resources/context.js';
3
+ import { GetItemContext, GetCollectionContext, CreateItemContext, UpdateItemContext, DeleteItemContext, GetCredentialAccountContext, ParseWebhooksContext, UpdateWebhookSubscriptionsContext, AcknowledgeWebhooksContext } from './resources/context.js';
4
4
  /**
5
5
  * Handler called to get an individual item.
6
6
  */
@@ -36,25 +36,25 @@ export type UpdateWebhookSubscriptionsHandler = (context: UpdateWebhookSubscript
36
36
  /**
37
37
  * Handler called to acknowledge the reception of a webhook.
38
38
  */
39
- export type AckknowledgeWebhooksHandler = (context: AckknowledgeWebhooksContext<any, any, any>) => Promise<API.WebhookAcknowledgeResponsePayload>;
40
- type ItemHandlers = {
39
+ export type AcknowledgeWebhooksHandler = (context: AcknowledgeWebhooksContext<any, any, any>) => Promise<API.WebhookAcknowledgeResponsePayload>;
40
+ export type ItemHandlers = {
41
41
  getItem?: GetItemHandler;
42
42
  getCollection?: GetCollectionHandler;
43
43
  createItem?: CreateItemHandler;
44
44
  updateItem?: UpdateItemHandler;
45
45
  deleteItem?: DeleteItemHandler;
46
46
  };
47
- type CredentialAccountHandlers = {
47
+ export type CredentialAccountHandlers = {
48
48
  getCredentialAccount: GetCredentialAccountHandler;
49
49
  };
50
- type ParseWebhookHandlers = {
50
+ export type ParseWebhookHandlers = {
51
51
  parseWebhooks: ParseWebhooksHandler;
52
52
  };
53
- type WebhookSubscriptionHandlers = {
53
+ export type WebhookSubscriptionHandlers = {
54
54
  updateWebhookSubscriptions: UpdateWebhookSubscriptionsHandler;
55
55
  };
56
- type AcknowledgeWebhookHandlers = {
57
- acknowledgeWebhooks: AckknowledgeWebhooksHandler;
56
+ export type AcknowledgeWebhookHandlers = {
57
+ acknowledgeWebhooks: AcknowledgeWebhooksHandler;
58
58
  };
59
59
  export type HandlersInput = ItemHandlers | CredentialAccountHandlers | ParseWebhookHandlers | WebhookSubscriptionHandlers | AcknowledgeWebhookHandlers;
60
60
  export declare class Handler {
@@ -64,4 +64,3 @@ export declare class Handler {
64
64
  constructor(inputPath: string, handlers: HandlersInput);
65
65
  generate(): Router;
66
66
  }
67
- export {};
@@ -90,6 +90,7 @@ export class Handler {
90
90
  }
91
91
  const collection = await handler({
92
92
  credentials: res.locals.credentials,
93
+ secrets: res.locals.secrets,
93
94
  selects: res.locals.selects,
94
95
  filters: res.locals.filters,
95
96
  logger: res.locals.logger,
@@ -109,6 +110,7 @@ export class Handler {
109
110
  assertCreateItemRequestPayload(req.body);
110
111
  const createItemSummary = await handler({
111
112
  credentials: res.locals.credentials,
113
+ secrets: res.locals.secrets,
112
114
  body: req.body,
113
115
  logger: res.locals.logger,
114
116
  params: req.params,
@@ -126,6 +128,7 @@ export class Handler {
126
128
  }
127
129
  const item = await handler({
128
130
  credentials: res.locals.credentials,
131
+ secrets: res.locals.secrets,
129
132
  logger: res.locals.logger,
130
133
  params: req.params,
131
134
  query: req.query,
@@ -143,6 +146,7 @@ export class Handler {
143
146
  assertUpdateItemRequestPayload(req.body);
144
147
  const item = await handler({
145
148
  credentials: res.locals.credentials,
149
+ secrets: res.locals.secrets,
146
150
  body: req.body,
147
151
  logger: res.locals.logger,
148
152
  params: req.params,
@@ -160,6 +164,7 @@ export class Handler {
160
164
  }
161
165
  await handler({
162
166
  credentials: res.locals.credentials,
167
+ secrets: res.locals.secrets,
163
168
  logger: res.locals.logger,
164
169
  params: req.params,
165
170
  query: req.query,
@@ -176,6 +181,7 @@ export class Handler {
176
181
  }
177
182
  const credentialAccount = await handler({
178
183
  credentials: res.locals.credentials,
184
+ secrets: res.locals.secrets,
179
185
  logger: res.locals.logger,
180
186
  params: req.params,
181
187
  query: req.query,
@@ -189,6 +195,7 @@ export class Handler {
189
195
  router.post(this.pathWithIdentifier, async (req, res) => {
190
196
  assertWebhookParseRequestPayload(req.body);
191
197
  const response = await handler({
198
+ secrets: res.locals.secrets,
192
199
  logger: res.locals.logger,
193
200
  params: req.params,
194
201
  query: req.query,
@@ -203,6 +210,7 @@ export class Handler {
203
210
  router.post(this.pathWithIdentifier, async (req, res) => {
204
211
  assertWebhookParseRequestPayload(req.body);
205
212
  const response = await handler({
213
+ secrets: res.locals.secrets,
206
214
  logger: res.locals.logger,
207
215
  params: req.params,
208
216
  query: req.query,
@@ -220,6 +228,7 @@ export class Handler {
220
228
  }
221
229
  assertWebhookSubscriptionRequestPayload(req.body);
222
230
  const response = await handler({
231
+ secrets: res.locals.secrets,
223
232
  credentials: res.locals.credentials,
224
233
  body: req.body,
225
234
  logger: res.locals.logger,
@@ -480,6 +480,7 @@ class Handler {
480
480
  }
481
481
  const collection = await handler({
482
482
  credentials: res.locals.credentials,
483
+ secrets: res.locals.secrets,
483
484
  selects: res.locals.selects,
484
485
  filters: res.locals.filters,
485
486
  logger: res.locals.logger,
@@ -499,6 +500,7 @@ class Handler {
499
500
  assertCreateItemRequestPayload(req.body);
500
501
  const createItemSummary = await handler({
501
502
  credentials: res.locals.credentials,
503
+ secrets: res.locals.secrets,
502
504
  body: req.body,
503
505
  logger: res.locals.logger,
504
506
  params: req.params,
@@ -516,6 +518,7 @@ class Handler {
516
518
  }
517
519
  const item = await handler({
518
520
  credentials: res.locals.credentials,
521
+ secrets: res.locals.secrets,
519
522
  logger: res.locals.logger,
520
523
  params: req.params,
521
524
  query: req.query,
@@ -533,6 +536,7 @@ class Handler {
533
536
  assertUpdateItemRequestPayload(req.body);
534
537
  const item = await handler({
535
538
  credentials: res.locals.credentials,
539
+ secrets: res.locals.secrets,
536
540
  body: req.body,
537
541
  logger: res.locals.logger,
538
542
  params: req.params,
@@ -550,6 +554,7 @@ class Handler {
550
554
  }
551
555
  await handler({
552
556
  credentials: res.locals.credentials,
557
+ secrets: res.locals.secrets,
553
558
  logger: res.locals.logger,
554
559
  params: req.params,
555
560
  query: req.query,
@@ -566,6 +571,7 @@ class Handler {
566
571
  }
567
572
  const credentialAccount = await handler({
568
573
  credentials: res.locals.credentials,
574
+ secrets: res.locals.secrets,
569
575
  logger: res.locals.logger,
570
576
  params: req.params,
571
577
  query: req.query,
@@ -579,6 +585,7 @@ class Handler {
579
585
  router.post(this.pathWithIdentifier, async (req, res) => {
580
586
  assertWebhookParseRequestPayload(req.body);
581
587
  const response = await handler({
588
+ secrets: res.locals.secrets,
582
589
  logger: res.locals.logger,
583
590
  params: req.params,
584
591
  query: req.query,
@@ -593,6 +600,7 @@ class Handler {
593
600
  router.post(this.pathWithIdentifier, async (req, res) => {
594
601
  assertWebhookParseRequestPayload(req.body);
595
602
  const response = await handler({
603
+ secrets: res.locals.secrets,
596
604
  logger: res.locals.logger,
597
605
  params: req.params,
598
606
  query: req.query,
@@ -610,6 +618,7 @@ class Handler {
610
618
  }
611
619
  assertWebhookSubscriptionRequestPayload(req.body);
612
620
  const response = await handler({
621
+ secrets: res.locals.secrets,
613
622
  credentials: res.locals.credentials,
614
623
  body: req.body,
615
624
  logger: res.locals.logger,
@@ -626,7 +635,7 @@ class Handler {
626
635
 
627
636
  function printErrorMessage(message) {
628
637
  console.error();
629
- console.error(`\x1b[31m Oups! Something went wrong! \x1b[0m`);
638
+ console.error(`\x1b[31m Oops! Something went wrong! \x1b[0m`);
630
639
  console.error(message);
631
640
  }
632
641
  class Integration {
@@ -11,7 +11,7 @@ import { shutdownCaches } from './resources/cache.js';
11
11
  import { Handler } from './handler.js';
12
12
  function printErrorMessage(message) {
13
13
  console.error();
14
- console.error(`\x1b[31m Oups! Something went wrong! \x1b[0m`);
14
+ console.error(`\x1b[31m Oops! Something went wrong! \x1b[0m`);
15
15
  console.error(message);
16
16
  }
17
17
  export default class Integration {
@@ -0,0 +1,13 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ declare global {
3
+ namespace Express {
4
+ interface Locals {
5
+ secrets: Secrets;
6
+ }
7
+ }
8
+ }
9
+ export type Secrets = {
10
+ [keys: string]: unknown;
11
+ };
12
+ declare const middleware: (req: Request, res: Response, next: NextFunction) => void;
13
+ export default middleware;
@@ -0,0 +1,17 @@
1
+ import { BadRequestError } from '../httpErrors.js';
2
+ const SECRETS_HEADER = 'X-Unito-Secrets';
3
+ const middleware = (req, res, next) => {
4
+ const secretsHeader = req.header(SECRETS_HEADER);
5
+ if (secretsHeader) {
6
+ let secrets;
7
+ try {
8
+ secrets = JSON.parse(Buffer.from(secretsHeader, 'base64').toString('utf8'));
9
+ }
10
+ catch {
11
+ throw new BadRequestError(`Malformed HTTP header ${SECRETS_HEADER}`);
12
+ }
13
+ res.locals.secrets = secrets;
14
+ }
15
+ next();
16
+ };
17
+ export default middleware;
@@ -1,14 +1,21 @@
1
1
  import * as API from '@unito/integration-api';
2
2
  import Logger from './logger.js';
3
3
  import { Credentials } from '../middlewares/credentials.js';
4
+ import { Secrets } from 'src/middlewares/secrets.js';
4
5
  import { Filter } from '../middlewares/filters.js';
5
- type Context<P extends Record<string, string>, Q extends ParsedQueryString> = {
6
+ export type Context<P extends Record<string, string>, Q extends ParsedQueryString> = {
6
7
  /**
7
8
  * The parsed credentials associated with the request through the X-Unito-Credentials header.
8
9
  *
9
10
  * Will contain the keys for the variables defined in the corresponding configuration's authorization.
10
11
  */
11
12
  credentials: Credentials;
13
+ /**
14
+ * The parsed secrets associated with the request through the X-Unito-Secrets header.
15
+ *
16
+ * Will contain the keys for the secrets defined in the corresponding configuration's secrets.
17
+ */
18
+ secrets: Secrets;
12
19
  /**
13
20
  * The logger pre decorated with the correlation ID and the additionnal metadata provided through the request headers.
14
21
  */
@@ -69,7 +76,7 @@ export type ParseWebhooksContext<P extends Record<string, string> = Record<strin
69
76
  export type UpdateWebhookSubscriptionsContext<P extends Record<string, string> = Record<string, never>, Q extends Record<string, string> = Record<string, never>, B extends API.WebhookSubscriptionRequestPayload = API.WebhookSubscriptionRequestPayload> = Context<P, Q> & {
70
77
  body: B;
71
78
  };
72
- export type AckknowledgeWebhooksContext<P extends Record<string, string> = Record<string, never>, Q extends Record<string, string> = Record<string, never>, B extends API.WebhookParseRequestPayload = API.WebhookParseRequestPayload> = Omit<Context<P, Q>, 'credentials'> & {
79
+ export type AcknowledgeWebhooksContext<P extends Record<string, string> = Record<string, never>, Q extends Record<string, string> = Record<string, never>, B extends API.WebhookParseRequestPayload = API.WebhookParseRequestPayload> = Omit<Context<P, Q>, 'credentials'> & {
73
80
  body: B;
74
81
  };
75
82
  interface ParsedQueryString {
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import assert from 'node:assert/strict';
2
+ import { describe, it } from 'node:test';
3
+ import middleware from '../../src/middlewares/secrets.js';
4
+ import { BadRequestError } from '../../src/httpErrors.js';
5
+ describe('secrets middleware', () => {
6
+ it('uses header', () => {
7
+ const secrets = Buffer.from(JSON.stringify({
8
+ chut: 'abc',
9
+ })).toString('base64');
10
+ const request = { header: (_key) => secrets };
11
+ const response = { locals: {} };
12
+ middleware(request, response, () => { });
13
+ assert.deepEqual(response.locals, {
14
+ secrets: {
15
+ chut: 'abc',
16
+ },
17
+ });
18
+ });
19
+ it('malformed header', async () => {
20
+ const request = { header: (_key) => 'nope' };
21
+ const response = { locals: {} };
22
+ assert.throws(() => middleware(request, response, () => { }), BadRequestError);
23
+ });
24
+ it('undefined', () => {
25
+ const response = { locals: {} };
26
+ assert.deepEqual(response.locals, {});
27
+ });
28
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unito/integration-sdk",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Integration SDK",
5
5
  "type": "module",
6
6
  "types": "dist/src/index.d.ts",
package/src/handler.ts CHANGED
@@ -11,7 +11,7 @@ import {
11
11
  GetCredentialAccountContext,
12
12
  ParseWebhooksContext,
13
13
  UpdateWebhookSubscriptionsContext,
14
- AckknowledgeWebhooksContext,
14
+ AcknowledgeWebhooksContext,
15
15
  } from './resources/context.js';
16
16
 
17
17
  /**
@@ -63,11 +63,11 @@ export type UpdateWebhookSubscriptionsHandler = (
63
63
  /**
64
64
  * Handler called to acknowledge the reception of a webhook.
65
65
  */
66
- export type AckknowledgeWebhooksHandler = (
67
- context: AckknowledgeWebhooksContext<any, any, any>,
66
+ export type AcknowledgeWebhooksHandler = (
67
+ context: AcknowledgeWebhooksContext<any, any, any>,
68
68
  ) => Promise<API.WebhookAcknowledgeResponsePayload>;
69
69
 
70
- type ItemHandlers = {
70
+ export type ItemHandlers = {
71
71
  getItem?: GetItemHandler;
72
72
  getCollection?: GetCollectionHandler;
73
73
  createItem?: CreateItemHandler;
@@ -75,20 +75,20 @@ type ItemHandlers = {
75
75
  deleteItem?: DeleteItemHandler;
76
76
  };
77
77
 
78
- type CredentialAccountHandlers = {
78
+ export type CredentialAccountHandlers = {
79
79
  getCredentialAccount: GetCredentialAccountHandler;
80
80
  };
81
81
 
82
- type ParseWebhookHandlers = {
82
+ export type ParseWebhookHandlers = {
83
83
  parseWebhooks: ParseWebhooksHandler;
84
84
  };
85
85
 
86
- type WebhookSubscriptionHandlers = {
86
+ export type WebhookSubscriptionHandlers = {
87
87
  updateWebhookSubscriptions: UpdateWebhookSubscriptionsHandler;
88
88
  };
89
89
 
90
- type AcknowledgeWebhookHandlers = {
91
- acknowledgeWebhooks: AckknowledgeWebhooksHandler;
90
+ export type AcknowledgeWebhookHandlers = {
91
+ acknowledgeWebhooks: AcknowledgeWebhooksHandler;
92
92
  };
93
93
 
94
94
  export type HandlersInput =
@@ -230,6 +230,7 @@ export class Handler {
230
230
 
231
231
  const collection = await handler({
232
232
  credentials: res.locals.credentials,
233
+ secrets: res.locals.secrets,
233
234
  selects: res.locals.selects,
234
235
  filters: res.locals.filters,
235
236
  logger: res.locals.logger,
@@ -255,6 +256,7 @@ export class Handler {
255
256
 
256
257
  const createItemSummary = await handler({
257
258
  credentials: res.locals.credentials,
259
+ secrets: res.locals.secrets,
258
260
  body: req.body,
259
261
  logger: res.locals.logger,
260
262
  params: req.params,
@@ -277,6 +279,7 @@ export class Handler {
277
279
 
278
280
  const item = await handler({
279
281
  credentials: res.locals.credentials,
282
+ secrets: res.locals.secrets,
280
283
  logger: res.locals.logger,
281
284
  params: req.params,
282
285
  query: req.query,
@@ -300,6 +303,7 @@ export class Handler {
300
303
 
301
304
  const item = await handler({
302
305
  credentials: res.locals.credentials,
306
+ secrets: res.locals.secrets,
303
307
  body: req.body,
304
308
  logger: res.locals.logger,
305
309
  params: req.params,
@@ -322,6 +326,7 @@ export class Handler {
322
326
 
323
327
  await handler({
324
328
  credentials: res.locals.credentials,
329
+ secrets: res.locals.secrets,
325
330
  logger: res.locals.logger,
326
331
  params: req.params,
327
332
  query: req.query,
@@ -343,6 +348,7 @@ export class Handler {
343
348
 
344
349
  const credentialAccount = await handler({
345
350
  credentials: res.locals.credentials,
351
+ secrets: res.locals.secrets,
346
352
  logger: res.locals.logger,
347
353
  params: req.params,
348
354
  query: req.query,
@@ -361,6 +367,7 @@ export class Handler {
361
367
  assertWebhookParseRequestPayload(req.body);
362
368
 
363
369
  const response = await handler({
370
+ secrets: res.locals.secrets,
364
371
  logger: res.locals.logger,
365
372
  params: req.params,
366
373
  query: req.query,
@@ -380,6 +387,7 @@ export class Handler {
380
387
  assertWebhookParseRequestPayload(req.body);
381
388
 
382
389
  const response = await handler({
390
+ secrets: res.locals.secrets,
383
391
  logger: res.locals.logger,
384
392
  params: req.params,
385
393
  query: req.query,
@@ -403,6 +411,7 @@ export class Handler {
403
411
  assertWebhookSubscriptionRequestPayload(req.body);
404
412
 
405
413
  const response = await handler({
414
+ secrets: res.locals.secrets,
406
415
  credentials: res.locals.credentials,
407
416
  body: req.body,
408
417
  logger: res.locals.logger,
@@ -14,7 +14,7 @@ import { HandlersInput, Handler } from './handler.js';
14
14
 
15
15
  function printErrorMessage(message: string) {
16
16
  console.error();
17
- console.error(`\x1b[31m Oups! Something went wrong! \x1b[0m`);
17
+ console.error(`\x1b[31m Oops! Something went wrong! \x1b[0m`);
18
18
  console.error(message);
19
19
  }
20
20
 
@@ -0,0 +1,35 @@
1
+ import { Request, Response, NextFunction } from 'express';
2
+ import { BadRequestError } from '../httpErrors.js';
3
+
4
+ declare global {
5
+ // eslint-disable-next-line @typescript-eslint/no-namespace
6
+ namespace Express {
7
+ interface Locals {
8
+ secrets: Secrets;
9
+ }
10
+ }
11
+ }
12
+
13
+ export type Secrets = { [keys: string]: unknown };
14
+
15
+ const SECRETS_HEADER = 'X-Unito-Secrets';
16
+
17
+ const middleware = (req: Request, res: Response, next: NextFunction) => {
18
+ const secretsHeader = req.header(SECRETS_HEADER);
19
+
20
+ if (secretsHeader) {
21
+ let secrets: Secrets;
22
+
23
+ try {
24
+ secrets = JSON.parse(Buffer.from(secretsHeader, 'base64').toString('utf8'));
25
+ } catch {
26
+ throw new BadRequestError(`Malformed HTTP header ${SECRETS_HEADER}`);
27
+ }
28
+
29
+ res.locals.secrets = secrets;
30
+ }
31
+
32
+ next();
33
+ };
34
+
35
+ export default middleware;
@@ -3,15 +3,22 @@ import * as API from '@unito/integration-api';
3
3
 
4
4
  import Logger from './logger.js';
5
5
  import { Credentials } from '../middlewares/credentials.js';
6
+ import { Secrets } from 'src/middlewares/secrets.js';
6
7
  import { Filter } from '../middlewares/filters.js';
7
8
 
8
- type Context<P extends Record<string, string>, Q extends ParsedQueryString> = {
9
+ export type Context<P extends Record<string, string>, Q extends ParsedQueryString> = {
9
10
  /**
10
11
  * The parsed credentials associated with the request through the X-Unito-Credentials header.
11
12
  *
12
13
  * Will contain the keys for the variables defined in the corresponding configuration's authorization.
13
14
  */
14
15
  credentials: Credentials;
16
+ /**
17
+ * The parsed secrets associated with the request through the X-Unito-Secrets header.
18
+ *
19
+ * Will contain the keys for the secrets defined in the corresponding configuration's secrets.
20
+ */
21
+ secrets: Secrets;
15
22
  /**
16
23
  * The logger pre decorated with the correlation ID and the additionnal metadata provided through the request headers.
17
24
  */
@@ -101,7 +108,7 @@ export type UpdateWebhookSubscriptionsContext<
101
108
  B extends API.WebhookSubscriptionRequestPayload = API.WebhookSubscriptionRequestPayload,
102
109
  > = Context<P, Q> & { body: B };
103
110
 
104
- export type AckknowledgeWebhooksContext<
111
+ export type AcknowledgeWebhooksContext<
105
112
  P extends Record<string, string> = Record<string, never>,
106
113
  Q extends Record<string, string> = Record<string, never>,
107
114
  B extends API.WebhookParseRequestPayload = API.WebhookParseRequestPayload,
@@ -0,0 +1,39 @@
1
+ import express from 'express';
2
+ import assert from 'node:assert/strict';
3
+ import { describe, it } from 'node:test';
4
+ import middleware from '../../src/middlewares/secrets.js';
5
+ import { BadRequestError } from '../../src/httpErrors.js';
6
+
7
+ describe('secrets middleware', () => {
8
+ it('uses header', () => {
9
+ const secrets = Buffer.from(
10
+ JSON.stringify({
11
+ chut: 'abc',
12
+ }),
13
+ ).toString('base64');
14
+
15
+ const request = { header: (_key: string) => secrets } as express.Request;
16
+ const response = { locals: {} } as express.Response;
17
+
18
+ middleware(request, response, () => {});
19
+
20
+ assert.deepEqual(response.locals, {
21
+ secrets: {
22
+ chut: 'abc',
23
+ },
24
+ });
25
+ });
26
+
27
+ it('malformed header', async () => {
28
+ const request = { header: (_key: string) => 'nope' } as express.Request;
29
+ const response = { locals: {} } as express.Response;
30
+
31
+ assert.throws(() => middleware(request, response, () => {}), BadRequestError);
32
+ });
33
+
34
+ it('undefined', () => {
35
+ const response = { locals: {} } as express.Response;
36
+
37
+ assert.deepEqual(response.locals, {});
38
+ });
39
+ });