@vouchfor/sdk 1.1.33 → 1.1.35

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.
@@ -0,0 +1,10 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(grep -l \"Router\\\\\\(\\\\\\)\" /home/david/dev/vouch-new/amplify/backend/function/restapi/lib/controllers/*.ts | xargs grep -L \"@openapi\")",
5
+ "Bash(for f:*)",
6
+ "Bash(cd /home/david/dev/vouch-new/amplify/backend/function/restapi/openapi && node -e \"const s = require\\('./components/schemas'\\); console.log\\(Object.keys\\(s\\).join\\(', '\\)\\)\" 2>&1)",
7
+ "Bash(cd /home/david/dev/vouch-new/amplify/backend/function/restapi/openapi && node -e \"const r = require\\('./components/responses'\\); console.log\\(Object.keys\\(r\\).join\\(', '\\)\\)\" 2>&1)"
8
+ ]
9
+ }
10
+ }
@@ -1,4 +1,5 @@
1
1
  const utils = require('../shared/utils');
2
+ const tasks = require('../shared/tasks');
2
3
 
3
4
  // set up env for local development
4
5
  // set env SDK_LOCAL_DEV to use default local development endpoints
@@ -25,6 +26,7 @@ class BaseService {
25
26
  this._client = client;
26
27
  this._apiKey = config.apiKey || '';
27
28
  this._integrationKey = config.integrationKey || '';
29
+ this._callbackUrl = config.callbackUrl || '';
28
30
  this._baseUrl = `${config.baseUrl}${basePath}`;
29
31
  this._logger = logger;
30
32
  this._utils = utils;
@@ -49,13 +51,87 @@ class BaseService {
49
51
  apiHeaders['x-integration-key'] = integrationKey;
50
52
  }
51
53
 
52
- return this._utils.request({
53
- body,
54
- headers: apiHeaders,
55
- method,
56
- url,
57
- logger: this._logger
58
- });
54
+ const elapsedTimeInSeconds = (start) => {
55
+ return ((Date.now() - start) / 1000).toFixed(3) + 's';
56
+ }
57
+
58
+ const logAsyncSuccess = ({ id, status, json, start }) => {
59
+ const elapsed = elapsedTimeInSeconds(start);
60
+ const response = JSON.stringify(json);
61
+ this._logger.info(
62
+ `async success for task: ${task.id} ++ ${elapsed}\n`
63
+ + `========================================\n`
64
+ + `Content-Type: application/json\n`
65
+ + `Content-Length: ${response.length}\n`
66
+ + '\n' + response + '\n'
67
+ + `========================================`);
68
+ }
69
+
70
+ const logAsyncFailure = ({ id, status, json, start }) => {
71
+ const elapsed = elapsedTimeInSeconds(start);
72
+ const response = JSON.stringify(json);
73
+ this._logger.info(
74
+ `async failure for task: ${task.id} ++ ${elapsed}\n`
75
+ + `========================================\n`
76
+ + `Content-Type: application/json\n`
77
+ + `Content-Length: ${response.length}\n`
78
+ + '\n' + response + '\n'
79
+ + `========================================`);
80
+ }
81
+
82
+ const registerAsyncResponse = () => {
83
+ if (this._callbackUrl) {
84
+ const start = Date.now();
85
+ const task = tasks.create();
86
+ apiHeaders['x-callback-url'] = this._callbackUrl + utils.queryString({ id: task.id });
87
+ const promise = task.promise
88
+ .then(({ status, json }) => {
89
+ logAsyncSuccess({ id: task.id, status, json, start });
90
+ return { json };
91
+ })
92
+ .catch(({ status, json }) => {
93
+ logAsyncFailure({ id: task.id, status, json, start });
94
+ throw json.error;
95
+ });
96
+ promise.catch(() => {});
97
+ return { id: task.id, promise };
98
+ }
99
+ return {};
100
+ }
101
+
102
+ const task = registerAsyncResponse();
103
+
104
+ let [res, cb]= await Promise.all([
105
+ this._utils.request({
106
+ body,
107
+ headers: apiHeaders,
108
+ method,
109
+ url,
110
+ logger: this._logger
111
+ }).then((res) => {
112
+ if (task.id && res.task !== task.id) {
113
+ tasks.cancel(task.id); // our callback url was ignored
114
+ }
115
+ return res;
116
+ }).catch((err) => {
117
+ return { error: err }
118
+ }),
119
+ task.promise || {}
120
+ ]);
121
+
122
+ if (task.id) {
123
+ if (res.task === task.id) {
124
+ res = cb.json; // we got the async response we expected
125
+ } else if (res.error && cb.json) {
126
+ res = cb.json; // api gateway failed, use async response
127
+ }
128
+ }
129
+
130
+ if (res.error) {
131
+ throw res.error;
132
+ }
133
+
134
+ return res;
59
135
  }
60
136
  }
61
137
 
