@friggframework/core 1.1.4 → 1.1.5

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/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ # v1.1.5 (Tue Apr 09 2024)
2
+
3
+ #### 🐛 Bug Fix
4
+
5
+ - update router to include options and refresh [#301](https://github.com/friggframework/frigg/pull/301) ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
6
+ - consistent spacing ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
7
+ - add back the /api/entity POST of a credential with a tentative adjustment to implementation ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
8
+ - be consistent about not using redundant variables for the response json ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
9
+ - remove accidental newline ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
10
+ - fixes to router and stubs ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
11
+ - update router to include options and refresh for entities, integration config, and integration user actions ([@MichaelRyanWebber](https://github.com/MichaelRyanWebber))
12
+ - Bump version to: v1.1.4 \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
13
+ - Bump version to: v1.1.3 \[skip ci\] ([@seanspeaks](https://github.com/seanspeaks))
14
+
15
+ #### Authors: 2
16
+
17
+ - [@MichaelRyanWebber](https://github.com/MichaelRyanWebber)
18
+ - Sean Matthews ([@seanspeaks](https://github.com/seanspeaks))
19
+
20
+ ---
21
+
1
22
  # v1.1.4 (Fri Apr 05 2024)
2
23
 
3
24
  #### 🐛 Bug Fix
@@ -154,9 +154,33 @@ class IntegrationBase {
154
154
  return options;
155
155
  }
156
156
 
157
+ async refreshConfigOptions(params) {
158
+ const options = {
159
+ jsonSchema: {},
160
+ uiSchema: {},
161
+ }
162
+ return options
163
+ }
164
+
157
165
  async getUserActions() {
158
166
  return [];
159
167
  }
168
+
169
+ async getActionOptions() {
170
+ const options = {
171
+ jsonSchema: {},
172
+ uiSchema: {},
173
+ }
174
+ return options
175
+ }
176
+
177
+ async refreshActionOptions(params) {
178
+ const options = {
179
+ jsonSchema: {},
180
+ uiSchema: {},
181
+ }
182
+ return options
183
+ }
160
184
  }
161
185
 
162
186
  module.exports = { IntegrationBase };
@@ -89,12 +89,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
89
89
  );
90
90
  await integration.onCreate();
91
91
 
92
- // filtered set for results
93
- const response = await IntegrationHelper.getFormattedIntegration(
94
- integration.record
92
+ res.status(201).json(
93
+ await IntegrationHelper.getFormattedIntegration(integration.record)
95
94
  );
96
- res.status(201);
97
- res.json(response);
98
95
  })
99
96
  );
100
97
 
@@ -114,11 +111,9 @@ function setIntegrationRoutes(router, factory, getUserId) {
114
111
  );
115
112
  await integration.onUpdate(params);
116
113
 
117
- const response = await IntegrationHelper.getFormattedIntegration(
118
- integration.record
114
+ res.json(
115
+ await IntegrationHelper.getFormattedIntegration(integration.record)
119
116
  );
120
-
121
- res.json(response);
122
117
  })
123
118
  );
124
119
 
@@ -142,8 +137,7 @@ function setIntegrationRoutes(router, factory, getUserId) {
142
137
  params.integrationId
143
138
  );
144
139
 
145
- res.status(201);
146
- res.json({});
140
+ res.status(201).json({});
147
141
  })
148
142
  );
149
143
 
@@ -154,9 +148,21 @@ function setIntegrationRoutes(router, factory, getUserId) {
154
148
  ]);
155
149
  const integration =
156
150
  await integrationFactory.getInstanceFromIntegrationId(params);
157
- const results = await integration.getConfigOptions();
158
- // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
159
- res.json(results);
151
+ res.json(await integration.getConfigOptions());
152
+ })
153
+ );
154
+
155
+ router.route('/api/integrations/:integrationId/config/options/refresh').post(
156
+ catchAsyncError(async (req, res) => {
157
+ const params = checkRequiredParams(req.params, [
158
+ 'integrationId',
159
+ ]);
160
+ const integration =
161
+ await integrationFactory.getInstanceFromIntegrationId(params);
162
+
163
+ res.json(
164
+ await integration.refreshConfigOptions(req.body)
165
+ );
160
166
  })
161
167
  );
162
168
 
@@ -168,11 +174,25 @@ function setIntegrationRoutes(router, factory, getUserId) {
168
174
  ]);
169
175
  const integration =
170
176
  await integrationFactory.getInstanceFromIntegrationId(params);
