UNPKG

@gnosticdev/highlevel-sdk

Version:
593 lines (592 loc) 18.2 kB
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 };