@@ -0,0 +1,17 @@
1
+ const tasks = require('../shared/tasks');
2
+
3
+ class CallbackService {
4
+ response(id, body) {
5
+ const { status, json } = body || {};
6
+ if (!(id && status)) {
7
+ // invalid - do nothing
8
+ } else if (status < 400) {
9
+ tasks.respond(id, body);
10
+ } else {
11
+ tasks.fail(id, body);
12
+ }
13
+ }
14
+ }
15
+
16
+ module.exports = CallbackService;
17
+
@@ -11,9 +11,10 @@ module.exports = Object.freeze({
11
11
  compositions: require('./rest/compositionService'),
12
12
  files: require('./rest/fileService'),
13
13
  images: require('./rest/imageService'),
14
- audios: require('./rest/audioService'),
14
+ audio: require('./rest/audioService'),
15
15
  documents: require('./rest/documentService'),
16
16
  links: require('./rest/linkService'),
17
17
  advocacy: require('./rest/advocacyService'),
18
18
  utilities: require('./rest/utilityService'),
19
+ callback: require('./callbackService'),
19
20
  });
@@ -6,6 +6,7 @@ class BaseRestService extends BaseService {
6
6
  super(client, {
7
7
  apiKey: config.apiKey,
8
8
  integrationKey: config.integrationKey,
9
+ callbackUrl: config.callbackUrl,
9
10
  baseUrl: process.env.SDK_LOCAL_REST || `https://api${utils.getApiSuffix(config.env)}.vouchfor.com/v1`,
10
11
  basePath,
11
12
  env: config.env,
@@ -0,0 +1,72 @@
1
+ const crypto = require('node:crypto')
2
+
3
+ function generateId() {
4
+ const id = crypto.randomBytes(40)
5
+ .toString('base64url')
6
+ .replace(/[^a-zA-Z0-9]/g, '')
7
+ .slice(0, 10);
8
+ return id;
9
+ }
10
+
11
+ class TaskBroker {
12
+ constructor() {
13
+ this.pending = new Map();
14
+ }
15
+
16
+ create(timeoutMs = 120000) {
17
+ const id = generateId();
18
+
19
+ let resolveFn;
20
+ let rejectFn;
21
+
22
+ const promise = new Promise((resolve, reject) => {
23
+ resolveFn = resolve;
24
+ rejectFn = reject;
25
+ })
26
+
27
+ const timeout = setTimeout(() => {
28
+ if (!this.pending.has(id)) return;
29
+ this.pending.delete(id);
30
+ rejectFn({ status: 0, json: { error: 'TimedOut' } });
31
+ }, timeoutMs);
32
+
33
+ this.pending.set(id, {
34
+ resolve: value => {
35
+ clearTimeout(timeout);
36
+ this.pending.delete(id);
37
+ resolveFn(value);
38
+ },
39
+ reject: err => {
40
+ clearTimeout(timeout);
41
+ this.pending.delete(id);
42
+ rejectFn(err);
43
+ }
44
+ })
45
+
46
+ return { id, promise };
47
+ }
48
+
49
+ cancel(id) {
50
+ const entry = this.pending.get(id);
51
+ if (!entry) return false;
52
+ entry.resolve({ status: 0, json: { error: 'Cancelled' } });
53
+ return true;
54
+ }
55
+
56
+ respond(id, value) {
57
+ const entry = this.pending.get(id);
58
+ if (!entry) return false;
59
+ entry.resolve(value);
60
+ return true;
61
+ }
62
+
63
+ fail(id, value) {
64
+ const entry = this.pending.get(id);
65
+ if (!entry) return false;
66
+ entry.reject(value);
67
+ return true;
68
+ }
69
+ }
70
+
71
+ const broker = new TaskBroker()
72
+ module.exports = broker
@@ -108,7 +108,7 @@ module.exports = {
108
108
 
109
109
  const errors = [
110
110
  502, // bad gateway, the BE is deploying
111
- 504, // gatewat timeout, the BE will scale
111
+ //504 gateway timeout, do not retry!!
112
112
  ];
113
113
  const maxAttempts = 8;
114
114
  const interval = 1000;
package/lib/vouch.js CHANGED
@@ -3,6 +3,7 @@ class Vouch {
3
3
  this.config = Object.freeze({
4
4
  apiKey: config.apiKey,
5
5
  integrationKey: config.integrationKey,
6
+ callbackUrl: config.callbackUrl,
6
7
  env: config.env || 'prod',
7
8
  });
8
9
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vouchfor/sdk",
3
- "version": "1.1.33",
3
+ "version": "1.1.35",
4
4
  "description": "Vouch API SDK",
5
5
  "main": "lib/index.js",
6
6
  "repository": {
@@ -0,0 +1,21 @@
1
+ const Vouch = require("./lib/vouch");
2
+
3
+ const vouchClient = new Vouch({
4
+ env: 'dev',
5
+ integrationKey: 'b0883f06-84af-4108-8543-31874c335c36-kkr3Wy4CLY8C2g65UT79sgUfOIR2ZzkA9uQam3bTs4ZNdlSs7M',
6
+ callbackUrl: 'https://extrajudicial-melanie-unadministratively.ngrok-free.dev/callback'
7
+ }, console);
8
+
9
+ console.log(vouchClient);
10
+
11
+ const apiKey = 'kTYGShoaeg-QvraTZk9LmHNsxP4dWcye82uJB6Rf0XtIsgq7UaEcYpVhMDl3z';
12
+
13
+ (async () => {
14
+ const params = {
15
+ query: 'why',
16
+ limit: 2
17
+ };
18
+ const data = await vouchClient.campaigns.search(params, apiKey).catch(() => undefined);
19
+ console.log(data);
20
+ })();
21
+