171
- const results = await integration.getActionOptions(
172
- params.actionId
177
+
178
+ res.json(
179
+ await integration.getActionOptions(params.actionId)
180
+ );
181
+ })
182
+ );
183
+
184
+ router.route('/api/integrations/:integrationId/actions/:actionId/options/refresh').post(
185
+ catchAsyncError(async (req, res) => {
186
+ const params = checkRequiredParams(req.params, [
187
+ 'integrationId',
188
+ 'actionId'
189
+ ]);
190
+ const integration =
191
+ await integrationFactory.getInstanceFromIntegrationId(params);
192
+
193
+ res.json(
194
+ await integration.refreshActionOptions(params.actionId, req.body)
173
195
  );
174
- // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
175
- res.json(results);
176
196
  })
177
197
  );
178
198
 
@@ -184,14 +204,12 @@ function setIntegrationRoutes(router, factory, getUserId) {
184
204
  ]);
185
205
  const integration =
186
206
  await integrationFactory.getInstanceFromIntegrationId(params);
187
- const results = await integration.notify(
188
- params.actionId,
189
- req.body
207
+
208
+ res.json(
209
+ await integration.notify(params.actionId, req.body)
190
210
  );
191
- // We could perhaps augment router with dynamic options? Haven't decided yet, but here may be the place
192
- res.json(results);
193
211
  })
194
- )
212
+ );
195
213
 
196
214
  router.route('/api/integrations/:integrationId').get(
197
215
  catchAsyncError(async (req, res) => {
@@ -268,6 +286,7 @@ function setEntityRoutes(router, factory, getUserId) {
268
286
  `Error: EntityManager of type ${params.entityType} requires a valid url`
269
287
  );
270
288
  }
289
+
271
290
  res.json(await module.getAuthorizationRequirements());
272
291
  })
273
292
  );
@@ -278,35 +297,14 @@ function setEntityRoutes(router, factory, getUserId) {
278
297
  'entityType',
279
298
  'data',
280
299
  ]);
281
- console.log('post authorize', params);
282
300
  const module = await getModuleInstance(req, params.entityType);
283
- console.log('post authorize module', module);
284
- const results = await module.processAuthorizationCallback({
285
- userId: getUserId(req),
286
- data: params.data,
287
- });
288
-
289
- res.json(results);
290
- })
291
- );
292
301
 
293
- router.route('/api/entity/options/:credentialId').get(
294
- catchAsyncError(async (req, res) => {
295
- // TODO May want to pass along the user ID as well so credential ID's can't be fished???
296
- // TODO **flagging this for review** -MW
297
- const credential = await IntegrationHelper.getCredentialById(
298
- req.params.credentialId
302
+ res.json(
303
+ await module.processAuthorizationCallback({
304
+ userId: getUserId(req),
305
+ data: params.data,
306
+ })
299
307
  );
300
- if (credential.user._id.toString() !== getUserId(req)) {
301
- throw Boom.forbidden('Credential does not belong to user');
302
- }
303
-
304
- const params = checkRequiredParams(req.query, [
305
- 'entityType',
306
- ]);
307
- const module = await getModuleInstance(req, params.entityType);
308
-
309
- res.json(await module.getEntityOptions());
310
308
  })
311
309
  );
312
310
 
@@ -328,7 +326,36 @@ function setEntityRoutes(router, factory, getUserId) {
328
326
  }
329
327
 
330
328
  const module = await getModuleInstance(req, params.entityType);
331
- res.json(await module.findOrCreateEntity(params.data));
329
+ const entityDetails = await module.getEntityDetails(
330
+ module.api,
331
+ null,
332
+ null,
333
+ getUserId(req)
334
+ )
335
+
336
+ res.json(
337
+ await module.findOrCreateEntity(entityDetails)
338
+ );
339
+ })
340
+ );
341
+
342
+ router.route('/api/entity/options/:credentialId').get(
343
+ catchAsyncError(async (req, res) => {
344
+ // TODO May want to pass along the user ID as well so credential ID's can't be fished???
345
+ // TODO **flagging this for review** -MW
346
+ const credential = await IntegrationHelper.getCredentialById(
347
+ req.params.credentialId
348
+ );
349
+ if (credential.user._id.toString() !== getUserId(req)) {
350
+ throw Boom.forbidden('Credential does not belong to user');
351
+ }
352
+
353
+ const params = checkRequiredParams(req.query, [
354
+ 'entityType',
355
+ ]);
356
+ const module = await getModuleInstance(req, params.entityType);
357
+
358
+ res.json(await module.getEntityOptions());
332
359
  })
333
360
  );
334
361
 
@@ -352,7 +379,7 @@ function setEntityRoutes(router, factory, getUserId) {
352
379
  errors: [
353
380
  {
354
381
  title: 'Authentication Error',
355
- message: `There was an error with your ${module.constructor.getName()} Entity. Please reconnect/re-authenticate, or reach out to Support for assistance.`,
382
+ message: `There was an error with your ${module.getName()} Entity. Please reconnect/re-authenticate, or reach out to Support for assistance.`,
356
383
  timestamp: Date.now(),
357
384
  },
358
385
  ],
@@ -362,6 +389,60 @@ function setEntityRoutes(router, factory, getUserId) {
362
389
  }
363
390
  })
