@vida-global/apps-tools 1.0.1
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/index.js +23 -0
- package/lib/actionHandlers/appFunctionHandler.js +7 -0
- package/lib/actionHandlers/appHooksHandler.js +7 -0
- package/lib/actionHandlers/index.js +4 -0
- package/lib/appResponses/appFunctionResponse.js +23 -0
- package/lib/appResponses/appHookResponse.js +21 -0
- package/lib/appResponses/calendarAppResponse.js +6 -0
- package/lib/appResponses/index.js +9 -0
- package/lib/apps/appManager/abstractAppManager.js +70 -0
- package/lib/apps/appManager/appServerAppManager.js +237 -0
- package/lib/apps/appManager/vaderApiClient.js +81 -0
- package/lib/apps/appManager/vidaLiveAppManager.js +187 -0
- package/lib/apps/vidaApp.js +345 -0
- package/lib/errors/illegalAppInvocationError.js +8 -0
- package/lib/openApi/baseApiSpec.js +10 -0
- package/lib/openApi/index.js +150 -0
- package/lib/providers/provider.js +141 -0
- package/lib/providers/providerManager.js +73 -0
- package/lib/providers/providers/auth/generic/index.js +60 -0
- package/lib/providers/providers/auth/google/index.js +251 -0
- package/lib/providers/providers/auth/hubspot/index.js +313 -0
- package/lib/providers/providers/auth/mcp/index.js +99 -0
- package/lib/providers/providers/auth/outlook/index.js +257 -0
- package/lib/providers/providers/auth/squareUp/index.js +111 -0
- package/lib/providers/providers/mock.js +51 -0
- package/lib/server/appController.js +112 -0
- package/lib/server/server.js +73 -0
- package/lib/userContext.js +218 -0
- package/package.json +33 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { logger } = require('@vida-global/core')
|
|
3
|
+
const { IllegalAppInvocationError } = require('../errors/illegalAppInvocationError');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class VidaApp {
|
|
7
|
+
functionHandler = null
|
|
8
|
+
hooksHandler = null
|
|
9
|
+
eventsHandler = null
|
|
10
|
+
|
|
11
|
+
constructor(
|
|
12
|
+
{
|
|
13
|
+
appId, appVersion, appManifest,
|
|
14
|
+
userContext,
|
|
15
|
+
providerManager,
|
|
16
|
+
}
|
|
17
|
+
) {
|
|
18
|
+
this.appId = appId
|
|
19
|
+
this.appVersion = appVersion
|
|
20
|
+
this.manifest = appManifest
|
|
21
|
+
|
|
22
|
+
this.userContext = userContext
|
|
23
|
+
|
|
24
|
+
// this.manifest.installed = this.manifest.installed === undefined ? false : this.manifest.installed
|
|
25
|
+
// this.manifest.active = this.manifest.active === undefined ? false : this.manifest.active
|
|
26
|
+
|
|
27
|
+
this.isServer = true
|
|
28
|
+
|
|
29
|
+
this.providerManager = providerManager
|
|
30
|
+
this.providers = {}
|
|
31
|
+
|
|
32
|
+
this.functions = {}
|
|
33
|
+
this.hooks = {}
|
|
34
|
+
this.events = {}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
id() {
|
|
38
|
+
return this.appId
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
version() {
|
|
42
|
+
return this.appVersion
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
context() {
|
|
46
|
+
return this.userContext
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static async get(
|
|
50
|
+
appClass,
|
|
51
|
+
{
|
|
52
|
+
appId, appVersion, appManifest,
|
|
53
|
+
userContext,
|
|
54
|
+
providerManager,
|
|
55
|
+
},
|
|
56
|
+
{isServer = true}
|
|
57
|
+
) {
|
|
58
|
+
const app = new appClass({
|
|
59
|
+
appId, appVersion, appManifest,
|
|
60
|
+
userContext,
|
|
61
|
+
providerManager,
|
|
62
|
+
})
|
|
63
|
+
await app._init({ isServer})
|
|
64
|
+
return app
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async _init ({ isServer }) {
|
|
68
|
+
this.isServer = isServer
|
|
69
|
+
|
|
70
|
+
this.manifest.installed = await this.userContext.isAppInstalled(this.appId, this.appVersion)
|
|
71
|
+
|
|
72
|
+
await this.buildImplementationList()
|
|
73
|
+
await this.buildProviders()
|
|
74
|
+
|
|
75
|
+
if (!this.isServer) {
|
|
76
|
+
await this.checkActive()
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (this.isServer) {
|
|
80
|
+
if (this.functionHandler) {
|
|
81
|
+
this._functionHandler = new this.functionHandler(this)
|
|
82
|
+
}
|
|
83
|
+
if (this.hooksHandler) {
|
|
84
|
+
this._hooksHandler = new this.hooksHandler(this)
|
|
85
|
+
}
|
|
86
|
+
if (this.eventsHandler) {
|
|
87
|
+
this._eventsHandler = new this.eventsHandler(this)
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
92
|
+
await this.initApp()
|
|
93
|
+
} catch (error) {
|
|
94
|
+
console.warn('Potential unhandled error in app init: ', error, this.appId, this.appVersion)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async initApp() {
|
|
99
|
+
// throw new Error('Not implemented')
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
isFunctionInApp(functionName) {
|
|
103
|
+
return !!this.functions[functionName]
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
isHookInApp(hookName) {
|
|
107
|
+
return !!this.hooks[hookName]
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
isEventInApp(eventName) {
|
|
111
|
+
return !!this.events[eventName]
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
async handleFunctionCall(functionName, functionArgs) {
|
|
115
|
+
if (!this.isServer) {
|
|
116
|
+
throw new IllegalAppInvocationError("Illegal invocation of handleFunctionCall method: this operation is not allowed in isServer mode.")
|
|
117
|
+
}
|
|
118
|
+
if (!(this.isFunctionInApp(functionName))) {
|
|
119
|
+
throw new Error(`Function "${functionName}" is not defined in the manifest.`);
|
|
120
|
+
}
|
|
121
|
+
if (!this._functionHandler) {
|
|
122
|
+
throw new Error(`No function handler defined in app ${this.appId}`)
|
|
123
|
+
}
|
|
124
|
+
logger.debug('Function call received', functionName, functionArgs)
|
|
125
|
+
|
|
126
|
+
const startTime = Date.now();
|
|
127
|
+
let result = await this._functionHandler[functionName](functionArgs);
|
|
128
|
+
result.functionName = functionName;
|
|
129
|
+
result.functionArgs = functionArgs;
|
|
130
|
+
result.responseTime = Date.now() - startTime;
|
|
131
|
+
|
|
132
|
+
return result
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
async handleHookCall(hookName, hookArgs) {
|
|
136
|
+
if (!this.isServer) {
|
|
137
|
+
throw new IllegalAppInvocationError("Illegal invocation of handleHookCall method: this operation is not allowed in isServer mode.")
|
|
138
|
+
}
|
|
139
|
+
if (!(this.isHookInApp(hookName))) {
|
|
140
|
+
throw new Error(`Hook "${hookName}" is not defined in the manifest.`);
|
|
141
|
+
}
|
|
142
|
+
if (!this._hooksHandler) {
|
|
143
|
+
throw new Error(`No hook handler defined in the app ${this.appId}`)
|
|
144
|
+
}
|
|
145
|
+
logger.debug('Hook call received', hookName, hookArgs)
|
|
146
|
+
|
|
147
|
+
const startTime = Date.now();
|
|
148
|
+
let result = await this._hooksHandler[hookName](hookArgs)
|
|
149
|
+
result.responseTime = Date.now() - startTime;
|
|
150
|
+
|
|
151
|
+
return result
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async handleEvent(eventName, eventData) {
|
|
155
|
+
if (!this.isServer) {
|
|
156
|
+
throw new IllegalAppInvocationError("Illegal invocation of handleEvent method: this operation is not allowed in isServer mode.")
|
|
157
|
+
}
|
|
158
|
+
if (!(this.isEventInApp(eventName))) {
|
|
159
|
+
throw new Error(`Event "${eventName}" is not defined in the manifest.`);
|
|
160
|
+
}
|
|
161
|
+
if (!this._eventsHandler) {
|
|
162
|
+
throw new Error(`No event handler defined in the app ${this.appId}`)
|
|
163
|
+
}
|
|
164
|
+
logger.debug('Hook call received', eventName, eventData)
|
|
165
|
+
|
|
166
|
+
const startTime = Date.now();
|
|
167
|
+
let result = await this._eventsHandler[eventName](eventData)
|
|
168
|
+
result.responseTime = Date.now() - startTime;
|
|
169
|
+
return result
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
addProvider(providerType, providerName, providerInstance) {
|
|
173
|
+
if (!this.providers[providerType]) {
|
|
174
|
+
this.providers[providerType] = {}
|
|
175
|
+
}
|
|
176
|
+
this.providers[providerType][providerName] = providerInstance
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async getProviderManifest(providerType, providerName) {
|
|
180
|
+
return await this.providers[providerType][providerName].getManifest()
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async getCompositeManifest() {
|
|
184
|
+
logger.info(`Building composite manifest ${this.appId} ${this.appVersion}`)
|
|
185
|
+
await this.checkActive()
|
|
186
|
+
let compositeManifest = {...this.manifest}
|
|
187
|
+
const providerManifests = this.manifest.dependencies.providers
|
|
188
|
+
for (const [providerType, providers] of Object.entries(providerManifests)) {
|
|
189
|
+
for (const [providerName, vanillaProviderManifest] of Object.entries(providers)) {
|
|
190
|
+
const installedProviderManifest = await this.getProviderManifest(providerType, providerName)
|
|
191
|
+
compositeManifest.dependencies.providers[providerType][providerName] = _.merge(
|
|
192
|
+
_.cloneDeep(vanillaProviderManifest), installedProviderManifest
|
|
193
|
+
)
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return compositeManifest
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
async serialize(){
|
|
200
|
+
return await this.getCompositeManifest()
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
async buildProviders(update= false) {
|
|
204
|
+
const providerManifest = this.manifest.dependencies.providers
|
|
205
|
+
for (const [providerType, providers] of Object.entries(providerManifest)) {
|
|
206
|
+
for (const [providerName, providerConfig] of Object.entries(providers)) {
|
|
207
|
+
const provider = await this.providerManager.buildProvider(
|
|
208
|
+
providerType, providerName, this.userContext, providerConfig,
|
|
209
|
+
this.id(), this.version()
|
|
210
|
+
)
|
|
211
|
+
if (update) {
|
|
212
|
+
provider.update(providerConfig)
|
|
213
|
+
}
|
|
214
|
+
this.addProvider(providerType, providerName, provider)
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
buildImplementationList() {
|
|
220
|
+
if (this.manifest) {
|
|
221
|
+
if (!this.manifest.implementations) {
|
|
222
|
+
this.manifest.implementations = {}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
if (this.manifest.implementations.functions) {
|
|
226
|
+
for (const func of this.manifest.implementations.functions) {
|
|
227
|
+
this.functions[func.name] = func
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (this.manifest.implementations.hooks) {
|
|
232
|
+
for (const hook of this.manifest.implementations.hooks) {
|
|
233
|
+
this.hooks[hook.name] = hook
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
if (this.manifest.implementations.events) {
|
|
238
|
+
for (const event of this.manifest.implementations.events) {
|
|
239
|
+
this.events[event.name] = event
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
async update(manifest) {
|
|
246
|
+
return await this.install(manifest, true)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
async reload(manifest) {
|
|
250
|
+
return await this.install(manifest, true)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
async checkActive() {
|
|
254
|
+
this.manifest.active = true
|
|
255
|
+
for (const providers of Object.values(this.providers)) {
|
|
256
|
+
for (const providerInstance of Object.values(providers)) {
|
|
257
|
+
// Perform desired operations on each providerInstance
|
|
258
|
+
const isProviderConfigured = await providerInstance.isConfigured()
|
|
259
|
+
this.manifest.active = this.manifest.active && isProviderConfigured
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async install(manifest, update = false) {
|
|
265
|
+
if (this.manifest.installed && !update) {
|
|
266
|
+
throw new Error('App is already installed')
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
this.manifest = manifest
|
|
270
|
+
this.manifest.installed = true
|
|
271
|
+
await this.buildImplementationList()
|
|
272
|
+
await this.buildProviders(true)
|
|
273
|
+
await this.checkActive()
|
|
274
|
+
|
|
275
|
+
if (!update) {
|
|
276
|
+
this.userContext.installApp(this.appId, this.appVersion)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return this.manifest
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
async getFunctions(onlyEnabled = false) {
|
|
283
|
+
let functions = (await this.getCompositeManifest()).implementations.functions;
|
|
284
|
+
if (onlyEnabled) {
|
|
285
|
+
const enabledFunctions = await this.userContext.getEnabledFunctions(this.appId, this.appVersion);
|
|
286
|
+
return functions.filter(func => {
|
|
287
|
+
return enabledFunctions.some(enabledFunc => enabledFunc === func.name);
|
|
288
|
+
})
|
|
289
|
+
} else {
|
|
290
|
+
return functions;
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
async getHooks() {
|
|
295
|
+
return this.manifest.implementations.hooks || []
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
async getAgentInstructions() {
|
|
299
|
+
const agent = this.userContext.get('agent')
|
|
300
|
+
const agentApps = agent.apps || []
|
|
301
|
+
const agentApp = _.find(agentApps, (app) => {
|
|
302
|
+
return app.appId === this.id() && app.version === this.version()
|
|
303
|
+
})
|
|
304
|
+
if (agentApp && agentApp.instructions) {
|
|
305
|
+
return agentApp.instructions
|
|
306
|
+
} else {
|
|
307
|
+
return this.manifest.description
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
isInstalled() {
|
|
312
|
+
if (this.isServer) {
|
|
313
|
+
throw new IllegalAppInvocationError("Illegal invocation of isInstalled method: this operation is not allowed in isServer mode.")
|
|
314
|
+
}
|
|
315
|
+
return this.manifest.installed
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
isActive() {
|
|
319
|
+
if (this.isServer) {
|
|
320
|
+
throw new IllegalAppInvocationError("Illegal invocation of isActive method: this operation is not allowed in isServer mode.")
|
|
321
|
+
}
|
|
322
|
+
return this.manifest.active
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
async uninstall() {
|
|
326
|
+
if (this.isServer) {
|
|
327
|
+
throw new IllegalAppInvocationError("Illegal invocation of uninstall method: this operation is not allowed in isServer mode.")
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
this.manifest.installed = false
|
|
331
|
+
this.manifest.active = false
|
|
332
|
+
|
|
333
|
+
// Uninstall all the user context and settings
|
|
334
|
+
await this.userContext.uninstallApp(this.appId, this.appVersion)
|
|
335
|
+
|
|
336
|
+
for (const providers of Object.values(this.providers)) {
|
|
337
|
+
for (const providerInstance of Object.values(providers)) {
|
|
338
|
+
await providerInstance.uninstall()
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
module.exports = { VidaApp }
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
const _ = require("lodash")
|
|
2
|
+
const baseApiSpec = require('./baseApiSpec')
|
|
3
|
+
|
|
4
|
+
function generateOpenApiSpecPaths(appId, version, functions, hooks) {
|
|
5
|
+
const paths = {}
|
|
6
|
+
const contextSpecs = {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
user: {
|
|
10
|
+
type: "object",
|
|
11
|
+
description: "Agent user details",
|
|
12
|
+
example: {
|
|
13
|
+
id: 100,
|
|
14
|
+
username: "johndoe",
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
agent: {
|
|
18
|
+
type: "object",
|
|
19
|
+
description: "Agent configuration data",
|
|
20
|
+
example: {
|
|
21
|
+
id: 200,
|
|
22
|
+
name: "Cool Agent",
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
caller: {
|
|
26
|
+
type: "object",
|
|
27
|
+
description: "Caller data",
|
|
28
|
+
example: {
|
|
29
|
+
id: 300,
|
|
30
|
+
name: "Cool Caller",
|
|
31
|
+
number: "+1234567890",
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
meta: {
|
|
35
|
+
type: "object",
|
|
36
|
+
description: "Convo meta",
|
|
37
|
+
example: {
|
|
38
|
+
callId: "123asd456",
|
|
39
|
+
convoUUID: "74c28825-aed9-45a6-8534-2177f2a66993 ",
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
manifest: {
|
|
43
|
+
type: "object",
|
|
44
|
+
description: "App manifest",
|
|
45
|
+
example: null
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
required: ["user", "agent", "caller"],
|
|
49
|
+
}
|
|
50
|
+
const responseSpecs = {
|
|
51
|
+
"200": {
|
|
52
|
+
description: "Successful response",
|
|
53
|
+
content: {
|
|
54
|
+
"application/json": {
|
|
55
|
+
schema: {
|
|
56
|
+
type: "object",
|
|
57
|
+
additionalProperties: true,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
"400": {
|
|
63
|
+
description: "Bad request",
|
|
64
|
+
},
|
|
65
|
+
"500": {
|
|
66
|
+
description: "Server error",
|
|
67
|
+
},
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
functions.forEach((func) => {
|
|
71
|
+
const functionName = func.name
|
|
72
|
+
const endpoint = `/invoke/app/function/${appId}/${version}/${functionName}`
|
|
73
|
+
|
|
74
|
+
paths[endpoint] = {
|
|
75
|
+
post: {
|
|
76
|
+
summary: func.description,
|
|
77
|
+
tags: [`${appId}/${version}`],
|
|
78
|
+
operationId: `${functionName}Operation`,
|
|
79
|
+
requestBody: {
|
|
80
|
+
required: true,
|
|
81
|
+
content: {
|
|
82
|
+
"application/json": {
|
|
83
|
+
schema: {
|
|
84
|
+
type: "object",
|
|
85
|
+
properties: {
|
|
86
|
+
userContext: contextSpecs,
|
|
87
|
+
functionArgs: func.parameters,
|
|
88
|
+
},
|
|
89
|
+
required: ['context', 'params'],
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
responses: responseSpecs,
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
hooks.forEach((hook) => {
|
|
100
|
+
const hookName = hook.name
|
|
101
|
+
const endpoint = `/invoke/app/hook/${appId}/${version}/${hookName}`
|
|
102
|
+
|
|
103
|
+
paths[endpoint] = {
|
|
104
|
+
post: {
|
|
105
|
+
summary: hook.description,
|
|
106
|
+
tags: [`${appId}/${version}`],
|
|
107
|
+
operationId: `${hookName}Operation`,
|
|
108
|
+
requestBody: {
|
|
109
|
+
required: true,
|
|
110
|
+
content: {
|
|
111
|
+
'application/json': {
|
|
112
|
+
schema: {
|
|
113
|
+
type: 'object',
|
|
114
|
+
properties: {
|
|
115
|
+
userContext: contextSpecs,
|
|
116
|
+
parameters: hook.parameters,
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
responses: responseSpecs,
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
return paths
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
async function generateOpenApiSpec(appManager) {
|
|
132
|
+
let paths = {}
|
|
133
|
+
for (const {id, version} of appManager.apps) {
|
|
134
|
+
const manifest = await appManager.fetchVanillaAppManifest(id, version)
|
|
135
|
+
const appPaths = generateOpenApiSpecPaths(id,
|
|
136
|
+
version,
|
|
137
|
+
manifest.implementations.functions || [],
|
|
138
|
+
manifest.implementations.hooks || []);
|
|
139
|
+
paths = {...paths, ...appPaths}
|
|
140
|
+
}
|
|
141
|
+
const apiSpec = _.cloneDeep(baseApiSpec)
|
|
142
|
+
apiSpec.paths = paths
|
|
143
|
+
return apiSpec
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
module.exports = {
|
|
148
|
+
generateOpenApiSpec
|
|
149
|
+
}
|
|
150
|
+
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
const _ = require('lodash');
|
|
2
|
+
const { logger } = require('@vida-global/core');
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class BaseProviderConfigurator {
|
|
6
|
+
constructor(userContext, redisClient, type, name,
|
|
7
|
+
globalProviderConfig, appId, appVersion) {
|
|
8
|
+
this.userContext = userContext;
|
|
9
|
+
this.redis = redisClient;
|
|
10
|
+
this.type = type;
|
|
11
|
+
this.name = name;
|
|
12
|
+
this.globalConfig = globalProviderConfig;
|
|
13
|
+
this.appId = appId;
|
|
14
|
+
this.appVersion = appVersion;
|
|
15
|
+
this.hasBuiltRoutes = false;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async _initialize() {
|
|
19
|
+
await this.initialize();
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async initialize() {
|
|
23
|
+
throw Error("Not implemented")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
buildRoutes (expressApp) {
|
|
27
|
+
logger.info('No routes to be built for base configurator')
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class BaseProvider {
|
|
33
|
+
type = null
|
|
34
|
+
name = 'sample-provider'
|
|
35
|
+
configurator = BaseProviderConfigurator
|
|
36
|
+
|
|
37
|
+
PROVIDER_GLOBAL_CONFIG_KEY () {
|
|
38
|
+
return `vader:providers:${this.type}:${this.name}:config`
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
constructor(
|
|
42
|
+
userContext, redisClient, vanillaConfig = null,
|
|
43
|
+
appId = null, appVersion = null,
|
|
44
|
+
isServer = false
|
|
45
|
+
) {
|
|
46
|
+
this.userContext = userContext;
|
|
47
|
+
this.redis = redisClient;
|
|
48
|
+
this.isServer = isServer;
|
|
49
|
+
this.config = vanillaConfig || {};
|
|
50
|
+
this.appId = appId;
|
|
51
|
+
this.appVersion = appVersion;
|
|
52
|
+
this.globalConfig = {};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
static async get(providerCls, {
|
|
56
|
+
userContext, redisClient, vanillaConfig,
|
|
57
|
+
appId, appVersion,
|
|
58
|
+
isServer = false
|
|
59
|
+
}) {
|
|
60
|
+
const provider = new providerCls(
|
|
61
|
+
userContext, redisClient, vanillaConfig,
|
|
62
|
+
appId, appVersion,
|
|
63
|
+
isServer
|
|
64
|
+
);
|
|
65
|
+
await provider._initialize();
|
|
66
|
+
return provider
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
async getConfigurator() {
|
|
70
|
+
const configurator = new this.configurator(
|
|
71
|
+
this.userContext, this.redis, this.type, this.name,
|
|
72
|
+
this.globalConfig,
|
|
73
|
+
this.appId, this.appVersion,
|
|
74
|
+
)
|
|
75
|
+
await configurator._initialize()
|
|
76
|
+
return configurator
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async _initialize() {
|
|
80
|
+
if (!this.isServer) {
|
|
81
|
+
// Read global config and add it to config
|
|
82
|
+
let globalConfig = await this.redis.get(
|
|
83
|
+
this.PROVIDER_GLOBAL_CONFIG_KEY()
|
|
84
|
+
)
|
|
85
|
+
globalConfig = globalConfig ? JSON.parse(globalConfig) : {}
|
|
86
|
+
this.globalConfig = globalConfig
|
|
87
|
+
|
|
88
|
+
if (this.userContext) {
|
|
89
|
+
let userProviderConfig = await this.userContext.getProviderConfig(
|
|
90
|
+
this.type, this.name, this.appId, this.appVersion
|
|
91
|
+
) || {}
|
|
92
|
+
this.config = _.merge(_.cloneDeep(this.config), userProviderConfig)
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
if (this.userContext) {
|
|
96
|
+
let userProviderConfig = await this.userContext.getProviderConfig(
|
|
97
|
+
this.type, this.name, this.appId, this.appVersion
|
|
98
|
+
) || {}
|
|
99
|
+
this.config = _.merge(_.cloneDeep(this.config), userProviderConfig)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
await this.initialize();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async getProperty (name) {
|
|
106
|
+
return this.config.parameters.properties[name].value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async saveConfig(config) {
|
|
110
|
+
await this.userContext.setProviderConfig(
|
|
111
|
+
this.type, this.name, config,
|
|
112
|
+
this.appId, this.appVersion
|
|
113
|
+
)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async update(config) {
|
|
117
|
+
throw Error("Not implemented")
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
async isConfigured() {
|
|
121
|
+
throw Error("Not implemented")
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async getManifest() {
|
|
125
|
+
throw Error("Not implemented")
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async initialize() {
|
|
129
|
+
throw new Error("Not implemented");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
async uninstall () {
|
|
133
|
+
throw new Error("Not implemented");
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
module.exports = {
|
|
139
|
+
BaseProviderConfigurator,
|
|
140
|
+
BaseProvider
|
|
141
|
+
}
|