@unito/integration-sdk 1.0.2 → 1.0.4
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/dist/src/handler.d.ts +12 -2
- package/dist/src/handler.js +35 -0
- package/dist/src/index.cjs +36 -1
- package/dist/src/resources/cache.js +2 -2
- package/dist/src/resources/context.d.ts +6 -0
- package/dist/test/resources/cache.test.js +1 -1
- package/dist/test/resources/provider.test.js +5 -0
- package/package.json +1 -1
- package/src/handler.ts +59 -0
- package/src/resources/cache.ts +2 -2
- package/src/resources/context.ts +7 -0
- package/test/resources/cache.test.ts +1 -1
- package/test/resources/provider.test.ts +6 -0
package/dist/src/handler.d.ts
CHANGED
|
@@ -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, AcknowledgeWebhooksContext } from './resources/context.js';
|
|
3
|
+
import { GetBlobContext, 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
|
*
|
|
@@ -35,6 +35,13 @@ export type UpdateItemHandler = (context: UpdateItemContext<any, any, any>) => P
|
|
|
35
35
|
* @param context {@link DeleteItemContext}
|
|
36
36
|
*/
|
|
37
37
|
export type DeleteItemHandler = (context: DeleteItemContext<any, any>) => Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Handler called to get a Binary Large Object.
|
|
40
|
+
*
|
|
41
|
+
* @param context {@link BlobItemContext}
|
|
42
|
+
* @returns A {@link ReadableStream} of the Blob.
|
|
43
|
+
*/
|
|
44
|
+
export type GetBlobHandler = (context: GetBlobContext<any, any>) => Promise<ReadableStream<Uint8Array>>;
|
|
38
45
|
/**
|
|
39
46
|
* Handler called to retrieve the account details associated with the credentials.
|
|
40
47
|
*
|
|
@@ -83,6 +90,9 @@ export type ItemHandlers = {
|
|
|
83
90
|
updateItem?: UpdateItemHandler;
|
|
84
91
|
deleteItem?: DeleteItemHandler;
|
|
85
92
|
};
|
|
93
|
+
export type BlobHandlers = {
|
|
94
|
+
getBlob: GetBlobHandler;
|
|
95
|
+
};
|
|
86
96
|
export type CredentialAccountHandlers = {
|
|
87
97
|
getCredentialAccount: GetCredentialAccountHandler;
|
|
88
98
|
};
|
|
@@ -95,7 +105,7 @@ export type WebhookSubscriptionHandlers = {
|
|
|
95
105
|
export type AcknowledgeWebhookHandlers = {
|
|
96
106
|
acknowledgeWebhooks: AcknowledgeWebhooksHandler;
|
|
97
107
|
};
|
|
98
|
-
export type HandlersInput = ItemHandlers | CredentialAccountHandlers | ParseWebhookHandlers | WebhookSubscriptionHandlers | AcknowledgeWebhookHandlers;
|
|
108
|
+
export type HandlersInput = ItemHandlers | BlobHandlers | CredentialAccountHandlers | ParseWebhookHandlers | WebhookSubscriptionHandlers | AcknowledgeWebhookHandlers;
|
|
99
109
|
export declare class Handler {
|
|
100
110
|
private path;
|
|
101
111
|
private pathWithIdentifier;
|
package/dist/src/handler.js
CHANGED
|
@@ -177,6 +177,41 @@ export class Handler {
|
|
|
177
177
|
res.status(204).send(null);
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
|
+
if (this.handlers.getBlob) {
|
|
181
|
+
console.debug(` Enabling getBlob at GET ${this.pathWithIdentifier}`);
|
|
182
|
+
const handler = this.handlers.getBlob;
|
|
183
|
+
router.get(this.pathWithIdentifier, async (req, res) => {
|
|
184
|
+
if (!res.locals.credentials) {
|
|
185
|
+
throw new UnauthorizedError();
|
|
186
|
+
}
|
|
187
|
+
const blob = await handler({
|
|
188
|
+
credentials: res.locals.credentials,
|
|
189
|
+
secrets: res.locals.secrets,
|
|
190
|
+
logger: res.locals.logger,
|
|
191
|
+
signal: res.locals.signal,
|
|
192
|
+
params: req.params,
|
|
193
|
+
query: req.query,
|
|
194
|
+
});
|
|
195
|
+
res.writeHead(200, {
|
|
196
|
+
'Content-Type': 'application/octet-stream',
|
|
197
|
+
});
|
|
198
|
+
const reader = blob.getReader();
|
|
199
|
+
let isDone = false;
|
|
200
|
+
try {
|
|
201
|
+
while (!isDone) {
|
|
202
|
+
const chunk = await reader.read();
|
|
203
|
+
isDone = chunk.done;
|
|
204
|
+
if (chunk.value) {
|
|
205
|
+
res.write(chunk.value);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
finally {
|
|
210
|
+
reader.releaseLock();
|
|
211
|
+
}
|
|
212
|
+
res.end();
|
|
213
|
+
});
|
|
214
|
+
}
|
|
180
215
|
if (this.handlers.getCredentialAccount) {
|
|
181
216
|
const handler = this.handlers.getCredentialAccount;
|
|
182
217
|
console.debug(` Enabling getCredentialAccount at GET ${this.pathWithIdentifier}`);
|
package/dist/src/index.cjs
CHANGED
|
@@ -212,7 +212,7 @@ class Cache {
|
|
|
212
212
|
* @returns A cache instance.
|
|
213
213
|
*/
|
|
214
214
|
static create(redisUrl) {
|
|
215
|
-
const cacheInstance = redisUrl ? new cachette.
|
|
215
|
+
const cacheInstance = redisUrl ? new cachette.RedisCache(redisUrl) : new cachette.LocalCache();
|
|
216
216
|
// Intended: the correlation id will be the same for all logs of Cachette.
|
|
217
217
|
const correlationId = uuid__namespace.v4();
|
|
218
218
|
const logger = new Logger({ correlation_id: correlationId });
|
|
@@ -692,6 +692,41 @@ class Handler {
|
|
|
692
692
|
res.status(204).send(null);
|
|
693
693
|
});
|
|
694
694
|
}
|
|
695
|
+
if (this.handlers.getBlob) {
|
|
696
|
+
console.debug(` Enabling getBlob at GET ${this.pathWithIdentifier}`);
|
|
697
|
+
const handler = this.handlers.getBlob;
|
|
698
|
+
router.get(this.pathWithIdentifier, async (req, res) => {
|
|
699
|
+
if (!res.locals.credentials) {
|
|
700
|
+
throw new UnauthorizedError();
|
|
701
|
+
}
|
|
702
|
+
const blob = await handler({
|
|
703
|
+
credentials: res.locals.credentials,
|
|
704
|
+
secrets: res.locals.secrets,
|
|
705
|
+
logger: res.locals.logger,
|
|
706
|
+
signal: res.locals.signal,
|
|
707
|
+
params: req.params,
|
|
708
|
+
query: req.query,
|
|
709
|
+
});
|
|
710
|
+
res.writeHead(200, {
|
|
711
|
+
'Content-Type': 'application/octet-stream',
|
|
712
|
+
});
|
|
713
|
+
const reader = blob.getReader();
|
|
714
|
+
let isDone = false;
|
|
715
|
+
try {
|
|
716
|
+
while (!isDone) {
|
|
717
|
+
const chunk = await reader.read();
|
|
718
|
+
isDone = chunk.done;
|
|
719
|
+
if (chunk.value) {
|
|
720
|
+
res.write(chunk.value);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
finally {
|
|
725
|
+
reader.releaseLock();
|
|
726
|
+
}
|
|
727
|
+
res.end();
|
|
728
|
+
});
|
|
729
|
+
}
|
|
695
730
|
if (this.handlers.getCredentialAccount) {
|
|
696
731
|
const handler = this.handlers.getCredentialAccount;
|
|
697
732
|
console.debug(` Enabling getCredentialAccount at GET ${this.pathWithIdentifier}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LocalCache, RedisCache } from 'cachette';
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
3
|
import Logger from './logger.js';
|
|
4
4
|
/**
|
|
@@ -78,7 +78,7 @@ export class Cache {
|
|
|
78
78
|
* @returns A cache instance.
|
|
79
79
|
*/
|
|
80
80
|
static create(redisUrl) {
|
|
81
|
-
const cacheInstance = redisUrl ? new
|
|
81
|
+
const cacheInstance = redisUrl ? new RedisCache(redisUrl) : new LocalCache();
|
|
82
82
|
// Intended: the correlation id will be the same for all logs of Cachette.
|
|
83
83
|
const correlationId = uuid.v4();
|
|
84
84
|
const logger = new Logger({ correlation_id: correlationId });
|
|
@@ -61,6 +61,12 @@ export type Context<P extends Maybe<Params> = Params, Q extends Maybe<Query> = Q
|
|
|
61
61
|
* @see {@link Context}
|
|
62
62
|
*/
|
|
63
63
|
export type GetItemContext<P extends Maybe<Params> = Empty, Q extends Query = Empty> = Context<P, Q>;
|
|
64
|
+
/**
|
|
65
|
+
* Context received by the `GetBlobHandler`, same as `GetItemContext`.
|
|
66
|
+
*
|
|
67
|
+
* @see {@link Context}
|
|
68
|
+
*/
|
|
69
|
+
export type GetBlobContext<P extends Maybe<Params> = Empty, Q extends Query = Empty> = Context<P, Q>;
|
|
64
70
|
/**
|
|
65
71
|
* Context received by the `GetCollectionHandler`.
|
|
66
72
|
*
|
|
@@ -10,7 +10,7 @@ describe('Cache', () => {
|
|
|
10
10
|
assert.ok(cache['cacheInstance'] instanceof LocalCache);
|
|
11
11
|
await cache['cacheInstance'].quit();
|
|
12
12
|
});
|
|
13
|
-
it('redis url
|
|
13
|
+
it('redis url tries to return a RedisCache', () => {
|
|
14
14
|
assert.throws(() => Cache.create('fakeredis'), Error, 'Invalid redis url fakereis.');
|
|
15
15
|
});
|
|
16
16
|
});
|
|
@@ -3,6 +3,11 @@ import { describe, it } from 'node:test';
|
|
|
3
3
|
import { Provider } from '../../src/resources/provider.js';
|
|
4
4
|
import * as HttpErrors from '../../src/httpErrors.js';
|
|
5
5
|
import Logger from '../../src/resources/logger.js';
|
|
6
|
+
// There is currently an issue with node 20.12 and fetch mocking. A quick fix is to first call fetch so it's getter
|
|
7
|
+
// get properly instantiated, which allow it to be mocked properly.
|
|
8
|
+
// Issue: https://github.com/nodejs/node/issues/52015
|
|
9
|
+
// PR fix: https://github.com/nodejs/node/pull/52275
|
|
10
|
+
globalThis.fetch = fetch;
|
|
6
11
|
describe('Provider', () => {
|
|
7
12
|
const provider = new Provider({
|
|
8
13
|
prepareRequest: requestOptions => {
|
package/package.json
CHANGED
package/src/handler.ts
CHANGED
|
@@ -3,6 +3,7 @@ import * as API from '@unito/integration-api';
|
|
|
3
3
|
import { InvalidHandler } from './errors.js';
|
|
4
4
|
import { UnauthorizedError, BadRequestError } from './httpErrors.js';
|
|
5
5
|
import {
|
|
6
|
+
GetBlobContext,
|
|
6
7
|
GetItemContext,
|
|
7
8
|
GetCollectionContext,
|
|
8
9
|
CreateItemContext,
|
|
@@ -53,6 +54,14 @@ export type UpdateItemHandler = (context: UpdateItemContext<any, any, any>) => P
|
|
|
53
54
|
*/
|
|
54
55
|
export type DeleteItemHandler = (context: DeleteItemContext<any, any>) => Promise<void>;
|
|
55
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Handler called to get a Binary Large Object.
|
|
59
|
+
*
|
|
60
|
+
* @param context {@link BlobItemContext}
|
|
61
|
+
* @returns A {@link ReadableStream} of the Blob.
|
|
62
|
+
*/
|
|
63
|
+
export type GetBlobHandler = (context: GetBlobContext<any, any>) => Promise<ReadableStream<Uint8Array>>;
|
|
64
|
+
|
|
56
65
|
/**
|
|
57
66
|
* Handler called to retrieve the account details associated with the credentials.
|
|
58
67
|
*
|
|
@@ -114,6 +123,10 @@ export type ItemHandlers = {
|
|
|
114
123
|
deleteItem?: DeleteItemHandler;
|
|
115
124
|
};
|
|
116
125
|
|
|
126
|
+
export type BlobHandlers = {
|
|
127
|
+
getBlob: GetBlobHandler;
|
|
128
|
+
};
|
|
129
|
+
|
|
117
130
|
export type CredentialAccountHandlers = {
|
|
118
131
|
getCredentialAccount: GetCredentialAccountHandler;
|
|
119
132
|
};
|
|
@@ -132,6 +145,7 @@ export type AcknowledgeWebhookHandlers = {
|
|
|
132
145
|
|
|
133
146
|
export type HandlersInput =
|
|
134
147
|
| ItemHandlers
|
|
148
|
+
| BlobHandlers
|
|
135
149
|
| CredentialAccountHandlers
|
|
136
150
|
| ParseWebhookHandlers
|
|
137
151
|
| WebhookSubscriptionHandlers
|
|
@@ -139,6 +153,7 @@ export type HandlersInput =
|
|
|
139
153
|
|
|
140
154
|
type Handlers = Partial<
|
|
141
155
|
ItemHandlers &
|
|
156
|
+
BlobHandlers &
|
|
142
157
|
CredentialAccountHandlers &
|
|
143
158
|
ParseWebhookHandlers &
|
|
144
159
|
WebhookSubscriptionHandlers &
|
|
@@ -380,6 +395,50 @@ export class Handler {
|
|
|
380
395
|
});
|
|
381
396
|
}
|
|
382
397
|
|
|
398
|
+
if (this.handlers.getBlob) {
|
|
399
|
+
console.debug(` Enabling getBlob at GET ${this.pathWithIdentifier}`);
|
|
400
|
+
|
|
401
|
+
const handler = this.handlers.getBlob;
|
|
402
|
+
|
|
403
|
+
router.get(this.pathWithIdentifier, async (req, res) => {
|
|
404
|
+
if (!res.locals.credentials) {
|
|
405
|
+
throw new UnauthorizedError();
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
const blob = await handler({
|
|
409
|
+
credentials: res.locals.credentials,
|
|
410
|
+
secrets: res.locals.secrets,
|
|
411
|
+
logger: res.locals.logger,
|
|
412
|
+
signal: res.locals.signal,
|
|
413
|
+
params: req.params,
|
|
414
|
+
query: req.query,
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
res.writeHead(200, {
|
|
418
|
+
'Content-Type': 'application/octet-stream',
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
const reader = blob.getReader();
|
|
422
|
+
|
|
423
|
+
let isDone = false;
|
|
424
|
+
|
|
425
|
+
try {
|
|
426
|
+
while (!isDone) {
|
|
427
|
+
const chunk = await reader.read();
|
|
428
|
+
isDone = chunk.done;
|
|
429
|
+
|
|
430
|
+
if (chunk.value) {
|
|
431
|
+
res.write(chunk.value);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
} finally {
|
|
435
|
+
reader.releaseLock();
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
res.end();
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
383
442
|
if (this.handlers.getCredentialAccount) {
|
|
384
443
|
const handler = this.handlers.getCredentialAccount;
|
|
385
444
|
|
package/src/resources/cache.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LocalCache, CacheInstance, FetchingFunction, CachableValue, RedisCache } from 'cachette';
|
|
2
2
|
import * as uuid from 'uuid';
|
|
3
3
|
import Logger from './logger.js';
|
|
4
4
|
|
|
@@ -92,7 +92,7 @@ export class Cache {
|
|
|
92
92
|
* @returns A cache instance.
|
|
93
93
|
*/
|
|
94
94
|
public static create(redisUrl?: string): Cache {
|
|
95
|
-
const cacheInstance: CacheInstance = redisUrl ? new
|
|
95
|
+
const cacheInstance: CacheInstance = redisUrl ? new RedisCache(redisUrl) : new LocalCache();
|
|
96
96
|
|
|
97
97
|
// Intended: the correlation id will be the same for all logs of Cachette.
|
|
98
98
|
const correlationId = uuid.v4();
|
package/src/resources/context.ts
CHANGED
|
@@ -67,6 +67,13 @@ export type Context<P extends Maybe<Params> = Params, Q extends Maybe<Query> = Q
|
|
|
67
67
|
*/
|
|
68
68
|
export type GetItemContext<P extends Maybe<Params> = Empty, Q extends Query = Empty> = Context<P, Q>;
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Context received by the `GetBlobHandler`, same as `GetItemContext`.
|
|
72
|
+
*
|
|
73
|
+
* @see {@link Context}
|
|
74
|
+
*/
|
|
75
|
+
export type GetBlobContext<P extends Maybe<Params> = Empty, Q extends Query = Empty> = Context<P, Q>;
|
|
76
|
+
|
|
70
77
|
/**
|
|
71
78
|
* Context received by the `GetCollectionHandler`.
|
|
72
79
|
*
|
|
@@ -14,7 +14,7 @@ describe('Cache', () => {
|
|
|
14
14
|
await cache['cacheInstance'].quit();
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('redis url
|
|
17
|
+
it('redis url tries to return a RedisCache', () => {
|
|
18
18
|
assert.throws(() => Cache.create('fakeredis'), Error, 'Invalid redis url fakereis.');
|
|
19
19
|
});
|
|
20
20
|
});
|
|
@@ -5,6 +5,12 @@ import { Provider } from '../../src/resources/provider.js';
|
|
|
5
5
|
import * as HttpErrors from '../../src/httpErrors.js';
|
|
6
6
|
import Logger from '../../src/resources/logger.js';
|
|
7
7
|
|
|
8
|
+
// There is currently an issue with node 20.12 and fetch mocking. A quick fix is to first call fetch so it's getter
|
|
9
|
+
// get properly instantiated, which allow it to be mocked properly.
|
|
10
|
+
// Issue: https://github.com/nodejs/node/issues/52015
|
|
11
|
+
// PR fix: https://github.com/nodejs/node/pull/52275
|
|
12
|
+
globalThis.fetch = fetch;
|
|
13
|
+
|
|
8
14
|
describe('Provider', () => {
|
|
9
15
|
const provider = new Provider({
|
|
10
16
|
prepareRequest: requestOptions => {
|