364
391
  );
392
+
393
+ router.route('/api/entities/:entityId').get(
394
+ catchAsyncError(async (req, res) => {
395
+ const params = checkRequiredParams(req.params, ['entityId']);
396
+ const module = await moduleFactory.getModuleInstanceFromEntityId(
397
+ params.entityId,
398
+ getUserId(req)
399
+ );
400
+
401
+ if (!module) {
402
+ throw Boom.notFound();
403
+ }
404
+
405
+ res.json(module.entity);
406
+ })
407
+ );
408
+
409
+ router.route('/api/entities/:entityId/options').post(
410
+ catchAsyncError(async (req, res) => {
411
+ const params = checkRequiredParams(req.params, [
412
+ 'entityId',
413
+ getUserId(req)
414
+ ]);
415
+ const module = await moduleFactory.getModuleInstanceFromEntityId(
416
+ params.entityId,
417
+ getUserId(req)
418
+ );
419
+
420
+ if (!module) {
421
+ throw Boom.notFound();
422
+ }
423
+
424
+ res.json(await module.getEntityOptions());
425
+ })
426
+ );
427
+
428
+ router.route('/api/entities/:entityId/options/refresh').post(
429
+ catchAsyncError(async (req, res) => {
430
+ const params = checkRequiredParams(req.params, [
431
+ 'entityId',
432
+ getUserId(req)
433
+ ]);
434
+ const module = await moduleFactory.getModuleInstanceFromEntityId(
435
+ params.entityId,
436
+ getUserId(req)
437
+ );
438
+
439
+ if (!module) {
440
+ throw Boom.notFound();
441
+ }
442
+
443
+ res.json(await module.refreshEntityOptions(req.body));
444
+ })
445
+ );
365
446
  }
366
447
 
367
448
  module.exports = { createIntegrationRouter, checkRequiredParams };
@@ -88,6 +88,12 @@ class Auther extends Delegate {
88
88
  const definition = get(params, 'definition');
89
89
  Auther.validateDefinition(definition);
90
90
  Object.assign(this, definition.requiredAuthMethods);
91
+ if (definition.getEntityOptions) {
92
+ this.getEntityOptions = definition.getEntityOptions;
93
+ }
94
+ if (definition.refreshEntityOptions) {
95
+ this.refreshEntityOptions = definition.refreshEntityOptions;
96
+ }
91
97
  this.name = definition.moduleName;
92
98
  this.modelName = definition.modelName;
93
99
  this.apiClass = definition.API;
@@ -263,12 +269,14 @@ class Auther extends Delegate {
263
269
  }
264
270
 
265
271
  async getEntityOptions() {
266
- // May not be needed if the callback already creates the entity, such as in situations
267
- // like HubSpot where the account is determined in the authorization flow.
268
- // This should only be used in situations such as FreshBooks where the user needs to make
269
- // an account decision on the front end.
270
272
  throw new Error(
271
- 'Entity requirement method getEntityOptions() is not defined in the class'
273
+ 'Method getEntityOptions() is not defined in the class'
274
+ );
275
+ }
276
+
277
+ async refreshEntityOptions() {
278
+ throw new Error(
279
+ 'Method refreshEntityOptions() is not defined in the class'
272
280
  );
273
281
  }
274
282
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@friggframework/core",
3
3
  "prettier": "@friggframework/prettier-config",
4
- "version": "1.1.4",
4
+ "version": "1.1.5",
5
5
  "dependencies": {
6
6
  "@hapi/boom": "^10.0.1",
7
7
  "aws-sdk": "^2.1200.0",
@@ -15,9 +15,9 @@
15
15
  "node-fetch": "^2.6.7"
16
16
  },
17
17
  "devDependencies": {
18
- "@friggframework/eslint-config": "^1.1.4",
19
- "@friggframework/prettier-config": "^1.1.4",
20
- "@friggframework/test": "^1.1.4",
18
+ "@friggframework/eslint-config": "^1.1.5",
19
+ "@friggframework/prettier-config": "^1.1.5",
20
+ "@friggframework/test": "^1.1.5",
21
21
  "@types/lodash": "^4.14.191",
22
22
  "@typescript-eslint/eslint-plugin": "^5.55.0",
23
23
  "chai": "^4.3.6",
@@ -49,5 +49,5 @@
49
49
  },
50
50
  "homepage": "https://github.com/friggframework/frigg#readme",
51
51
  "description": "",
52
- "gitHead": "29600061d60d711eaf83ca7016f18949e67f0c8c"
52
+ "gitHead": "1a53bc7153b3735729e4d881ca9d7677964293c9"
53
53
  }