Skip to content
Open
3 changes: 2 additions & 1 deletion examples/test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,14 @@ let fdkExtension = setupFdk({
}
});

app.use(fdkExtension.fdkHandler);

app.use('/_healthz', (req, res, next) => {
res.json({
"ok": "ok"
});
});

app.use('/', fdkExtension.fdkHandler);
fdkExtension.apiRoutes.get("/test/routes", async (req, res, next) => {
try {
let data = await req.platformClient.lead.getTickets();
Expand Down
16 changes: 12 additions & 4 deletions express/api_routes.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
'use strict';
const { extension } = require('./extension');
const express = require('express');
const { sessionMiddleware } = require('./middleware/session_middleware');
const { ApplicationConfig, ApplicationClient } = require("@gofynd/fdk-client-javascript");
const { ExtensionFactory } = require('./extension_factory');


function setupProxyRoutes() {
function setupProxyRoutes(extension) {
const apiRoutes = express.Router({ mergeParams: true });
const applicationProxyRoutes = express.Router({ mergeParams: true });

applicationProxyRoutes.use(async (req, res, next) => {
applicationProxyRoutes.use( "/" ,async (req, res, next) => {
try {
const clusterId = req.query.cluster_domain || req.query.cluster_url?.replace("https://", "").replace("http://", "");
if (clusterId) {
extension = ExtensionFactory.getExtension(clusterId)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ExtensionFactory import is missing

}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

req.extension = extension;

Injection of extension instance in the request object will be helpful to get the cluster_id

if(req.headers["x-user-data"]) {
req.user = JSON.parse(req.headers["x-user-data"]);
req.user.user_id = req.user._id;
Expand All @@ -30,8 +34,12 @@ function setupProxyRoutes() {
}
});

apiRoutes.use(sessionMiddleware(true), async (req, res, next) => {
apiRoutes.use( "/" , sessionMiddleware(extension, true), async (req, res, next) => {
try {
const clusterId = req.query.cluster_domain || req.query.cluster_url?.replace("https://", "").replace("http://", "");
if (clusterId) {
extension = ExtensionFactory.getExtension(clusterId)
}
const client = await extension.getPlatformClient(req.fdkSession.company_id, req.fdkSession);
req.platformClient = client;
req.extension = extension;
Expand Down
9 changes: 8 additions & 1 deletion express/error_code.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,12 @@ class FdkWebhookHandlerNotFound extends Error {
}
}

class FdkInvalidCluster extends Error {
constructor(message) {
super(message);
}
}


module.exports = {
FdkInvalidExtensionConfig,
Expand All @@ -64,5 +70,6 @@ module.exports = {
FdkInvalidWebhookConfig,
FdkWebhookRegistrationError,
FdkWebhookProcessError,
FdkWebhookHandlerNotFound
FdkWebhookHandlerNotFound,
FdkInvalidCluster
};
17 changes: 11 additions & 6 deletions express/extension.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const { WebhookRegistry } = require('./webhook');
const logger = require('./logger');
const { fdkAxios } = require('@gofynd/fdk-client-javascript/sdk/common/AxiosHelper');
const { version } = require('./../package.json');
const SessionStorage = require("./session/session_storage");
const { RetryManger } = require("./retry_manager")

class Extension {
Expand All @@ -19,7 +20,9 @@ class Extension {
this.access_mode = null;
this.cluster = "https://api.fynd.com";
this.webhookRegistry = null;
this.sessionStore = null;
this._isInitialized = false;
this._clusterId = null;
this._retryManager = new RetryManger();
}

Expand All @@ -34,6 +37,7 @@ class Extension {

this.storage = data.storage;

this.sessionStorage = new SessionStorage(this.storage);
if (!data.api_key) {
throw new FdkInvalidExtensionConfig("Invalid api_key");
}
Expand All @@ -56,6 +60,7 @@ class Extension {
throw new FdkInvalidExtensionConfig("Invalid cluster value. Invalid value: " + data.cluster);
}
this.cluster = data.cluster;
this._clusterId = this.cluster.replace("https://", "");
}
this.webhookRegistry = new WebhookRegistry(this._retryManager);

Expand Down Expand Up @@ -87,6 +92,10 @@ class Extension {
return this._isInitialized;
}

get clusterId(){
return this._clusterId;
}

verifyScopes(scopes, extensionData) {
const missingScopes = scopes.filter(val => extensionData.scope.indexOf(val) === -1);
if (!scopes || scopes.length <= 0 || missingScopes.length) {
Expand Down Expand Up @@ -122,7 +131,6 @@ class Extension {
if (!this._isInitialized){
await this.initialize(this.configData);
}
const SessionStorage = require('./session/session_storage');

let platformConfig = await this.getPlatformConfig(companyId);
platformConfig.oauthClient.setToken(session);
Expand All @@ -135,7 +143,7 @@ class Extension {
const renewTokenRes = await platformConfig.oauthClient.renewAccessToken(session.access_mode === 'offline');
renewTokenRes.access_token_validity = platformConfig.oauthClient.token_expires_at;
session.updateToken(renewTokenRes);
await SessionStorage.saveSession(session);
await this.sessionStorage.saveSession(session);
logger.debug(`Access token renewed for company ${companyId} with response ${logger.safeStringify(renewTokenRes)}`);
}
}
Expand Down Expand Up @@ -188,9 +196,6 @@ class Extension {
}
}


const extension = new Extension();

module.exports = {
extension
Extension
};
40 changes: 40 additions & 0 deletions express/extension_factory.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const { FdkInvalidCluster } = require("./error_code");
const { Extension } = require("./extension")

class ExtensionFactory {
static _extensionMap = {};
static _defaultExt = null;

static getExtension(clusterId) {
const clusterExt = ExtensionFactory._extensionMap[clusterId]
if (clusterId !== null && !clusterExt) {
throw new FdkInvalidCluster(`Extension instance not found for clusterId ${clusterId}`);
}
return clusterExt;
}

static defaultExtInstance() {
return ExtensionFactory._defaultExt;
}

static async initializeExtension(clusterData, clusterId = null) {
const promises = [];
for (let extConfig of clusterData) {
const extInstance = new Extension();
if(clusterId != null && clusterId !== extConfig.cluster_id) {
continue;
}
if (!ExtensionFactory._defaultExt) {
ExtensionFactory._defaultExt = extInstance;
}
const cluster_id = clusterId || extConfig.cluster.replace("https://", "").replace("http://", "");
ExtensionFactory._extensionMap[cluster_id] = extInstance;
promises.push(extInstance.initialize(extConfig))
}
return Promise.all(promises);
}
}

module.exports = {
ExtensionFactory
};
53 changes: 37 additions & 16 deletions express/index.js
Original file line number Diff line number Diff line change
@@ -1,56 +1,77 @@
'use strict';

const { extension } = require('./extension');
const {ExtensionFactory} = require('./extension_factory');
const setupRoutes = require("./routes");
const { setupProxyRoutes } = require("./api_routes");
const Session = require("./session/session");
const SessionStorage = require("./session/session_storage");
const { ApplicationConfig, ApplicationClient } = require("@gofynd/fdk-client-javascript");
const logger = require('./logger');

function setupFdk(data, syncInitialization) {
const multiClusterMode = data.cluster_config !== undefined;
const clusterId = data.cluster?.replace("https://", "").replace("http://", "");
if (data.debug) {
logger.transports[0].level = 'debug';
}
const promiseInit = extension.initialize(data)
.catch(err=>{
logger.error(err);
throw err;
});

const promiseInit = ExtensionFactory.initializeExtension(multiClusterMode? data.cluster_config: [data]).catch(err=>{
logger.error(err);
throw err;
});

const extension = !multiClusterMode? ExtensionFactory.defaultExtInstance(): ExtensionFactory.getExtension(clusterId);

let router = setupRoutes(extension);
let { apiRoutes, applicationProxyRoutes } = setupProxyRoutes();
let { apiRoutes, applicationProxyRoutes } = setupProxyRoutes(extension);

async function getPlatformClient(companyId) {
async function getPlatformClient(companyId, clusterId = null) {
let clusterExt = extension;
if (clusterId) {
clusterExt = ExtensionFactory.getExtension(clusterId)
}
let client = null;
if (!extension.isOnlineAccessMode()) {
if (!clusterExt.isOnlineAccessMode()) {
let sid = Session.generateSessionId(false, {
cluster: extension.cluster,
cluster: clusterExt.cluster,
companyId: companyId
});
let session = await SessionStorage.getSession(sid);
client = await extension.getPlatformClient(companyId, session);
let session = await clusterExt.sessionStorage.getSession(sid);
client = await clusterExt.getPlatformClient(companyId, session);
}
return client;
}

async function getApplicationClient(applicationId, applicationToken) {
async function getApplicationClient(applicationId, applicationToken, clusterId = null) {
let clusterExt = extension;
if (clusterId) {
clusterExt = ExtensionFactory.getExtension(clusterId)
}
let applicationConfig = new ApplicationConfig({
applicationID: applicationId,
applicationToken: applicationToken,
domain: extension.cluster
domain: clusterExt.cluster
});
let applicationClient = new ApplicationClient(applicationConfig);
return applicationClient;
}

function getWebhookRegistry(clusterId) {
let clusterExt = extension;
if (clusterId) {
clusterExt = ExtensionFactory.getExtension(clusterId)
}
return clusterExt.webhookRegistry;
}

const configInstance = {
fdkHandler: router,
extension: extension,
apiRoutes: apiRoutes,
webhookRegistry: extension.webhookRegistry,
applicationProxyRoutes: applicationProxyRoutes,
getPlatformClient: getPlatformClient,
getApplicationClient: getApplicationClient
getApplicationClient: getApplicationClient,
getWebhookRegistry: getWebhookRegistry
};

return syncInitialization? promiseInit.then(()=>configInstance).catch(()=>configInstance): configInstance;
Expand Down
10 changes: 7 additions & 3 deletions express/middleware/session_middleware.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
'use strict';
const { ExtensionFactory } = require('../extension_factory');
const { SESSION_COOKIE_NAME } = require('./../constants');
const SessionStorage = require("../session/session_storage");

function sessionMiddleware(strict) {
function sessionMiddleware(extension, strict) {
return async (req, res, next) => {
try {
const clusterId = req.query.cluster_domain;
if (clusterId) {
extension = ExtensionFactory.getExtension(clusterId)
}
const companyId = req.headers['x-company-id'] || req.query['company_id'];
const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}`
let sessionId = req.signedCookies[compCookieName];
req.fdkSession = await SessionStorage.getSession(sessionId);
req.fdkSession = await extension.sessionStorage.getSession(sessionId);

if(strict && !req.fdkSession) {
return res.status(401).json({ "message": "unauthorized" });
Expand Down
Loading