@app-connect/core 1.7.0-beta.4 → 1.7.0-beta.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/README.md +77 -77
- package/{adapter → connector}/registry.js +66 -66
- package/handlers/admin.js +4 -4
- package/handlers/auth.js +5 -5
- package/handlers/contact.js +4 -4
- package/handlers/disposition.js +3 -3
- package/handlers/log.js +5 -5
- package/handlers/user.js +2 -2
- package/index.js +36 -36
- package/lib/analytics.js +3 -3
- package/lib/callLogComposer.js +2 -2
- package/lib/oauth.js +2 -2
- package/models/adminConfigModel.js +1 -0
- package/package.json +1 -1
- package/test/adapter/registry.test.js +109 -109
- package/test/handlers/auth.test.js +21 -21
- package/test/setup.js +9 -9
- /package/{adapter → connector}/mock.js +0 -0
package/README.md
CHANGED
|
@@ -5,7 +5,7 @@ Core package for RingCentral App Connect project providing modular APIs for CRM
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Modular API Design**: Flexible Express app setup with customizable middleware and routes
|
|
8
|
-
- **CRM
|
|
8
|
+
- **CRM Connector Registry**: Centralized connector management for multiple CRM platforms
|
|
9
9
|
- **Authentication**: OAuth and API key authentication support
|
|
10
10
|
- **Contact Management**: Find, create, and manage contacts across CRM platforms
|
|
11
11
|
- **Call Logging**: Comprehensive call and message logging capabilities
|
|
@@ -23,15 +23,15 @@ npm install @app-connect/core
|
|
|
23
23
|
### Basic Usage
|
|
24
24
|
|
|
25
25
|
```javascript
|
|
26
|
-
const { createCoreApp,
|
|
27
|
-
const
|
|
28
|
-
const manifest = require('./
|
|
29
|
-
// Set the default manifest for the
|
|
26
|
+
const { createCoreApp, connectorRegistry } = require('@app-connect/core');
|
|
27
|
+
const myCRMConnector = require('./connectors/myCRM');
|
|
28
|
+
const manifest = require('./connectors/manifest.json');
|
|
29
|
+
// Set the default manifest for the connector registry. This ensures that all connectors
|
|
30
30
|
// have access to the necessary configuration and metadata before registration.
|
|
31
|
-
|
|
32
|
-
// Register your CRM
|
|
33
|
-
// to ensure proper initialization of the
|
|
34
|
-
|
|
31
|
+
connectorRegistry.setDefaultManifest(manifest);
|
|
32
|
+
// Register your CRM connectors. The default manifest must be set before registration
|
|
33
|
+
// to ensure proper initialization of the connector with the required settings.
|
|
34
|
+
connectorRegistry.registerConnector('myCRM', myCRMConnector, manifest);
|
|
35
35
|
|
|
36
36
|
// Create Express app with all core functionality
|
|
37
37
|
const app = createCoreApp();
|
|
@@ -44,12 +44,12 @@ app.get('/my-custom-route', (req, res) => {
|
|
|
44
44
|
exports.getServer = () => app;
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
###
|
|
47
|
+
### Connector Interface Registration
|
|
48
48
|
|
|
49
|
-
The
|
|
49
|
+
The connector registry supports dynamic interface registration, allowing you to extend connector functionality without modifying the original connector:
|
|
50
50
|
|
|
51
51
|
```javascript
|
|
52
|
-
const {
|
|
52
|
+
const { connectorRegistry } = require('@app-connect/core');
|
|
53
53
|
|
|
54
54
|
// Register interface functions for a platform
|
|
55
55
|
async function customCreateCallLog({ user, contactInfo, authHeader, callLog, note }) {
|
|
@@ -78,32 +78,32 @@ async function customFindContact({ user, authHeader, phoneNumber }) {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
// Register interface functions
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
connectorRegistry.registerConnectorInterface('myCRM', 'createCallLog', customCreateCallLog);
|
|
82
|
+
connectorRegistry.registerConnectorInterface('myCRM', 'findContact', customFindContact);
|
|
83
83
|
|
|
84
|
-
// Register the base
|
|
85
|
-
|
|
84
|
+
// Register the base connector
|
|
85
|
+
connectorRegistry.registerConnector('myCRM', myCRMConnector);
|
|
86
86
|
|
|
87
|
-
// Get composed
|
|
88
|
-
const
|
|
87
|
+
// Get composed connector with interfaces
|
|
88
|
+
const composedConnector = connectorRegistry.getConnector('myCRM');
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
-
**Interface-Only
|
|
91
|
+
**Interface-Only Connectors (No Base Connector):**
|
|
92
92
|
|
|
93
93
|
```javascript
|
|
94
|
-
// Register only interface functions, no base
|
|
95
|
-
|
|
96
|
-
|
|
94
|
+
// Register only interface functions, no base connector
|
|
95
|
+
connectorRegistry.registerConnectorInterface('interfaceOnlyCRM', 'createCallLog', customCreateCallLog);
|
|
96
|
+
connectorRegistry.registerConnectorInterface('interfaceOnlyCRM', 'findContact', customFindContact);
|
|
97
97
|
|
|
98
|
-
// Get interface-only
|
|
99
|
-
const
|
|
100
|
-
console.log('Interface-only methods:', Object.keys(
|
|
98
|
+
// Get interface-only connector
|
|
99
|
+
const interfaceOnlyConnector = connectorRegistry.getConnector('interfaceOnlyCRM');
|
|
100
|
+
console.log('Interface-only methods:', Object.keys(interfaceOnlyConnector));
|
|
101
101
|
// Output: ['createCallLog', 'findContact']
|
|
102
102
|
|
|
103
|
-
// Later, you can add a base
|
|
104
|
-
|
|
105
|
-
const
|
|
106
|
-
console.log('Full
|
|
103
|
+
// Later, you can add a base connector
|
|
104
|
+
connectorRegistry.registerConnector('interfaceOnlyCRM', myCRMConnector);
|
|
105
|
+
const fullConnector = connectorRegistry.getConnector('interfaceOnlyCRM');
|
|
106
|
+
console.log('Full connector methods:', Object.keys(fullConnector));
|
|
107
107
|
// Output: ['getAuthType', 'getUserInfo', 'updateCallLog', 'unAuthorize', 'createContact', 'createCallLog', 'findContact']
|
|
108
108
|
```
|
|
109
109
|
|
|
@@ -115,15 +115,15 @@ const {
|
|
|
115
115
|
createCoreRouter,
|
|
116
116
|
createCoreMiddleware,
|
|
117
117
|
initializeCore,
|
|
118
|
-
|
|
118
|
+
connectorRegistry
|
|
119
119
|
} = require('@app-connect/core');
|
|
120
120
|
|
|
121
|
-
const
|
|
122
|
-
const manifest = require('./
|
|
121
|
+
const myCRMConnector = require('./connectors/myCRM');
|
|
122
|
+
const manifest = require('./connectors/manifest.json');
|
|
123
123
|
// Set manifest
|
|
124
|
-
|
|
125
|
-
// Register
|
|
126
|
-
|
|
124
|
+
connectorRegistry.setDefaultManifest(manifest);
|
|
125
|
+
// Register connectors
|
|
126
|
+
connectorRegistry.registerConnector('myCRM', myCRMConnector, manifest);
|
|
127
127
|
|
|
128
128
|
// Initialize core services
|
|
129
129
|
initializeCore();
|
|
@@ -181,24 +181,24 @@ Initializes core services (database, analytics).
|
|
|
181
181
|
- `skipDatabaseInit` (Boolean): Skip database initialization (default: false)
|
|
182
182
|
- `skipAnalyticsInit` (Boolean): Skip analytics initialization (default: false)
|
|
183
183
|
|
|
184
|
-
###
|
|
184
|
+
### Connector Registry
|
|
185
185
|
|
|
186
|
-
#### `
|
|
187
|
-
Sets the default manifest for
|
|
186
|
+
#### `connectorRegistry.setDefaultManifest(manifest)`
|
|
187
|
+
Sets the default manifest for connectors.
|
|
188
188
|
|
|
189
189
|
**Parameters:**
|
|
190
190
|
- `manifest` (Object): Default manifest
|
|
191
191
|
|
|
192
|
-
#### `
|
|
193
|
-
Registers a CRM
|
|
192
|
+
#### `connectorRegistry.registerConnector(name, connector, manifest)`
|
|
193
|
+
Registers a CRM connector.
|
|
194
194
|
|
|
195
195
|
**Parameters:**
|
|
196
|
-
- `name` (String):
|
|
197
|
-
- `
|
|
198
|
-
- `manifest` (Object, optional):
|
|
196
|
+
- `name` (String): Connector name
|
|
197
|
+
- `connector` (Object): Connector implementation
|
|
198
|
+
- `manifest` (Object, optional): Connector manifest
|
|
199
199
|
|
|
200
|
-
#### `
|
|
201
|
-
Registers an interface function for a specific platform that will be composed with the
|
|
200
|
+
#### `connectorRegistry.registerConnectorInterface(platformName, interfaceName, interfaceFunction)`
|
|
201
|
+
Registers an interface function for a specific platform that will be composed with the connector at retrieval time.
|
|
202
202
|
|
|
203
203
|
**Parameters:**
|
|
204
204
|
- `platformName` (String): Platform identifier (e.g., 'pipedrive', 'salesforce')
|
|
@@ -219,32 +219,32 @@ async function customCreateCallLog({ user, contactInfo, authHeader, callLog, not
|
|
|
219
219
|
};
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
-
|
|
222
|
+
connectorRegistry.registerConnectorInterface('myCRM', 'createCallLog', customCreateCallLog);
|
|
223
223
|
```
|
|
224
224
|
|
|
225
|
-
#### `
|
|
226
|
-
Retrieves a registered
|
|
225
|
+
#### `connectorRegistry.getConnector(name)`
|
|
226
|
+
Retrieves a registered connector with composed interfaces.
|
|
227
227
|
|
|
228
228
|
**Parameters:**
|
|
229
|
-
- `name` (String):
|
|
229
|
+
- `name` (String): Connector name
|
|
230
230
|
|
|
231
|
-
**Returns:** Composed
|
|
231
|
+
**Returns:** Composed connector object or interface-only object
|
|
232
232
|
|
|
233
233
|
**Behavior:**
|
|
234
|
-
- If
|
|
235
|
-
- If
|
|
236
|
-
- If no
|
|
237
|
-
- If no
|
|
234
|
+
- If connector exists and interfaces exist: Returns composed connector with both
|
|
235
|
+
- If connector exists but no interfaces: Returns original connector
|
|
236
|
+
- If no connector but interfaces exist: Returns object with just interface functions
|
|
237
|
+
- If no connector and no interfaces: Throws error
|
|
238
238
|
|
|
239
|
-
#### `
|
|
240
|
-
Retrieves the original
|
|
239
|
+
#### `connectorRegistry.getOriginalConnector(name)`
|
|
240
|
+
Retrieves the original connector without any composed interface functions.
|
|
241
241
|
|
|
242
242
|
**Parameters:**
|
|
243
|
-
- `name` (String):
|
|
243
|
+
- `name` (String): Connector name
|
|
244
244
|
|
|
245
|
-
**Returns:** Original
|
|
245
|
+
**Returns:** Original connector object
|
|
246
246
|
|
|
247
|
-
#### `
|
|
247
|
+
#### `connectorRegistry.getPlatformInterfaces(platformName)`
|
|
248
248
|
Returns a Map of registered interface functions for a platform.
|
|
249
249
|
|
|
250
250
|
**Parameters:**
|
|
@@ -252,7 +252,7 @@ Returns a Map of registered interface functions for a platform.
|
|
|
252
252
|
|
|
253
253
|
**Returns:** Map of interface functions
|
|
254
254
|
|
|
255
|
-
#### `
|
|
255
|
+
#### `connectorRegistry.hasPlatformInterface(platformName, interfaceName)`
|
|
256
256
|
Checks if a specific interface function is registered for a platform.
|
|
257
257
|
|
|
258
258
|
**Parameters:**
|
|
@@ -261,20 +261,20 @@ Checks if a specific interface function is registered for a platform.
|
|
|
261
261
|
|
|
262
262
|
**Returns:** Boolean indicating if interface exists
|
|
263
263
|
|
|
264
|
-
#### `
|
|
264
|
+
#### `connectorRegistry.unregisterConnectorInterface(platformName, interfaceName)`
|
|
265
265
|
Unregisters an interface function for a platform.
|
|
266
266
|
|
|
267
267
|
**Parameters:**
|
|
268
268
|
- `platformName` (String): Platform identifier
|
|
269
269
|
- `interfaceName` (String): Interface function name
|
|
270
270
|
|
|
271
|
-
#### `
|
|
272
|
-
Gets comprehensive information about an
|
|
271
|
+
#### `connectorRegistry.getConnectorCapabilities(platformName)`
|
|
272
|
+
Gets comprehensive information about an connector including its capabilities and registered interfaces.
|
|
273
273
|
|
|
274
274
|
**Parameters:**
|
|
275
275
|
- `platformName` (String): Platform identifier
|
|
276
276
|
|
|
277
|
-
**Returns:** Object with
|
|
277
|
+
**Returns:** Object with connector capabilities information
|
|
278
278
|
|
|
279
279
|
### Exported Components
|
|
280
280
|
|
|
@@ -377,29 +377,29 @@ The core package uses the following environment variables:
|
|
|
377
377
|
- `IS_PROD` - Production environment flag
|
|
378
378
|
- `DYNAMODB_LOCALHOST` - Local DynamoDB endpoint for development, used for lock cache
|
|
379
379
|
|
|
380
|
-
##
|
|
380
|
+
## Connector Interface Registration Benefits
|
|
381
381
|
|
|
382
382
|
### Key Features
|
|
383
383
|
|
|
384
|
-
- **Composition over Mutation**: Interface functions are composed with
|
|
385
|
-
- **Dynamic Registration**: Register interface functions before or after
|
|
386
|
-
- **Immutability**: Original
|
|
387
|
-
- **Clean Separation**: Interface functions are kept separate from core
|
|
388
|
-
- **Flexibility**: Support for interface-only
|
|
384
|
+
- **Composition over Mutation**: Interface functions are composed with connectors at retrieval time, preserving the original connector
|
|
385
|
+
- **Dynamic Registration**: Register interface functions before or after connector registration
|
|
386
|
+
- **Immutability**: Original connector objects remain unchanged
|
|
387
|
+
- **Clean Separation**: Interface functions are kept separate from core connector logic
|
|
388
|
+
- **Flexibility**: Support for interface-only connectors (no base connector required)
|
|
389
389
|
|
|
390
390
|
### Best Practices
|
|
391
391
|
|
|
392
|
-
1. **Register Required Interfaces**: Register all required interface functions before using the
|
|
392
|
+
1. **Register Required Interfaces**: Register all required interface functions before using the connector
|
|
393
393
|
2. **Use Descriptive Names**: Use clear, descriptive names for interface functions
|
|
394
394
|
3. **Handle Errors**: Implement proper error handling in interface functions
|
|
395
|
-
4. **Test Composed
|
|
395
|
+
4. **Test Composed Connectors**: Test the final composed connector to ensure interfaces work correctly
|
|
396
396
|
5. **Document Interfaces**: Document what each interface function does and expects
|
|
397
397
|
|
|
398
398
|
### Use Cases
|
|
399
399
|
|
|
400
|
-
- **Extending Existing
|
|
401
|
-
- **Progressive Enhancement**: Start with interfaces, add base
|
|
402
|
-
- **Testing**: Test interface functions separately from base
|
|
400
|
+
- **Extending Existing Connectors**: Add new functionality to existing connectors without modification
|
|
401
|
+
- **Progressive Enhancement**: Start with interfaces, add base connector later
|
|
402
|
+
- **Testing**: Test interface functions separately from base connectors
|
|
403
403
|
- **Modular Development**: Develop interface functions independently
|
|
404
404
|
- **Plugin Architecture**: Create pluggable interface functions for different scenarios
|
|
405
405
|
|
|
@@ -424,8 +424,8 @@ Core Package
|
|
|
424
424
|
│ ├── jwt.js - JWT operations
|
|
425
425
|
│ ├── analytics.js - Analytics tracking
|
|
426
426
|
│ └── util.js - General utilities
|
|
427
|
-
├──
|
|
428
|
-
│ └── registry.js - CRM
|
|
427
|
+
├── Connector Registry
|
|
428
|
+
│ └── registry.js - CRM connector management
|
|
429
429
|
└── API Layer
|
|
430
430
|
├── createCoreApp() - Complete app setup
|
|
431
431
|
├── createCoreRouter() - Route management
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// core/src/
|
|
2
|
-
class
|
|
1
|
+
// core/src/connector/registry.js
|
|
2
|
+
class ConnectorRegistry {
|
|
3
3
|
constructor() {
|
|
4
|
-
this.
|
|
4
|
+
this.connectors = new Map();
|
|
5
5
|
this.manifests = new Map();
|
|
6
6
|
this.releaseNotes = {};
|
|
7
7
|
this.platformInterfaces = new Map(); // Store interface functions per platform
|
|
@@ -17,7 +17,7 @@ class AdapterRegistry {
|
|
|
17
17
|
* @param {string} interfaceName - Interface function name (e.g., 'createCallLog', 'findContact')
|
|
18
18
|
* @param {Function} interfaceFunction - The interface function to register
|
|
19
19
|
*/
|
|
20
|
-
|
|
20
|
+
registerConnectorInterface(platformName, interfaceName, interfaceFunction) {
|
|
21
21
|
if (typeof interfaceFunction !== 'function') {
|
|
22
22
|
throw new Error(`Interface function must be a function, got: ${typeof interfaceFunction}`);
|
|
23
23
|
}
|
|
@@ -57,7 +57,7 @@ class AdapterRegistry {
|
|
|
57
57
|
* @param {string} platformName - Platform identifier
|
|
58
58
|
* @param {string} interfaceName - Interface function name
|
|
59
59
|
*/
|
|
60
|
-
|
|
60
|
+
unregisterConnectorInterface(platformName, interfaceName) {
|
|
61
61
|
const platformInterfaceMap = this.platformInterfaces.get(platformName);
|
|
62
62
|
if (platformInterfaceMap && platformInterfaceMap.has(interfaceName)) {
|
|
63
63
|
platformInterfaceMap.delete(interfaceName);
|
|
@@ -66,80 +66,80 @@ class AdapterRegistry {
|
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
69
|
-
* Register an
|
|
69
|
+
* Register an connector with the core system
|
|
70
70
|
* @param {string} platform - Platform identifier (e.g., 'pipedrive', 'salesforce')
|
|
71
|
-
* @param {Object}
|
|
72
|
-
* @param {Object} manifest -
|
|
71
|
+
* @param {Object} connector - Connector implementation
|
|
72
|
+
* @param {Object} manifest - Connector manifest configuration
|
|
73
73
|
*/
|
|
74
|
-
|
|
75
|
-
// Validate
|
|
76
|
-
this.
|
|
74
|
+
registerConnector(platform, connector, manifest = null) {
|
|
75
|
+
// Validate connector interface
|
|
76
|
+
this.validateConnectorInterface(platform, connector);
|
|
77
77
|
|
|
78
|
-
this.
|
|
78
|
+
this.connectors.set(platform, connector);
|
|
79
79
|
if (manifest) {
|
|
80
80
|
this.manifests.set(platform, manifest);
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
console.log(`Registered
|
|
83
|
+
console.log(`Registered connector: ${platform}`);
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* Get
|
|
87
|
+
* Get connector by platform name with composed interfaces
|
|
88
88
|
* @param {string} platform - Platform identifier
|
|
89
|
-
* @returns {Object} Composed
|
|
89
|
+
* @returns {Object} Composed connector with interface functions
|
|
90
90
|
*/
|
|
91
|
-
|
|
92
|
-
const
|
|
91
|
+
getConnector(platform) {
|
|
92
|
+
const connector = this.connectors.get(platform);
|
|
93
93
|
const platformInterfaceMap = this.platformInterfaces.get(platform);
|
|
94
94
|
|
|
95
|
-
// If no
|
|
96
|
-
if (!
|
|
97
|
-
throw new Error(`
|
|
95
|
+
// If no connector and no interfaces, throw error
|
|
96
|
+
if (!connector && (!platformInterfaceMap || platformInterfaceMap.size === 0)) {
|
|
97
|
+
throw new Error(`Connector not found for platform: ${platform}`);
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
// If no
|
|
101
|
-
if (!
|
|
102
|
-
const
|
|
100
|
+
// If no connector but interfaces exist, create a composed object with just interfaces
|
|
101
|
+
if (!connector && platformInterfaceMap && platformInterfaceMap.size > 0) {
|
|
102
|
+
const composedConnector = {};
|
|
103
103
|
|
|
104
|
-
// Add interface functions to the composed
|
|
104
|
+
// Add interface functions to the composed connector
|
|
105
105
|
for (const [interfaceName, interfaceFunction] of platformInterfaceMap) {
|
|
106
|
-
|
|
106
|
+
composedConnector[interfaceName] = interfaceFunction;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
console.log(`Returning interface-only
|
|
110
|
-
return
|
|
109
|
+
console.log(`Returning interface-only connector for platform: ${platform}`);
|
|
110
|
+
return composedConnector;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
// If
|
|
114
|
-
if (
|
|
115
|
-
return
|
|
113
|
+
// If connector exists but no interfaces, return original connector
|
|
114
|
+
if (connector && (!platformInterfaceMap || platformInterfaceMap.size === 0)) {
|
|
115
|
+
return connector;
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
// If both
|
|
119
|
-
const
|
|
118
|
+
// If both connector and interfaces exist, create a composed object
|
|
119
|
+
const composedConnector = Object.create(connector);
|
|
120
120
|
|
|
121
|
-
// Add interface functions to the composed
|
|
121
|
+
// Add interface functions to the composed connector
|
|
122
122
|
for (const [interfaceName, interfaceFunction] of platformInterfaceMap) {
|
|
123
|
-
// Only add if the interface doesn't already exist in the
|
|
124
|
-
if (!Object.prototype.hasOwnProperty.call(
|
|
125
|
-
|
|
123
|
+
// Only add if the interface doesn't already exist in the connector
|
|
124
|
+
if (!Object.prototype.hasOwnProperty.call(connector, interfaceName)) {
|
|
125
|
+
composedConnector[interfaceName] = interfaceFunction;
|
|
126
126
|
}
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
return
|
|
129
|
+
return composedConnector;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
132
|
/**
|
|
133
|
-
* Get the original
|
|
133
|
+
* Get the original connector without composed interfaces
|
|
134
134
|
* @param {string} platform - Platform identifier
|
|
135
|
-
* @returns {Object} Original
|
|
135
|
+
* @returns {Object} Original connector implementation
|
|
136
136
|
*/
|
|
137
|
-
|
|
138
|
-
const
|
|
139
|
-
if (!
|
|
140
|
-
throw new Error(`
|
|
137
|
+
getOriginalConnector(platform) {
|
|
138
|
+
const connector = this.connectors.get(platform);
|
|
139
|
+
if (!connector) {
|
|
140
|
+
throw new Error(`Connector not found for platform: ${platform}`);
|
|
141
141
|
}
|
|
142
|
-
return
|
|
142
|
+
return connector;
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/**
|
|
@@ -163,7 +163,7 @@ class AdapterRegistry {
|
|
|
163
163
|
* @returns {Array<string>} Array of platform names
|
|
164
164
|
*/
|
|
165
165
|
getRegisteredPlatforms() {
|
|
166
|
-
return Array.from(this.
|
|
166
|
+
return Array.from(this.connectors.keys());
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
/**
|
|
@@ -172,35 +172,35 @@ class AdapterRegistry {
|
|
|
172
172
|
* @returns {boolean} True if platform is registered
|
|
173
173
|
*/
|
|
174
174
|
isRegistered(platform) {
|
|
175
|
-
return this.
|
|
175
|
+
return this.connectors.has(platform);
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/**
|
|
179
|
-
* Validate that
|
|
180
|
-
* @param {Object}
|
|
179
|
+
* Validate that connector implements required interface
|
|
180
|
+
* @param {Object} connector - Connector to validate
|
|
181
181
|
*/
|
|
182
|
-
|
|
182
|
+
validateConnectorInterface(platform, connector) {
|
|
183
183
|
const requiredMethods = [
|
|
184
184
|
'createCallLog',
|
|
185
185
|
'updateCallLog',
|
|
186
186
|
];
|
|
187
187
|
|
|
188
188
|
for (const method of requiredMethods) {
|
|
189
|
-
if (typeof
|
|
190
|
-
throw new Error(`
|
|
189
|
+
if (typeof connector[method] !== 'function') {
|
|
190
|
+
throw new Error(`Connector ${platform} missing required method: ${method}`);
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
/**
|
|
196
|
-
* Unregister an
|
|
196
|
+
* Unregister an connector
|
|
197
197
|
* @param {string} platform - Platform identifier
|
|
198
198
|
*/
|
|
199
|
-
|
|
200
|
-
this.
|
|
199
|
+
unregisterConnector(platform) {
|
|
200
|
+
this.connectors.delete(platform);
|
|
201
201
|
this.manifests.delete(platform);
|
|
202
202
|
this.platformInterfaces.delete(platform);
|
|
203
|
-
console.log(`Unregistered
|
|
203
|
+
console.log(`Unregistered connector: ${platform}`);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
206
|
setReleaseNotes(releaseNotes) {
|
|
@@ -212,27 +212,27 @@ class AdapterRegistry {
|
|
|
212
212
|
}
|
|
213
213
|
|
|
214
214
|
/**
|
|
215
|
-
* Get
|
|
215
|
+
* Get connector capabilities summary including composed interfaces
|
|
216
216
|
* @param {string} platform - Platform identifier
|
|
217
|
-
* @returns {Object}
|
|
217
|
+
* @returns {Object} Connector capabilities
|
|
218
218
|
*/
|
|
219
|
-
|
|
220
|
-
const
|
|
221
|
-
const
|
|
219
|
+
getConnectorCapabilities(platform) {
|
|
220
|
+
const originalConnector = this.getOriginalConnector(platform);
|
|
221
|
+
const composedConnector = this.getConnector(platform);
|
|
222
222
|
const platformInterfaceMap = this.getPlatformInterfaces(platform);
|
|
223
223
|
|
|
224
224
|
const capabilities = {
|
|
225
225
|
platform,
|
|
226
|
-
originalMethods: Object.keys(
|
|
227
|
-
composedMethods: Object.keys(
|
|
226
|
+
originalMethods: Object.keys(originalConnector),
|
|
227
|
+
composedMethods: Object.keys(composedConnector),
|
|
228
228
|
registeredInterfaces: Array.from(platformInterfaceMap.keys()),
|
|
229
229
|
authType: null
|
|
230
230
|
};
|
|
231
231
|
|
|
232
232
|
// Get auth type if available
|
|
233
|
-
if (typeof
|
|
233
|
+
if (typeof originalConnector.getAuthType === 'function') {
|
|
234
234
|
try {
|
|
235
|
-
capabilities.authType =
|
|
235
|
+
capabilities.authType = originalConnector.getAuthType();
|
|
236
236
|
} catch (error) {
|
|
237
237
|
capabilities.authType = 'unknown';
|
|
238
238
|
}
|
|
@@ -243,5 +243,5 @@ class AdapterRegistry {
|
|
|
243
243
|
}
|
|
244
244
|
|
|
245
245
|
// Export singleton instance
|
|
246
|
-
const
|
|
247
|
-
module.exports =
|
|
246
|
+
const connectorRegistry = new ConnectorRegistry();
|
|
247
|
+
module.exports = connectorRegistry;
|
package/handlers/admin.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const axios = require('axios');
|
|
2
2
|
const { AdminConfigModel } = require('../models/adminConfigModel');
|
|
3
|
-
const
|
|
3
|
+
const connectorRegistry = require('../connector/registry');
|
|
4
4
|
const oauth = require('../lib/oauth');
|
|
5
5
|
const { RingCentral } = require('../lib/ringcentral');
|
|
6
6
|
|
|
@@ -53,7 +53,7 @@ async function updateAdminRcTokens({ hashedRcAccountId, adminAccessToken, adminR
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
async function getServerLoggingSettings({ user }) {
|
|
56
|
-
const platformModule =
|
|
56
|
+
const platformModule = connectorRegistry.getConnector(user.platform);
|
|
57
57
|
if (platformModule.getServerLoggingSettings) {
|
|
58
58
|
const serverLoggingSettings = await platformModule.getServerLoggingSettings({ user });
|
|
59
59
|
return serverLoggingSettings;
|
|
@@ -62,7 +62,7 @@ async function getServerLoggingSettings({ user }) {
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
async function updateServerLoggingSettings({ user, additionalFieldValues }) {
|
|
65
|
-
const platformModule =
|
|
65
|
+
const platformModule = connectorRegistry.getConnector(user.platform);
|
|
66
66
|
const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: user?.platformAdditionalInfo?.tokenUrl, hostname: user?.hostname })));
|
|
67
67
|
if (platformModule.updateServerLoggingSettings) {
|
|
68
68
|
const { successful, returnMessage } = await platformModule.updateServerLoggingSettings({ user, additionalFieldValues, oauthApp });
|
|
@@ -200,7 +200,7 @@ async function getUserReport({ rcAccountId, rcExtensionId, timezone, timeFrom, t
|
|
|
200
200
|
|
|
201
201
|
async function getUserMapping({ user, hashedRcAccountId, rcExtensionList }) {
|
|
202
202
|
const adminConfig = await getAdminSettings({ hashedRcAccountId });
|
|
203
|
-
const platformModule =
|
|
203
|
+
const platformModule = connectorRegistry.getConnector(user.platform);
|
|
204
204
|
if (platformModule.getUserList) {
|
|
205
205
|
const authType = platformModule.getAuthType();
|
|
206
206
|
let authHeader = '';
|
package/handlers/auth.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
const oauth = require('../lib/oauth');
|
|
2
2
|
const { UserModel } = require('../models/userModel');
|
|
3
|
-
const
|
|
3
|
+
const connectorRegistry = require('../connector/registry');
|
|
4
4
|
const Op = require('sequelize').Op;
|
|
5
5
|
const { RingCentral } = require('../lib/ringcentral');
|
|
6
6
|
const adminCore = require('./admin');
|
|
7
7
|
|
|
8
8
|
async function onOAuthCallback({ platform, hostname, tokenUrl, callbackUri, apiUrl, username, query }) {
|
|
9
|
-
const platformModule =
|
|
9
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
10
10
|
const oauthInfo = await platformModule.getOauthInfo({ tokenUrl, hostname, rcAccountId: query.rcAccountId });
|
|
11
11
|
|
|
12
12
|
if (oauthInfo.failMessage) {
|
|
@@ -58,7 +58,7 @@ async function onOAuthCallback({ platform, hostname, tokenUrl, callbackUri, apiU
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
async function onApiKeyLogin({ platform, hostname, apiKey, additionalInfo }) {
|
|
61
|
-
const platformModule =
|
|
61
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
62
62
|
const basicAuth = platformModule.getBasicAuth({ apiKey });
|
|
63
63
|
const { successful, platformUserInfo, returnMessage } = await platformModule.getUserInfo({ authHeader: `Basic ${basicAuth}`, hostname, additionalInfo, apiKey });
|
|
64
64
|
if (successful) {
|
|
@@ -169,7 +169,7 @@ async function saveUserInfo({ platformUserInfo, platform, hostname, accessToken,
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
async function getLicenseStatus({ userId, platform }) {
|
|
172
|
-
const platformModule =
|
|
172
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
173
173
|
const licenseStatus = await platformModule.getLicenseStatus({ userId });
|
|
174
174
|
return licenseStatus;
|
|
175
175
|
}
|
|
@@ -187,7 +187,7 @@ async function authValidation({ platform, userId }) {
|
|
|
187
187
|
}
|
|
188
188
|
});
|
|
189
189
|
if (existingUser) {
|
|
190
|
-
const platformModule =
|
|
190
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
191
191
|
const oauthApp = oauth.getOAuthApp((await platformModule.getOauthInfo({ tokenUrl: existingUser?.platformAdditionalInfo?.tokenUrl, hostname: existingUser?.hostname })));
|
|
192
192
|
existingUser = await oauth.checkAndRefreshAccessToken(oauthApp, existingUser);
|
|
193
193
|
const { successful, returnMessage, status } = await platformModule.authValidation({ user: existingUser });
|
package/handlers/contact.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const oauth = require('../lib/oauth');
|
|
2
2
|
const { UserModel } = require('../models/userModel');
|
|
3
3
|
const errorMessage = require('../lib/generalErrorMessage');
|
|
4
|
-
const
|
|
4
|
+
const connectorRegistry = require('../connector/registry');
|
|
5
5
|
async function findContact({ platform, userId, phoneNumber, overridingFormat, isExtension }) {
|
|
6
6
|
try {
|
|
7
7
|
let user = await UserModel.findOne({
|
|
@@ -20,7 +20,7 @@ async function findContact({ platform, userId, phoneNumber, overridingFormat, is
|
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
}
|
|
23
|
-
const platformModule =
|
|
23
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
24
24
|
const authType = platformModule.getAuthType();
|
|
25
25
|
let authHeader = '';
|
|
26
26
|
switch (authType) {
|
|
@@ -127,7 +127,7 @@ async function createContact({ platform, userId, phoneNumber, newContactName, ne
|
|
|
127
127
|
if (!user || !user.accessToken) {
|
|
128
128
|
return { successful: false, message: `Contact not found` };
|
|
129
129
|
}
|
|
130
|
-
const platformModule =
|
|
130
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
131
131
|
const authType = platformModule.getAuthType();
|
|
132
132
|
let authHeader = '';
|
|
133
133
|
switch (authType) {
|
|
@@ -207,7 +207,7 @@ async function findContactWithName({ platform, userId, name }) {
|
|
|
207
207
|
}
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
|
-
const platformModule =
|
|
210
|
+
const platformModule = connectorRegistry.getConnector(platform);
|
|
211
211
|
const authType = platformModule.getAuthType();
|
|
212
212
|
let authHeader = '';
|
|
213
213
|
switch (authType) {
|