diff --git a/README.md b/README.md index ac2d0b26..78210440 100644 --- a/README.md +++ b/README.md @@ -1,48 +1,45 @@ # fdk-extension-javascript +- A helper library for extension development on the Fynd Platform. -The FDK Extension JavaScript library is designed to streamline the implementation of OAuth for accessing Fynd Platform APIs and managing webhook subscriptions. This library offers built-in support for Express, Nest.js, and Fastify frameworks. Additionally, it provides flexibility for developing extensions in your preferred framework beyond the default support. +## Overview -This readme provides step-by-step guidance on implementing FDK extensions in different frameworks. +The `FDK Extension JavaScript Library` eases the process of implementing OAuth and managing webhook subscriptions for Fynd Platform APIs. With its framework-agnostic nature, it adapts to any JavaScript framework, offering flexible options for extension development. -# [Express Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/express/README.md) -Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. - -# [Nest.js Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/nest/README.md) -Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. - -# [Fastify Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/fastify/README.md) -Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. +## Usage -# Developing Extensions in other frameworks +### Setting Up OAuth Routes -If you wish to develop an extension in a framework other than Express, Nest.js, or Fastify, refer to the documentation below. +> The process of integrating OAuth functionality into an existing extension involves creating specific routes within the extension: + - `/fp/install`: This route initiates the OAuth flow and obtains the authorization code with user consent. + - Use the `extInstall` handler for this route. It requires three parameters: company_id, application_id, and the extension object, which is obtained from the `setupfdk` method. + - The `extInstall` handler returns the redirect URL for the extension consent page and user session data, which should be sent back from the `/fp/install` route as a redirection. ->The process of integrating OAuth functionality into an existing extension involves creating specific routes within the extension. These routes, namely `/fp/install`, `/fp/auth`, `/fp/autoinstall`, and `/fp/uninstall`, play a crucial role in OAuth implementation. It is essential to attach a `routerHandler` to each of these created routes, which can be obtained from the `setupfdk` function. + - `/fp/auth`: This route is used to exchange the authorization code for an access token. + - Use the `extAuth` handler for this route. It takes five arguments: reqObject, state, code, extension object, and sessionId. The reqObject must contain a valid sessionId. + - The `extAuth` handler returns the redirect URL for the extension home page and user session data, which should be sent back from the `/fp/auth` route as a redirection. -> The `fpInstall` function call requires three parameters: company_id, application_id, and exe data (extension exposed through the setupfdk method). This call will return the redirect URL of an extension consent page and session data that must be sent back. +### Handling Uninstall Events +To manage cleanup when an extension is uninstalled from a company, you need to implement the `/fp/uninstall` route: -> The `fpAuth` function call takes five arguments: reqobject, state, code, ext and sessionId. Request object must contain valid sessionId. This call will return the redirect URL of an installed extension and the session data that must be sent back. +- `/fp/uninstall`: This route is used to handles clean up process of an extension. + - Use the `extUninstall` handler for this route. It takes reqObject, companyId, and extension object as arguments, which is obtained from the `setupfdk` method. + - This handler processes the client_id, company_id, and cluster data received in the request payload when the extension is uninstalled, facilitating the necessary cleanup. -> The `fpAutoInstall` function call will take reqObject, companyId, code, and extension data as arguments. This is beneficial for installing the extension whenever a company is created. - -> The `fpUninstall` function call will take reqObject, companyId, and extension as arguments. This facilitates the uninstallation of a specific extension. - -#### Initial Setup +#### Example code ```javascript const express = require("express"); const bodyParser = require("body-parser"); const cookieParser = require("cookie-parser"); const { setupFdk } = require("fdk-extension-javascript"); -const { RedisStorage } = require("fdk-extension-javascript/storage"); //RedisStorage class is provided by default. If you have implemented custom storage class, use here. -const Redis = require("ioredis"); +const sqlite3 = require('sqlite3').verbose(); +const { SQLiteStorage } = require("fdk-extension-javascript/express/storage"); //SQLiteStorage class is provided by default. If you have implemented custom storage class, use here. +const sqliteInstance = new sqlite3.Database('session_storage.db'); const app = express(); app.use(cookieParser("ext.session")); app.use(bodyParser.json({ limit: "2mb" })); -const redis = new Redis(); - let extensionHandler = { auth: async function (data) { console.log("called auth callback"); @@ -56,24 +53,22 @@ let extensionHandler = { let fdkClient = setupFdk({ api_key: "", // API Key of an extension for authentication. api_secret: "", // API Secret of an extension for authentication. - base_url: baseUrl, // optional. Base URL for extension. - scopes: ["company/products"], // optional. An array of scopes indicating the specific permissions needed for an extension. - callbacks: extensionHandler, // The callback function to handle extension-related tasks. - storage: new RedisStorage(redis), // An instance of storage (e.g., RedisStorage) for data storage. + base_url: "", // Base URL for extension. + callbacks: extensionHandler, // An object containing callback functions like auth, uninstall and others, allowing you to execute custom tasks related to your extension's lifecycle. + storage: new SQLiteStorage(sqliteInstance), // An instance of storage (e.g. SQLiteStorage) for to store and manage user session data. access_mode: "offline", // Access mode of an extension. It can be `online` or `offline`. - cluster: "https://api.fyndx0.de", // optional. The API url of the Fynd Platform cluster. }); -let router = app.express.Router(); +let router = express.Router(); const handlers = fdkClient.routerHandlers; // Functions that constains implementaion of OAuth router.get("/fp/install", async (req, res, next) => { - const { redirectUrl, fdkSession } = await handlers.fpInstall( + const { redirectUrl, fdkSession } = await handlers.extInstall( req.query.company_id, req.query.application_id, // optional fdkClient.extension ); - // Return redirect url obtained in fpInstall call + // Return redirect url obtained in extInstall call // Return fdk session (for example in cookies or jwt token or any other form ) /*res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -88,16 +83,16 @@ router.get("/fp/install", async (req, res, next) => { router.get("/fp/auth", async (req, res, next) => { let sessionId = session_id; // Get the session id from cookies or jwt token or any other form - req.fdkSession = await redis.get(sessionId); // Attach session to request object + req.fdkSession = await sqliteStorageInstance.get(sessionId); // Attach session to request object req.extension = fdkClient.extension; // Attach extension to request object - const { redirectUrl, fdkSession } = await handlers.fpAuth( + const { redirectUrl, fdkSession } = await handlers.extAuth( reqObj, req.query.state, req.query.code, fdkClient.extension, sessionId ); - // Return redirect url obtained in fpInstall call + // Return redirect url obtained in extInstall call // Return fdk session (for example in cookies or jwt token or any other form ) /*res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -109,18 +104,8 @@ router.get("/fp/auth", async (req, res, next) => { res.redirect(redirectUrl); */ }); -router.post("/fp/auto_install", async (req, res, next) => { - await handlers.fpAutoInstall( - reqObj, - req.body.company_id, - req.body.code, - fdkClient.extension - ); - res.json({ message: "success" }); -}); - router.post("/fp/uninstall", async (req, res, next) => { - await handlers.fpUninstall( + await handlers.extUninstall( reqObj, req.body.company_id, fdkClient.extension @@ -131,21 +116,22 @@ router.post("/fp/uninstall", async (req, res, next) => { app.use(router); app.listen(3000); ``` -### Parameters of setupFDK function + +### Parameters Table #### Parameter table for `setupFdk` function | Parameter | Description | | ------------- | ------------- | | api_key | API Key of an extension for authentication. | | api_secret | API Secret of an extension for authentication. | -| base_url? | Base URL for extension. | -| scopes? | An array of scopes indicating the specific permissions needed for an extension. | -| callbacks | The callback function to handle extension-related tasks. | -| storage | An instance of storage (e.g., RedisStorage) for data storage. | +| base_url | Base URL for extension. | +| scopes | An array of scopes indicating the specific permissions needed for an extension. | +| callbacks | An object containing callback functions like auth, uninstall and others, allowing you to execute custom tasks related to your extension's lifecycle. | +| storage | An instance of storage (e.g. SQLiteStorage) for to store and manage user session data. | | access_mode | Access mode of an extension. It can be `online` or `offline`. | -| cluster? | The API url of the Fynd Platform cluster. | +| cluster? | The API endpoint of the Fynd Platform cluster. | | debug? | Enable debug logs if it is `true`. Value can be `true` or `false`. | -| [webhook_config](https://github.com/gofynd/fdk-extension-javascript?tab=readme-ov-file#parameter-table-for-webhook-configuration) | Necessary configuration for webhooks. | +| [webhook_config](#parameter-table-for-webhook-configuration) | Necessary configuration for webhooks. | #### Parameter table for `webhook` configuration | Parameter | Description | @@ -154,12 +140,12 @@ app.listen(3000); | notification_email | Email address for webhook related notifications. | | subscribe_on_install? | Whether to auto subscribe to all webhooks on extension installation. It can be true or false. | | subscribed_saleschannel? | If `specific` then you have to manually subscribe to sales channel/website level events for individual sales channels. Value can be `all` or `optional`. | -| [event_map](https://github.com/gofynd/fdk-extension-javascript?tab=readme-ov-file#parameter-table-for-event_map-object) | A mapping of events to corresponding handlers for webhook processing. | +| [event_map](#parameter-table-for-event_map-object) | A mapping of events to corresponding handlers for webhook processing. | #### Parameter table for `event_map` object | Parameter | Description | | ------------- | ------------- | -| key | API endpoint to process webhooks event. | +| key | Name of a webhook event. | | value | `version` and `handler` | | | `version` -- API version of specified event | | | `handler` -- A handler function when specified event occures| @@ -252,7 +238,7 @@ app.use(fdkClient.partnerApiRoutes); #### How to register for webhook events? Webhook events can be helpful to handle tasks when certain events occur on platform. You can subscribe to such events by passing `webhook_config` in setupFdk function. -Please refer [webhook documentation](https://partners.fynd.com/help/docs/partners/webhooks/webhook-events/article#payload) to know about event payload and it's structure. +Please refer [webhook documentation](https://partners.fynd.com/help/docs/webhooks/latest/company#article) to know about event payload and it's structure. ```javascript @@ -269,7 +255,7 @@ let fdkClient = setupFdk({ console.log("called uninstall callback"); }, }, - storage: new RedisStorage(redis), + storage: new SQLiteStorage(sqliteInstance), access_mode: "offline", webhook_config: { api_path: "/api/v1/webhooks", // API endpoint to process webhooks event. @@ -331,4 +317,18 @@ Other way to update webhook config manually for a company is to call `syncEvents # [Custom storage class](https://github.com/gofynd/fdk-extension-javascript/tree/main/storage/README.md) -The FDK Extension JavaScript library provides built-in support for Redis and in-memory storage options as default choices for session data storage. However, if you require a different storage option, this readme will guide you through the process of implementing a custom storage class. \ No newline at end of file +The FDK Extension JavaScript library provides built-in support for SQLite, Redis and in-memory storage options as default choices for session data storage. However, if you require a different storage option, this readme will guide you through the process of implementing a custom storage class. + +# Supported frameworks +This library comes with built-in compatibility for Express, NestJS, and Fastify frameworks. + +Below, you'll find step-by-step instructions for implementing FDK extensions library in each of these frameworks. + +# [Express Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/express/README.md) +Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. + +# [Nest.js Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/nest/README.md) +Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. + +# [Fastify Framework](https://github.com/gofynd/fdk-extension-javascript/tree/main/fastify/README.md) +Follow this readme if you intend to develop FDK extensions in the Express framework. The instructions outlined here will guide you through the entire implementation process. diff --git a/examples/extension.handler.js b/examples/extension.handler.js index 0935f2ed..eaa5b0ee 100644 --- a/examples/extension.handler.js +++ b/examples/extension.handler.js @@ -5,12 +5,6 @@ async function auth(req) { return req.extension.base_url + `?company_id=${req.query.company_id}`; } -async function autoInstall(req) { - // Write you code here to do any special handling on auto install event is received. - // Here any handling on auth call back should under here as well since this event will be called when extension is installed - // but auth callback won't be triggered until user launches extension -} - async function uninstall(req) { // Write your code here to cleanup data related to extension // If task is time taking then process it async on other process. @@ -19,5 +13,4 @@ async function uninstall(req) { module.exports = { auth: auth, uninstall: uninstall, - auto_install: autoInstall }; \ No newline at end of file diff --git a/express/routes.js b/express/routes.js index cbea7013..8fb2231a 100644 --- a/express/routes.js +++ b/express/routes.js @@ -16,7 +16,7 @@ function setupRoutes(ext) { // ?company_id=1&client_id=123313112122 let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, ext); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, ext); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}` res.header['x-company-id'] = companyId; @@ -42,7 +42,7 @@ function setupRoutes(ext) { req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = ext; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, ext, req.fdkSession?.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, ext, req.fdkSession?.id); res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -58,22 +58,10 @@ function setupRoutes(ext) { } }); - - FdkRoutes.post("/fp/auto_install", async (req, res, next) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj ,req.body.company_id, req.body.code, ext); - return res.json({ message: "success" }); - } - catch (error) { - next(error) - } - }); - FdkRoutes.post("/fp/uninstall", async (req, res, next) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, ext); + await handlers.extUninstall(reqObj, req.body.company_id, ext); return res.json({ success: true }); } catch (error) { diff --git a/fastify/routes.js b/fastify/routes.js index f0268036..a96c1f49 100644 --- a/fastify/routes.js +++ b/fastify/routes.js @@ -12,7 +12,7 @@ async function setupRoutes(fastify, options){ // ?company_id=1&client_id=123313112122 let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, extension); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, extension); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}` res.header['x-company-id'] = companyId; @@ -40,7 +40,7 @@ async function setupRoutes(fastify, options){ req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, extension, req.fdkSession?.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, extension, req.fdkSession?.id); res.header['x-company-id'] = companyId; res.setCookie(compCookieName, fdkSession.id, { domain: req.hostname, @@ -58,22 +58,10 @@ async function setupRoutes(fastify, options){ } }); - - fastify.post("/fp/auto_install", async (req, res) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj ,req.body.company_id, req.body.code, extension); - res.send({ message: "success" }); - } - catch (error) { - throw error; - } - }); - fastify.post("/fp/uninstall", async (req, res) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, extension); + await handlers.extUninstall(reqObj, req.body.company_id, extension); res.send({ success: true }); } catch (error) { diff --git a/lib/handlers/index.js b/lib/handlers/index.js index 8920ead5..a640584c 100644 --- a/lib/handlers/index.js +++ b/lib/handlers/index.js @@ -8,7 +8,7 @@ const { FdkInvalidOAuthError, } = require("../../lib/error_code"); -const fpInstall = async function fpInstall(company_id, application_id, redirect_path, ext) { +const extInstall = async function extInstall(company_id, application_id, redirect_path, ext) { let companyId = parseInt(company_id); let platformConfig = await ext.getPlatformConfig(companyId); let session; @@ -55,7 +55,7 @@ const fpInstall = async function fpInstall(company_id, application_id, redirect_ }; }; -const fpAuth = async function fpAuth (reqObj, state, code, ext, sessionId) { +const extAuth = async function extAuth (reqObj, state, code, ext, sessionId) { const fdkSession = await SessionStorage.getSession(sessionId); if (!fdkSession) { throw new FdkSessionNotFoundError( @@ -130,61 +130,7 @@ const fpAuth = async function fpAuth (reqObj, state, code, ext, sessionId) { }; }; -const fpAutoInstall = async function fpAutoInstall (reqObj, company_id, code, ext) { - logger.debug( - `Extension auto install started for company: ${company_id} on company creation.` - ); - - let platformConfig = await ext.getPlatformConfig(company_id); - let sid = Session.generateSessionId(false, { - cluster: ext.cluster, - id: company_id, - }); - - let session = await SessionStorage.getSession(sid); - if (!session) { - session = new Session(sid); - } else if (session.extension_id !== ext.api_key) { - session = new Session(sid); - } - - let offlineTokenRes = await platformConfig.oauthClient.getOfflineAccessToken( - ext.scopes, - code - ); - - session.company_id = company_id; - session.scope = ext.scopes; - session.state = uuidv4(); - session.extension_id = ext.api_key; - offlineTokenRes.access_token_validity = - platformConfig.oauthClient.token_expires_at; - offlineTokenRes.access_mode = "offline"; - session.updateToken(offlineTokenRes); - - if (!ext.isOnlineAccessMode()) { - await SessionStorage.saveSession(session); - } - - if ( - ext.webhookRegistry.isInitialized && - ext.webhookRegistry.isSubscribeOnInstall - ) { - const client = await ext.getPlatformClient(company_id, session); - await ext.webhookRegistry.syncEvents(client, null, true).catch((err) => { - logger.error(err); - }); - } - logger.debug( - `Extension installed for company: ${company_id} on company creation.` - ); - if (ext.callbacks.auto_install) { - await ext.callbacks.auto_install(reqObj); - } - return; -}; - -const fpUninstall = async function fpUninstall (reqObj,company_id, ext) { +const extUninstall = async function extUninstall (reqObj,company_id, ext) { let sid; if (!ext.isOnlineAccessMode()) { sid = Session.generateSessionId(false, { @@ -295,10 +241,9 @@ const admAuth = async function admAuth(state, code, ext, sessionId){ }; } module.exports = { - fpAuth: fpAuth, - fpInstall: fpInstall, - fpAutoInstall: fpAutoInstall, - fpUninstall: fpUninstall, + extAuth: extAuth, + extInstall: extInstall, + extUninstall: extUninstall, admInstall: admInstall, admAuth: admAuth }; diff --git a/nest/extension.controller.js b/nest/extension.controller.js index 52572849..46a7ab24 100644 --- a/nest/extension.controller.js +++ b/nest/extension.controller.js @@ -14,7 +14,7 @@ class ExtensionController { // ?company_id=1&client_id=123313112122 let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, extension); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, extension); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}` res.header['x-company-id'] = companyId; @@ -41,7 +41,7 @@ class ExtensionController { req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, extension, req.fdkSession?.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, extension, req.fdkSession?.id); res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -57,27 +57,13 @@ class ExtensionController { } } - @Post('fp/auto_install') - @HttpCode(200) - @Bind(Req(), Res(), Next()) - async autoInstall(req, res, next) { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj ,req.body.company_id, req.body.code, extension); - res.json({ message: "success" }); - } - catch (error) { - next(error) - } - } - @Post('fp/uninstall') @HttpCode(200) @Bind(Req(), Res(), Next()) async unInstall(req, res, next) { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, extension); + await handlers.extUninstall(reqObj, req.body.company_id, extension); res.json({ success: true }); } catch (error) { diff --git a/spec/tests/custom_framework.spec.js b/spec/tests/custom_framework.spec.js index da1cb629..c0dce9e4 100644 --- a/spec/tests/custom_framework.spec.js +++ b/spec/tests/custom_framework.spec.js @@ -42,7 +42,7 @@ describe("Custom framework integration as express - Extension launch flow", () = router.get("/fp/install", async (req, res, next) => { let companyId = req.query.company_id; - const { redirectUrl, fdkSession } = await handlers.fpInstall( + const { redirectUrl, fdkSession } = await handlers.extInstall( companyId, req.query.application_id, 'test', // redirect path @@ -68,7 +68,7 @@ describe("Custom framework integration as express - Extension launch flow", () = req.fdkSession = await redis.get(sessionId); req.extension = fdk_instance.extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth( + const { redirectUrl, fdkSession } = await handlers.extAuth( reqObj, req.query.state, req.query.code, @@ -89,24 +89,10 @@ describe("Custom framework integration as express - Extension launch flow", () = } }); - router.post("/fp/auto_install", async (req, res, next) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall( - reqObj, - req.body.company_id, - req.body.code, - fdk_instance.extension - ); - res.json({ message: "success" }); - } catch (error) { - next(error); - } - }); router.post("/fp/uninstall", async (req, res, next) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall( + await handlers.extUninstall( reqObj, req.body.company_id, fdk_instance.extension @@ -226,13 +212,6 @@ describe("Custom framework integration as express - Extension launch flow", () = expect(client.cart).toBeDefined(); }); - it("/fp/auto_install", async () => { - let response = await request - .post(`/custom/fp/auto_install`) - .send({ company_id: 1 }); - expect(response.status).toBe(200); - }); - it("/fp/install auth call back should contains application id", async () => { let response = await request .get( diff --git a/spec/tests/custom_framework_jwt.spec.js b/spec/tests/custom_framework_jwt.spec.js index 955eff5c..c885ca2b 100644 --- a/spec/tests/custom_framework_jwt.spec.js +++ b/spec/tests/custom_framework_jwt.spec.js @@ -43,7 +43,7 @@ describe("Custom framework integration as express with jwt token - Extension lau router.get("/fp/install", async (req, res, next) => { let companyId = req.query.company_id; - const { redirectUrl, fdkSession } = await handlers.fpInstall( + const { redirectUrl, fdkSession } = await handlers.extInstall( companyId, req.query.application_id, 'test', // redirect path @@ -62,7 +62,7 @@ describe("Custom framework integration as express with jwt token - Extension lau req.fdkSession = await redis.get(sessionId); req.extension = fdk_instance.extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth( + const { redirectUrl, fdkSession } = await handlers.extAuth( reqObj, req.query.state, req.query.code, @@ -77,24 +77,10 @@ describe("Custom framework integration as express with jwt token - Extension lau } }); - router.post("/fp/auto_install", async (req, res, next) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall( - reqObj, - req.body.company_id, - req.body.code, - fdk_instance.extension - ); - return res.json({ message: "success" }); - } catch (error) { - next(error); - } - }); router.post("/fp/uninstall", async (req, res, next) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall( + await handlers.extUninstall( reqObj, req.body.company_id, fdk_instance.extension @@ -213,13 +199,6 @@ describe("Custom framework integration as express with jwt token - Extension lau expect(client.cart).toBeDefined(); }); - it("/fp/auto_install", async () => { - let response = await request - .post(`/custom_jwt/fp/auto_install`) - .send({ company_id: 1 }); - expect(response.status).toBe(200); - }); - it("/fp/install auth call back should contains application id", async () => { let response = await request .get( diff --git a/spec/tests/extension.controller.spec.js b/spec/tests/extension.controller.spec.js index ee2d75d8..3d6da4b8 100644 --- a/spec/tests/extension.controller.spec.js +++ b/spec/tests/extension.controller.spec.js @@ -73,13 +73,6 @@ describe("Nestjs --> Extension launch flow", () => { expect(response.status).toBe(302); }); - it("/fp/auto_install", async () => { - let response = await request - .post(`/fp/auto_install`) - .send({ company_id: 1 }); - expect(response.status).toBe(200); - }); - it("/fp/uninstall", async () => { let response = await request.post("/fp/uninstall").send({ company_id: 1 }); expect(response.status).toBe(200); diff --git a/spec/tests/fastify.spec.js b/spec/tests/fastify.spec.js index 823f0a24..46d0bf59 100644 --- a/spec/tests/fastify.spec.js +++ b/spec/tests/fastify.spec.js @@ -154,13 +154,6 @@ describe("Fastify --> Extension launch flow", () => { expect(client.cart).toBeDefined(); }); - it('/fp/auto_install', async () => { - let response = await request - .post(`/fp/auto_install`) - .send({ company_id: 1 }); - expect(response.status).toBe(200); - }); - it('/fp/install redirect url should contains application id', async () => { let response = await request .get(`/fp/install?company_id=1&install_event=true&application_id=${applicationId}`) diff --git a/spec/tests/routes.spec.js b/spec/tests/routes.spec.js index 75686ad9..fca589bb 100644 --- a/spec/tests/routes.spec.js +++ b/spec/tests/routes.spec.js @@ -106,13 +106,6 @@ describe("Extension launch flow", () => { expect(client.cart).toBeDefined(); }); - it('/fp/auto_install', async () => { - let response = await request - .post(`/fp/auto_install`) - .send({ company_id: 1 }); - expect(response.status).toBe(200); - }); - it('/fp/install redirect url should contains application id', async () => { let response = await request .get(`/fp/install?company_id=1&install_event=true&application_id=${applicationId}`) diff --git a/types/express/routes.js b/types/express/routes.js index 7c64ee81..b720a99a 100644 --- a/types/express/routes.js +++ b/types/express/routes.js @@ -12,7 +12,7 @@ function setupRoutes(ext) { try { let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, ext); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, ext); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}`; res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { @@ -37,7 +37,7 @@ function setupRoutes(ext) { req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = ext; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, ext, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, ext, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -52,20 +52,10 @@ function setupRoutes(ext) { next(error); } }); - FdkRoutes.post("/fp/auto_install", async (req, res, next) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj, req.body.company_id, req.body.code, ext); - return res.json({ message: "success" }); - } - catch (error) { - next(error); - } - }); FdkRoutes.post("/fp/uninstall", async (req, res, next) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, ext); + await handlers.extUninstall(reqObj, req.body.company_id, ext); return res.json({ success: true }); } catch (error) { diff --git a/types/fastify/index.d.ts b/types/fastify/index.d.ts index db1f0cde..65f721c3 100644 --- a/types/fastify/index.d.ts +++ b/types/fastify/index.d.ts @@ -35,16 +35,15 @@ export function setupFdk(data: any, syncInitialization: any): { getApplicationConfig: typeof getApplicationConfig; getUserData: typeof getUserData; routerHandlers: { - fpAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ + extAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ redirectUrl: any; fdkSession: any; }>; - fpInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ + extInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); }>; - fpAutoInstall: (reqObj: any, company_id: any, code: any, ext: any) => Promise; - fpUninstall: (reqObj: any, company_id: any, ext: any) => Promise; + extUninstall: (reqObj: any, company_id: any, ext: any) => Promise; admInstall: (organization_id: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); @@ -90,16 +89,15 @@ export function setupFdk(data: any, syncInitialization: any): { getApplicationConfig: typeof getApplicationConfig; getUserData: typeof getUserData; routerHandlers: { - fpAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ + extAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ redirectUrl: any; fdkSession: any; }>; - fpInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ + extInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); }>; - fpAutoInstall: (reqObj: any, company_id: any, code: any, ext: any) => Promise; - fpUninstall: (reqObj: any, company_id: any, ext: any) => Promise; + extUninstall: (reqObj: any, company_id: any, ext: any) => Promise; admInstall: (organization_id: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); diff --git a/types/fastify/routes.js b/types/fastify/routes.js index 9199b51a..422649ab 100644 --- a/types/fastify/routes.js +++ b/types/fastify/routes.js @@ -9,7 +9,7 @@ async function setupRoutes(fastify, options) { try { let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, extension); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, extension); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}`; res.header['x-company-id'] = companyId; res.setCookie(compCookieName, fdkSession.id, { @@ -36,7 +36,7 @@ async function setupRoutes(fastify, options) { req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, extension, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, extension, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); res.header['x-company-id'] = companyId; res.setCookie(compCookieName, fdkSession.id, { domain: req.hostname, @@ -53,20 +53,10 @@ async function setupRoutes(fastify, options) { throw error; } }); - fastify.post("/fp/auto_install", async (req, res) => { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj, req.body.company_id, req.body.code, extension); - res.send({ message: "success" }); - } - catch (error) { - throw error; - } - }); fastify.post("/fp/uninstall", async (req, res) => { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, extension); + await handlers.extUninstall(reqObj, req.body.company_id, extension); res.send({ success: true }); } catch (error) { diff --git a/types/lib/handlers/index.d.ts b/types/lib/handlers/index.d.ts index 324b6ceb..1edb2604 100644 --- a/types/lib/handlers/index.d.ts +++ b/types/lib/handlers/index.d.ts @@ -1,13 +1,12 @@ -export function fpAuth(reqObj: any, state: any, code: any, ext: any, sessionId: any): Promise<{ +export function extAuth(reqObj: any, state: any, code: any, ext: any, sessionId: any): Promise<{ redirectUrl: any; fdkSession: any; }>; -export function fpInstall(company_id: any, application_id: any, redirect_path: any, ext: any): Promise<{ +export function extInstall(company_id: any, application_id: any, redirect_path: any, ext: any): Promise<{ redirectUrl: any; fdkSession: Session; }>; -export function fpAutoInstall(reqObj: any, company_id: any, code: any, ext: any): Promise; -export function fpUninstall(reqObj: any, company_id: any, ext: any): Promise; +export function extUninstall(reqObj: any, company_id: any, ext: any): Promise; export function admInstall(organization_id: any, ext: any): Promise<{ redirectUrl: any; fdkSession: Session; diff --git a/types/lib/handlers/index.js b/types/lib/handlers/index.js index b12aef2d..7a46a3e7 100644 --- a/types/lib/handlers/index.js +++ b/types/lib/handlers/index.js @@ -4,7 +4,7 @@ const { v4: uuidv4 } = require("uuid"); const logger = require("../../lib/logger"); const urljoin = require('url-join'); const { FdkSessionNotFoundError, FdkInvalidOAuthError, } = require("../../lib/error_code"); -const fpInstall = async function fpInstall(company_id, application_id, redirect_path, ext) { +const extInstall = async function extInstall(company_id, application_id, redirect_path, ext) { let companyId = parseInt(company_id); let platformConfig = await ext.getPlatformConfig(companyId); let session; @@ -42,7 +42,7 @@ const fpInstall = async function fpInstall(company_id, application_id, redirect_ fdkSession: session, }; }; -const fpAuth = async function fpAuth(reqObj, state, code, ext, sessionId) { +const extAuth = async function extAuth(reqObj, state, code, ext, sessionId) { const fdkSession = await SessionStorage.getSession(sessionId); if (!fdkSession) { throw new FdkSessionNotFoundError("Can not complete oauth process as session not found"); @@ -99,46 +99,7 @@ const fpAuth = async function fpAuth(reqObj, state, code, ext, sessionId) { fdkSession: fdkSession, }; }; -const fpAutoInstall = async function fpAutoInstall(reqObj, company_id, code, ext) { - logger.debug(`Extension auto install started for company: ${company_id} on company creation.`); - let platformConfig = await ext.getPlatformConfig(company_id); - let sid = Session.generateSessionId(false, { - cluster: ext.cluster, - id: company_id, - }); - let session = await SessionStorage.getSession(sid); - if (!session) { - session = new Session(sid); - } - else if (session.extension_id !== ext.api_key) { - session = new Session(sid); - } - let offlineTokenRes = await platformConfig.oauthClient.getOfflineAccessToken(ext.scopes, code); - session.company_id = company_id; - session.scope = ext.scopes; - session.state = uuidv4(); - session.extension_id = ext.api_key; - offlineTokenRes.access_token_validity = - platformConfig.oauthClient.token_expires_at; - offlineTokenRes.access_mode = "offline"; - session.updateToken(offlineTokenRes); - if (!ext.isOnlineAccessMode()) { - await SessionStorage.saveSession(session); - } - if (ext.webhookRegistry.isInitialized && - ext.webhookRegistry.isSubscribeOnInstall) { - const client = await ext.getPlatformClient(company_id, session); - await ext.webhookRegistry.syncEvents(client, null, true).catch((err) => { - logger.error(err); - }); - } - logger.debug(`Extension installed for company: ${company_id} on company creation.`); - if (ext.callbacks.auto_install) { - await ext.callbacks.auto_install(reqObj); - } - return; -}; -const fpUninstall = async function fpUninstall(reqObj, company_id, ext) { +const extUninstall = async function extUninstall(reqObj, company_id, ext) { let sid; if (!ext.isOnlineAccessMode()) { sid = Session.generateSessionId(false, { @@ -229,10 +190,9 @@ const admAuth = async function admAuth(state, code, ext, sessionId) { }; }; module.exports = { - fpAuth: fpAuth, - fpInstall: fpInstall, - fpAutoInstall: fpAutoInstall, - fpUninstall: fpUninstall, + extAuth: extAuth, + extInstall: extInstall, + extUninstall: extUninstall, admInstall: admInstall, admAuth: admAuth }; diff --git a/types/nest/extension.controller.d.ts b/types/nest/extension.controller.d.ts index 2436a760..6b6a743a 100644 --- a/types/nest/extension.controller.d.ts +++ b/types/nest/extension.controller.d.ts @@ -2,7 +2,6 @@ export = ExtensionController; declare class ExtensionController { install(req: any, res: any, next: any): Promise; auth(req: any, res: any, next: any): Promise; - autoInstall(req: any, res: any, next: any): Promise; unInstall(req: any, res: any, next: any): Promise; admInstall(req: any, res: any, next: any): Promise; admAuth(req: any, res: any, next: any): Promise; diff --git a/types/nest/extension.controller.js b/types/nest/extension.controller.js index bd856617..70dc9c37 100644 --- a/types/nest/extension.controller.js +++ b/types/nest/extension.controller.js @@ -18,7 +18,7 @@ let ExtensionController = class ExtensionController { try { let companyId = parseInt(req.query.company_id); let redirectPath = req.query.redirect_path; - const { redirectUrl, fdkSession } = await handlers.fpInstall(req.query.company_id, req.query.application_id, redirectPath, extension); + const { redirectUrl, fdkSession } = await handlers.extInstall(req.query.company_id, req.query.application_id, redirectPath, extension); const compCookieName = `${SESSION_COOKIE_NAME}_${companyId}`; res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { @@ -43,7 +43,7 @@ let ExtensionController = class ExtensionController { req.fdkSession = await SessionStorage.getSession(sessionId); req.extension = extension; const reqObj = formRequestObject(req); - const { redirectUrl, fdkSession } = await handlers.fpAuth(reqObj, req.query.state, req.query.code, extension, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); + const { redirectUrl, fdkSession } = await handlers.extAuth(reqObj, req.query.state, req.query.code, extension, (_a = req.fdkSession) === null || _a === void 0 ? void 0 : _a.id); res.header['x-company-id'] = companyId; res.cookie(compCookieName, fdkSession.id, { secure: true, @@ -58,20 +58,10 @@ let ExtensionController = class ExtensionController { next(error); } } - async autoInstall(req, res, next) { - try { - const reqObj = formRequestObject(req); - await handlers.fpAutoInstall(reqObj, req.body.company_id, req.body.code, extension); - res.json({ message: "success" }); - } - catch (error) { - next(error); - } - } async unInstall(req, res, next) { try { const reqObj = formRequestObject(req); - await handlers.fpUninstall(reqObj, req.body.company_id, extension); + await handlers.extUninstall(reqObj, req.body.company_id, extension); res.json({ success: true }); } catch (error) { @@ -132,14 +122,6 @@ __decorate([ __metadata("design:paramtypes", [Object, Object, Object]), __metadata("design:returntype", Promise) ], ExtensionController.prototype, "auth", null); -__decorate([ - Post('fp/auto_install'), - HttpCode(200), - Bind(Req(), Res(), Next()), - __metadata("design:type", Function), - __metadata("design:paramtypes", [Object, Object, Object]), - __metadata("design:returntype", Promise) -], ExtensionController.prototype, "autoInstall", null); __decorate([ Post('fp/uninstall'), HttpCode(200), diff --git a/types/nest/index.d.ts b/types/nest/index.d.ts index 15531dc7..52ea6b55 100644 --- a/types/nest/index.d.ts +++ b/types/nest/index.d.ts @@ -33,16 +33,15 @@ export function setupFdk(data: any, syncInitialization: any): { getApplicationConfig: typeof getApplicationConfig; getUserData: typeof getUserData; routerHandlers: { - fpAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ + extAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ redirectUrl: any; fdkSession: any; }>; - fpInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ + extInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); }>; - fpAutoInstall: (reqObj: any, company_id: any, code: any, ext: any) => Promise; - fpUninstall: (reqObj: any, company_id: any, ext: any) => Promise; + extUninstall: (reqObj: any, company_id: any, ext: any) => Promise; admInstall: (organization_id: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); @@ -87,16 +86,15 @@ export function setupFdk(data: any, syncInitialization: any): { getApplicationConfig: typeof getApplicationConfig; getUserData: typeof getUserData; routerHandlers: { - fpAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ + extAuth: (reqObj: any, state: any, code: any, ext: any, sessionId: any) => Promise<{ redirectUrl: any; fdkSession: any; }>; - fpInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ + extInstall: (company_id: any, application_id: any, redirect_path: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session"); }>; - fpAutoInstall: (reqObj: any, company_id: any, code: any, ext: any) => Promise; - fpUninstall: (reqObj: any, company_id: any, ext: any) => Promise; + extUninstall: (reqObj: any, company_id: any, ext: any) => Promise; admInstall: (organization_id: any, ext: any) => Promise<{ redirectUrl: any; fdkSession: import("../lib/session/session");