@gohighlevel/api-client
Version:
Official SDK for HighLevel Public APIs
273 lines • 10.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoDBSessionStorage = void 0;
const mongodb_1 = require("mongodb");
const session_storage_1 = require("./session-storage");
const logging_1 = require("../logging");
/**
* MongoDB implementation of SessionStorage
* Provides MongoDB-based storage for sessions, tokens, and related data
*/
class MongoDBSessionStorage extends session_storage_1.SessionStorage {
constructor(dbUrl, dbName, collectionName = 'application_sessions', logger) {
super(logger ? logger.child('MongoDB') : new logging_1.Logger('warn', 'GHL SDK MongoDB'));
this.client = null;
this.db = null;
this.clientId = '';
this.isConnected = false;
this.dbUrl = dbUrl;
this.dbName = dbName;
this.collectionName = collectionName;
}
/**
* Set the client ID (called automatically by HighLevel class)
* @param clientId - The client ID from HighLevel configuration
*/
setClientId(clientId) {
if (!clientId) {
throw new Error('ClientId is required for session storage');
}
this.clientId = clientId;
this.logger.debug(`SessionStorage clientId set: ${this.getApplicationId()}`);
}
/**
* Extract applicationId from clientId (first part before "-")
* @returns Application ID extracted from clientId
*/
getApplicationId() {
if (!this.clientId) {
throw new Error('ClientId not set. Make sure HighLevel class has a valid clientId configured.');
}
return this.clientId.split('-')[0];
}
/**
* Generate a unique key combining applicationId and resourceId
* @param resourceId - The resource identifier (companyId or locationId)
* @returns Unique composite key
*/
generateUniqueKey(resourceId) {
const applicationId = this.getApplicationId();
return `${applicationId}:${resourceId}`;
}
/**
* Initialize the MongoDB connection
*/
async init() {
try {
this.client = new mongodb_1.MongoClient(this.dbUrl);
await this.client.connect();
this.db = this.client.db(this.dbName);
await this.createCollection(this.collectionName);
this.isConnected = true;
this.logger.info(`Connected to MongoDB database: ${this.dbName}`);
}
catch (error) {
this.logger.error('Failed to connect to MongoDB:', error);
throw error;
}
}
/**
* Close the MongoDB connection
*/
async disconnect() {
try {
if (this.isConnected && this.client) {
await this.client.close();
this.isConnected = false;
this.db = null;
this.client = null;
this.logger.info('Disconnected from MongoDB');
}
}
catch (error) {
this.logger.error('Error disconnecting from MongoDB:', error);
throw error;
}
}
/**
* Create a collection if it doesn't exist
* @param collectionName - Name of the collection to create
*/
async createCollection(collectionName) {
if (!this.db) {
throw new Error('Database not initialized. Call init() first.');
}
try {
// Get list of existing collections
const collections = await this.db.listCollections().toArray();
const collectionExists = collections.some(col => col.name === collectionName);
if (!collectionExists) {
await this.db.createCollection(collectionName);
this.logger.debug(`Created MongoDB collection: ${collectionName}`);
}
else {
this.logger.debug(`MongoDB collection already exists: ${collectionName}`);
}
}
catch (error) {
this.logger.error(`Error creating collection ${collectionName}:`, error);
throw error;
}
}
/**
* Get a reference to a collection
* @param collectionName - Name of the collection to get
*/
async getCollection(collectionName) {
if (!this.db) {
throw new Error('Database not initialized. Call init() first.');
}
// Ensure collection exists
await this.createCollection(collectionName);
return this.db.collection(collectionName);
}
/**
* Store a session in MongoDB
* @param resourceId - Unique identifier: it can be a companyId or a locationId
* @param sessionData - Session data to store
*/
async setSession(resourceId, sessionData) {
try {
const collection = await this.getCollection(this.collectionName);
const applicationId = this.getApplicationId();
const uniqueKey = this.generateUniqueKey(resourceId);
const sessionDocument = {
uniqueKey,
applicationId,
resourceId,
...sessionData,
expire_at: this.calculateExpireAt(sessionData.expires_in),
createdAt: new Date(),
updatedAt: new Date()
};
await collection.findOneAndReplace({ uniqueKey }, sessionDocument, { upsert: true });
this.logger.debug(`Session stored: ${uniqueKey}`);
}
catch (error) {
this.logger.error(`Error storing session ${this.getApplicationId()}:${resourceId}:`, error);
throw error;
}
}
/**
* Retrieve a session from MongoDB
* @param resourceId - Unique identifier: it can be a companyId or a locationId
* @returns Session data or null if not found
*/
async getSession(resourceId) {
try {
const collection = await this.getCollection(this.collectionName);
const uniqueKey = this.generateUniqueKey(resourceId);
const sessionDocument = await collection.findOne({ uniqueKey });
if (!sessionDocument) {
return null;
}
this.logger.debug(`Session retrieved: ${uniqueKey}`);
// Return the session data including expire_at but without MongoDB metadata
const { uniqueKey: _, applicationId: __, resourceId: ___, createdAt, updatedAt, _id, ...sessionData } = sessionDocument;
return sessionData;
}
catch (error) {
this.logger.error(`Error retrieving session ${this.getApplicationId()}:${resourceId}:`, error);
throw error;
}
}
/**
* Delete a session from MongoDB
* @param resourceId - Unique identifier: it can be a companyId or a locationId
*/
async deleteSession(resourceId) {
try {
const collection = await this.getCollection(this.collectionName);
const uniqueKey = this.generateUniqueKey(resourceId);
const result = await collection.deleteOne({ uniqueKey });
if (result.deletedCount > 0) {
this.logger.debug(`Session deleted: ${uniqueKey}`);
}
else {
this.logger.debug(`Session not found for deletion: ${uniqueKey}`);
}
}
catch (error) {
this.logger.error(`Error deleting session ${this.getApplicationId()}:${resourceId}:`, error);
throw error;
}
}
/**
* Get only the access token for a resource
* @param resourceId - Unique identifier for the resource (companyId or locationId)
* @returns Access token or null if not found
*/
async getAccessToken(resourceId) {
try {
const collection = await this.getCollection(this.collectionName);
const uniqueKey = this.generateUniqueKey(resourceId);
const sessionDocument = await collection.findOne({ uniqueKey }, { projection: { access_token: 1 } });
return sessionDocument?.access_token || null;
}
catch (error) {
this.logger.error(`Error retrieving access token ${this.getApplicationId()}:${resourceId}:`, error);
throw error;
}
}
/**
* Get only the refresh token for a resource
* @param resourceId - Unique identifier for the resource (companyId or locationId)
* @returns Refresh token or null if not found
*/
async getRefreshToken(resourceId) {
try {
const collection = await this.getCollection(this.collectionName);
const uniqueKey = this.generateUniqueKey(resourceId);
const sessionDocument = await collection.findOne({ uniqueKey }, { projection: { refresh_token: 1 } });
return sessionDocument?.refresh_token || null;
}
catch (error) {
this.logger.error(`Error retrieving refresh token ${this.getApplicationId()}:${resourceId}:`, error);
throw error;
}
}
/**
* Get all sessions for this application
* @returns Array of session data for the application
*/
async getSessionsByApplication() {
try {
const collection = await this.getCollection(this.collectionName);
const applicationId = this.getApplicationId();
const sessions = await collection.find({ applicationId }).toArray();
this.logger.debug(`Found ${sessions.length} sessions for application: ${applicationId}`);
// Return session data without MongoDB metadata
return sessions.map(doc => {
const { uniqueKey: _, applicationId: __, resourceId: ___, createdAt, updatedAt, _id, expire_at, ...sessionData } = doc;
return sessionData;
});
}
catch (error) {
this.logger.error(`Error retrieving sessions for application ${this.getApplicationId()}:`, error);
throw error;
}
}
/**
* Get the underlying MongoDB database instance
* @returns MongoDB Db instance
*/
getDb() {
return this.db;
}
/**
* Get the underlying MongoDB client instance
* @returns MongoDB client instance
*/
getClient() {
return this.client;
}
/**
* Check if the storage is connected
* @returns Connection status
*/
isConnectionActive() {
return this.isConnected;
}
}
exports.MongoDBSessionStorage = MongoDBSessionStorage;
//# sourceMappingURL=mongodb-session-storage.js.map