@gnosticdev/highlevel-sdk
Version:
SDK for the HighLevel API
593 lines (592 loc) • 18.2 kB
JavaScript
import { t as HighLevelSDKError } from "./errors-DX_S3nKC.js";
import createClient from "openapi-fetch";
//#region src/v2/client/client-type-helpers.ts
/**
* Creates a client with or without authentication based on the presence of auth headers.
* @param authHeaders - the authentication headers to use for the client.
* @param options - the options to use for the client.
* @returns a client with or without authentication based on the presence of auth headers.
* @example
* ```ts
* const client = createClientMaybeAuth({Authorization: 'Bearer 1234567890', Version: '2021-07-28'}, {baseUrl: 'https://services.leadconnectorhq.com'})
* ```
*/
function createClientMaybeAuth(authHeaders, options = {}) {
if (authHeaders) {
options.headers = {
...options.headers,
...authHeaders
};
return createClientWithAuth(authHeaders, options);
}
return createClient({ ...options });
}
/**
* Creates an `openapi-fetch` client, and adds the Authentication headers to each request.
*
* For use with clients that have the Authentication headers pre-configured.
*
* @param options - the client options with required authentication headers.
* @returns An `openapi-fetch` client with the Authentication headers added to each request.
*/
function createClientWithAuth(authHeaders, options = {}) {
if (!authHeaders.Authorization.startsWith("Bearer ")) throw new HighLevelSDKError("INVALID_AUTH_HEADER");
const merged = {
...options.headers,
...authHeaders
};
return createClient({
...options,
headers: merged
});
}
//#endregion
//#region src/v2/client/base.ts
/**
* Base implementation for HighLevel API client.
* Provides endpoint clients for each API domain.
*/
var BaseHighLevelClient = class {
/**
* Exposed config object for convenience.
*/
_clientConfig;
oauth;
agencies;
associations;
blogs;
businesses;
calendars;
campaigns;
companies;
contacts;
conversations;
courses;
customFields;
customMenus;
emailIsv;
emails;
forms;
funnels;
invoices;
links;
locations;
marketplace;
medias;
objects;
opportunities;
payments;
phoneSystem;
products;
proposals;
saasApi;
snapshots;
socialMediaPosting;
store;
surveys;
users;
voiceAi;
workflows;
constructor(clientConfig, authHeaders) {
this._clientConfig = {
...clientConfig,
baseUrl: clientConfig?.baseUrl ?? "https://services.leadconnectorhq.com"
};
if (authHeaders) this._clientConfig.headers = {
...this._clientConfig.headers,
...authHeaders
};
this.oauth = createClient(this._clientConfig);
/**
* agencies client implementation.
*/
this.agencies = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* associations client implementation.
*/
this.associations = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* blogs client implementation.
*/
this.blogs = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* businesses client implementation.
*/
this.businesses = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* calendars client implementation.
*/
this.calendars = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* campaigns client implementation.
*/
this.campaigns = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* companies client implementation.
*/
this.companies = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* contacts client implementation.
*/
this.contacts = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* conversations client implementation.
*/
this.conversations = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* courses client implementation.
*/
this.courses = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* customFields client implementation.
*/
this.customFields = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* customMenus client implementation.
*/
this.customMenus = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* emailIsv client implementation.
*/
this.emailIsv = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* emails client implementation.
*/
this.emails = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* forms client implementation.
*/
this.forms = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* funnels client implementation.
*/
this.funnels = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* invoices client implementation.
*/
this.invoices = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* links client implementation.
*/
this.links = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* locations client implementation.
*/
this.locations = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* marketplace client implementation.
*/
this.marketplace = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* medias client implementation.
*/
this.medias = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* objects client implementation.
*/
this.objects = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* opportunities client implementation.
*/
this.opportunities = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* payments client implementation.
*/
this.payments = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* phoneSystem client implementation.
*/
this.phoneSystem = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* products client implementation.
*/
this.products = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* proposals client implementation.
*/
this.proposals = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* saasApi client implementation.
*/
this.saasApi = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* snapshots client implementation.
*/
this.snapshots = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* socialMediaPosting client implementation.
*/
this.socialMediaPosting = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* store client implementation.
*/
this.store = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* surveys client implementation.
*/
this.surveys = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* users client implementation.
*/
this.users = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* voiceAi client implementation.
*/
this.voiceAi = createClientMaybeAuth(authHeaders, this._clientConfig);
/**
* workflows client implementation.
*/
this.workflows = createClientMaybeAuth(authHeaders, this._clientConfig);
}
};
/**
* Default client for HighLevel API endpoints.
*
* @remarks use the `createHighLevelClient` function to create an instance of this client without handling generic types.
*
* @see {@link createHighLevelClient}
*
* @example
* ```ts
* const client = new HighLevelClient({}, {Authorization: 'Bearer 1234567890', Version: '2021-07-28'})
* const locations = client.locations.GET('/locations/search', {query: {name: 'John Doe'}})
* ```
*/
var HighLevelClient = class extends BaseHighLevelClient {
oauth;
constructor(clientConfig) {
super(clientConfig);
this.oauth = createClient(this._clientConfig);
}
};
new HighLevelClient({}).businesses.GET("/businesses/{businessId}", { params: {
header: { Version: "2021-07-28" },
path: { businessId: "1234567890" }
} });
//#endregion
//#region src/v2/oauth/impl.ts
/**
* This client has built in methods for generating, refreshing, and storing tokens.
* You can extend this class to implement your own methods.
* @see https://highlevel.stoplight.io/docs/integrations/
*/
var OauthClientImpl = class {
_accessToken;
_refreshToken;
/**
* Type of user that is accessing the API.
*
* Only used for generating tokens, similar to `accessType` but uses `Location` (Sub-Account) or `Company` (Agency)
*/
userType;
/**
* Underlying oauth client created by `createClient` method from `openapi-fetch`
*
* Most likely do not need to use this unless special use case.
*/
_oauthClient;
expiresAt;
scopes;
config;
baseUrl;
baseOauthUrl;
tokenData;
storeTokenFn;
/**
* creates a new oauth client for use with the HighLevel API
* @constructor
* @param config - configuration for your app
*/
constructor(config) {
this.config = config;
this.baseUrl = config.baseUrl ?? "https://services.leadconnectorhq.com";
this.baseOauthUrl = config.baseAuthUrl ?? "https://marketplace.leadconnectorhq.com/oauth/chooselocation";
this.scopes = config.scopes.join(" ");
if (this.scopes.length === 0) console.warn("No scopes provided! Your app will not be able to access any data.");
this.userType = config.accessType === "Sub-Account" ? "Location" : "Company";
this.storeTokenFn = config.storageFunction ? async (tokenData) => {
await config.storageFunction(tokenData);
return tokenData;
} : async (tokenData) => {
await defaultMemoryStorageFunction(tokenData);
return tokenData;
};
this._oauthClient = createClient({ baseUrl: this.baseUrl });
}
/**
* Update the stored token data with the provided token data.
* @param updatedTokenData - The token data to update.
*/
updateTokenData(updatedTokenData) {
this.tokenData = {
...this.tokenData,
...updatedTokenData
};
this.storeTokenFn(this.tokenData);
}
/**
* generates the authorization url for your app using the baseAuthUrl, clientId, redirectUri, and scopes.
* @see https://highlevel.stoplight.io/docs/integrations/a04191c0fabf9-authorization
* @example
* ```ts
https://marketplace.leadconnectorhq.com/oauth/chooselocation?response_type=code&redirect_uri=https://myapp.com/oauth/callback/gohighlevel&client_id=CLIENT_ID&scope=conversations/message.readonly conversations/message.write
* ```
*/
getAuthorizationUrl() {
const url = new URL(this.baseOauthUrl);
const requiredParams = {
client_id: this.config.clientId,
redirect_uri: this.config.redirectUri,
scope: this.scopes,
response_type: "code"
};
url.search = new URLSearchParams(requiredParams).toString();
return url.toString();
}
/**
* Stores the token data using the `storageFunction` including the accessToken, refreshToken, locationID, and adds the expiresAt time (in ms).
* **NOTE**: You can add a `storageFunction` to the config to store the token data in your database or cache.
* @param tokenData - the token response from the server
* @returns the token data with the `expiresAt` time added
*/
async storeTokenData(tokenData) {
this._accessToken = tokenData.access_token;
this._refreshToken = tokenData.refresh_token;
const expiresAt = Date.now() + tokenData.expires_in * 1e3;
this.tokenData = {
...tokenData,
expiresAt
};
return this.storeTokenFn(this.tokenData);
}
/**
* Check if the token is expired or if we need to refresh it
* @returns true if the token is expired or if we need to refresh it
*/
isTokenExpired() {
if (!this.tokenData?.expiresAt || !this._refreshToken) return true;
return this.tokenData.expiresAt <= Date.now() + 300 * 1e3;
}
/**
* Returns a valid access token by either refreshing the token or exchanging the auth code for a new token.
*
* Also stores the token via the `storeTokenData` if provided.
* @param authCode - The authorization code received from the OAuth provider.
* @throws {Error} - If no token response is received or if no auth code or refresh token is provided.
* @returns The access token.
*/
async getAccessToken(authCode) {
if (this._accessToken && !this.isTokenExpired()) return this._accessToken;
if (authCode) {
const tokenResponse = await this.exchangeToken(authCode);
if (!tokenResponse) throw new Error("Error in token exchange");
await this.storeTokenData(tokenResponse);
return tokenResponse.access_token;
}
if (!this._refreshToken) return null;
const tokenResponse = await this.refreshAccessToken();
await this.storeTokenData(tokenResponse);
return tokenResponse.access_token;
}
/**
* Generates a new access token using the provided authorization code. \
* **NOTE**: This method does not save the token data to the client.
* To store the token:
* - `storeTokenData` - saves the token data.
* - `getAccessToken` - fetches and stores the token data.
* @param authCode - Parameters required to generate a new token.
* @returns The token response from the server.
*/
async exchangeToken(authCode) {
const tokenParams = {
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
grant_type: "authorization_code",
user_type: this.userType,
code: authCode
};
const { data, error } = await this.#fetchAccessToken(tokenParams);
if (error) {
console.error("Error: exchanging token", error);
throw new Error(error.message?.toString() ?? String(error));
}
return data;
}
/**
* Refreshes the current access token.
* **NOTE**: This method does not save the token data to the client.
* To store the token:
* - `storeTokenData` - saves the token data.
* - `getAccessToken` - fetches and stores the token data.
* @returns The token response from the server.
*/
async refreshAccessToken() {
if (!this._refreshToken) throw new Error("No refresh token available.");
const tokenParams = {
client_id: this.config.clientId,
client_secret: this.config.clientSecret,
refresh_token: this._refreshToken,
grant_type: "refresh_token",
user_type: this.userType
};
const { data, error } = await this.#fetchAccessToken(tokenParams);
if (error) {
console.error("Error: refreshing token", error);
throw new Error(error.message?.toString() ?? String(error));
}
return data;
}
/**
* Main method for getting getting a token from HighLevel v2 API.
*
* Sends a `POST` request to the `/oauth/token` endpoint.
*
* @param tokenParams - Auth code params or refresh token params
* @private
*/
async #fetchAccessToken(tokenParams) {
return this._oauthClient.POST("/oauth/token", {
body: tokenParams,
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json"
},
bodySerializer(_body) {
return new URLSearchParams(_body).toString();
}
});
}
/**
* generate a location AccessToken from Agency AccessToken
* @param companyId - your agency id
* @param locationId - The locationId is the locationId of the location you want to get a token for
*/
async generateLocationToken({ companyId, locationId }) {
const { data, error, response } = await this._oauthClient.POST("/oauth/locationToken", {
body: {
companyId,
locationId
},
params: { header: { Version: "2021-07-28" } },
bodySerializer(_body) {
return new URLSearchParams(_body).toString();
},
headers: {
"Content-Type": "application/x-www-form-urlencoded",
Accept: "application/json"
}
});
if (error) {
console.error(await response.text());
throw new Error(error.message?.toString() ?? String(error));
}
return data;
}
/**
* Get all locations under your agency that have installed your app
* @param query - search for installed locations using any of these properties
* @param appId - the appId of your app
* @param companyId - the companyId of your agency
*/
async getInstalledLocations(query) {
const { data, error } = await this._oauthClient.GET("/oauth/installedLocations", { params: {
query: {
...query,
appId: query.appId,
companyId: query.companyId
},
header: { Version: "2021-07-28" }
} });
if (error) {
console.error("Error: installed locations", error);
throw new Error(error.message?.toString());
}
return data;
}
};
/**
* In-memory storage for token data.
* This is a simple Map-based storage that persists token data in memory.
* Useful for testing and development, but not recommended for production.
*/
var MemoryTokenStore = class {
store = /* @__PURE__ */ new Map();
/**
* Store token data in memory.
* @param tokenData - The token data to store
* @returns The stored token data
*/
async set(tokenData) {
const key = tokenData.locationId ?? tokenData.companyId ?? "default";
this.store.set(key, tokenData);
return tokenData;
}
/**
* Retrieve token data from memory.
* @param key - The key to retrieve (locationId, companyId, or 'default')
* @returns The stored token data or undefined
*/
get(key) {
return this.store.get(key);
}
/**
* Clear all stored token data.
*/
clear() {
this.store.clear();
}
/**
* Get all stored token data.
* @returns Array of all stored token data
*/
getAll() {
return Array.from(this.store.values());
}
};
/**
* Default memory store instance.
* This is used as the default storage when no custom storage function is provided.
*/
const defaultMemoryStore = new MemoryTokenStore();
/**
* Default memory storage function for token data.
* Stores token data in memory using the default memory store.
*
* @param tokenData - The token data to store
* @returns The stored token data
*/
async function defaultMemoryStorageFunction(tokenData) {
return defaultMemoryStore.set(tokenData);
}
/**
* HighLevelClient with built in OAuth methods.
*
* To create an instance, use the `createHighLevelClient` function from the main client.
*
* @see {@link createHighLevelClient}
* @example
* ```ts
* const client = createHighLevelClient({}, 'oauth', {
* clientId: 'your-client-id',
* clientSecret: 'your-client-secret',
* redirectUri: 'http://localhost:3000/callback',
* accessType: 'Sub-Account',
* scopes: ['contacts.readonly']
* })
* ```
* @internal
*/
var HighLevelClientWithOAuth = class extends BaseHighLevelClient {
oauth;
constructor(oauthConfig, clientConfig) {
super(clientConfig);
const baseUrl = clientConfig?.baseUrl ?? oauthConfig.baseUrl ?? "https://services.leadconnectorhq.com";
this.oauth = new OauthClientImpl({
...oauthConfig,
baseUrl,
baseAuthUrl: oauthConfig?.baseAuthUrl ?? "https://marketplace.leadconnectorhq.com/oauth/chooselocation"
});
}
};
//#endregion
export { BaseHighLevelClient as i, OauthClientImpl as n, HighLevelClient as r, HighLevelClientWithOAuth as t };