UNPKG

@gnosticdev/highlevel-sdk

Version:
679 lines (669 loc) 19.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __name = (target, value) => __defProp(target, "name", { value, configurable: true }); var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/v2/index.ts var v2_exports = {}; __export(v2_exports, { createHighLevelClient: () => createHighLevelClient2 }); module.exports = __toCommonJS(v2_exports); // src/lib/errors.ts var HighLevelSDKErrorCodes = { INVALID_AUTH_HEADER: "INVALID_AUTH_HEADER", INVALID_AUTH_TYPE: "INVALID_AUTH_TYPE", NO_HANDLER_REGISTERED: "NO_HANDLER_REGISTERED", INVALID_WEBHOOK_PAYLOAD: "INVALID_WEBHOOK_PAYLOAD", API_KEY_REQUIRED: "API_KEY_REQUIRED" }; var ERROR_MESSAGES = { [HighLevelSDKErrorCodes.INVALID_AUTH_HEADER]: 'Authorization header must start with "Bearer "', [HighLevelSDKErrorCodes.INVALID_AUTH_TYPE]: "Invalid authentication type provided", [HighLevelSDKErrorCodes.NO_HANDLER_REGISTERED]: "No handler registered for webhook event: {event}", [HighLevelSDKErrorCodes.INVALID_WEBHOOK_PAYLOAD]: "Invalid webhook payload", [HighLevelSDKErrorCodes.API_KEY_REQUIRED]: "apiKey is required" }; var HighLevelSDKError = class extends Error { static { __name(this, "HighLevelSDKError"); } constructor(message, options) { const finalMessage = options?.event ? ERROR_MESSAGES[message].replace("{event}", options.event) : ERROR_MESSAGES[message]; super(finalMessage, options); this.name = "HighLevelSDKError"; this.cause = HighLevelSDKErrorCodes[message]; } }; // src/v2/client/default.ts var import_openapi_fetch = __toESM(require("openapi-fetch"), 1); // src/v2/client/types.ts var import_src = __toESM(require("openapi-fetch/src/index.js"), 1); function createClientWithAuth(authHeaders, options) { if (!authHeaders.Authorization.startsWith("Bearer ")) { throw new HighLevelSDKError("INVALID_AUTH_HEADER"); } const config = { ...options, headers: { ...options?.headers, ...authHeaders } }; return (0, import_src.default)({ ...config }); } __name(createClientWithAuth, "createClientWithAuth"); // src/v2/client/default.ts var DEFAULT_V2_BASE_URL = "https://services.leadconnectorhq.com"; function createClientMaybeAuth(authHeaders, options) { if (authHeaders) { return createClientWithAuth( authHeaders, options ); } return (0, import_openapi_fetch.default)(options); } __name(createClientMaybeAuth, "createClientMaybeAuth"); var HighLevelClient = class { constructor(clientConfig, authHeaders) { this.authHeaders = authHeaders; this._clientConfig = clientConfig ? { baseUrl: DEFAULT_V2_BASE_URL, ...clientConfig } : { baseUrl: DEFAULT_V2_BASE_URL }; if (authHeaders) { this._clientConfig.headers = { ...this._clientConfig.headers, ...authHeaders }; } this.oauth = (0, import_openapi_fetch.default)(this._clientConfig); this.businesses = createClientMaybeAuth( authHeaders, this._clientConfig ); this.blogs = createClientMaybeAuth( authHeaders, this._clientConfig ); this.customMenus = createClientMaybeAuth( authHeaders, this._clientConfig ); this.emails = createClientMaybeAuth( authHeaders, this._clientConfig ); this.emailIsv = createClientMaybeAuth( authHeaders, this._clientConfig ); this.calendars = createClientMaybeAuth( authHeaders, this._clientConfig ); this.campaigns = createClientMaybeAuth( authHeaders, this._clientConfig ); this.companies = createClientMaybeAuth( authHeaders, this._clientConfig ); this.courses = createClientMaybeAuth( authHeaders, this._clientConfig ); this.contacts = createClientMaybeAuth( authHeaders, this._clientConfig ); this.conversations = createClientMaybeAuth( authHeaders, this._clientConfig ); this.forms = createClientMaybeAuth( authHeaders, this._clientConfig ); this.funnels = createClientMaybeAuth( authHeaders, this._clientConfig ); this.invoices = createClientMaybeAuth( authHeaders, this._clientConfig ); this.links = createClientMaybeAuth( authHeaders, this._clientConfig ); this.locations = createClientMaybeAuth( authHeaders, this._clientConfig ); this.medias = createClientMaybeAuth( authHeaders, this._clientConfig ); this.opportunities = createClientMaybeAuth( authHeaders, this._clientConfig ); this.locations = createClientMaybeAuth( authHeaders, this._clientConfig ); this.medias = createClientMaybeAuth( authHeaders, this._clientConfig ); this.opportunities = createClientMaybeAuth( authHeaders, this._clientConfig ); this.payments = createClientMaybeAuth( authHeaders, this._clientConfig ); this.products = createClientMaybeAuth( authHeaders, this._clientConfig ); this.saasApi = createClientMaybeAuth( authHeaders, this._clientConfig ); this.snapshots = createClientMaybeAuth( authHeaders, this._clientConfig ); this.socialMediaPosting = createClientMaybeAuth(authHeaders, this._clientConfig); this.surveys = createClientMaybeAuth( authHeaders, this._clientConfig ); this.users = createClientMaybeAuth( authHeaders, this._clientConfig ); this.workflows = createClientMaybeAuth( authHeaders, this._clientConfig ); } static { __name(this, "HighLevelClient"); } /** * oauth client implementation. */ oauth; /** * businesses client implementation. */ businesses; blogs; customMenus; emails; emailIsv; /** * invoices client implementation. */ invoices; /** * opportunities client implementation. */ opportunities; /** * campaigns client implementation. */ campaigns; /** * conversations client implementation. */ conversations; /** * products client implementation. */ products; /** * courses client implementation. */ courses; /** * surveys client implementation. */ surveys; /** * payments client implementation. */ payments; /** * workflows client implementation. */ workflows; /** * snapshots client implementation. */ snapshots; /** * saasApi client implementation. */ saasApi; /** * users client implementation. */ users; /** * funnels client implementation. */ funnels; /** * locations client implementation. */ locations; /** * links client implementation. */ links; /** * companies client implementation. */ companies; /** * contacts client implementation. */ contacts; /** * forms client implementation. */ forms; /** * calendars client implementation. */ calendars; /** * medias client implementation. */ medias; /** * social media posting client implementation. */ socialMediaPosting; /** * client configuration */ _clientConfig; }; // src/v2/client/with-integration.ts var HighLevelIntegrationClient = class extends HighLevelClient { static { __name(this, "HighLevelIntegrationClient"); } /** * The private token for the integration * * @see https://help.leadconnectorhq.com/support/solutions/articles/155000002774-private-integrations-everything-you-need-to-know */ privateToken; /** * The scopes for the integration. * * _NOTE_: in a private integration, we never send off the scopes like we do in Oauth2, but leaving this here for potential future use. * * @example * ```ts * const scopes = new ScopesBuilder().all().build() * ``` */ scopes; constructor(integrationConfig, clientConfig) { const authHeaders = { Authorization: `Bearer ${integrationConfig.privateToken}`, Version: "2021-07-28" }; super(clientConfig, authHeaders); this.privateToken = integrationConfig.privateToken; this.scopes = integrationConfig.scopes ?? []; } }; // src/v2/oauth/impl.ts var import_openapi_fetch2 = __toESM(require("openapi-fetch"), 1); var OauthClientImpl = class { static { __name(this, "OauthClientImpl"); } _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. */ _client; // avoid conflict with the `expiresAt` getter _expiresAt; scopes; config; baseUrl; baseOauthUrl; // avoid conflict with the `tokenData` property 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 ?? DEFAULT_V2_BASE_URL; this.baseOauthUrl = config.baseAuthUrl ?? DEFAULT_BASE_AUTH_URL; this.scopes = Array.isArray(config.scopes) ? config.scopes.join(" ") : config.scopes; if (this.scopes.length === 0) { console.warn( "No scopes provided! Pass the scopes set in your app to the scopes param" ); } this.userType = config.accessType === "Sub-Account" ? "Location" : "Company"; this.storeTokenFn = config.storageFunction ?? (() => { if (!this.tokenData) { throw new Error("No token data to store"); } return Promise.resolve(this.tokenData); }); this._client = (0, import_openapi_fetch2.default)({ baseUrl: this.baseUrl }); } /** * The time (in seconds) when the access token expires. */ get expiresAt() { return this._expiresAt; } /** * 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" }; const searchParams = new URLSearchParams(requiredParams); url.search = searchParams.toString(); return url.toString(); } /** * Stores everything from the Token response 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() + 5 * 60 * 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 tokenResponse2 = await this.exchangeToken(authCode); if (!tokenResponse2) throw new Error("Error in token exchange"); const storedToken2 = await this.storeTokenData(tokenResponse2); return storedToken2.access_token; } if (!this._refreshToken) { return null; } const tokenResponse = await this.refreshAccessToken(); const storedToken = await this.storeTokenData(tokenResponse); return storedToken.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._client.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._client.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._client.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; } }; // src/v2/client/with-oauth.ts var DEFAULT_BASE_AUTH_URL = "https://marketplace.leadconnectorhq.com/oauth/chooselocation"; var HighLevelClientWithOAuth = class extends HighLevelClient { static { __name(this, "HighLevelClientWithOAuth"); } oauth; constructor(oauthConfig, clientConfig) { super(clientConfig); const baseUrl = clientConfig?.baseUrl ?? oauthConfig.baseUrl ?? DEFAULT_V2_BASE_URL; const _oauthConfig = { ...oauthConfig, baseUrl, baseAuthUrl: oauthConfig?.baseAuthUrl ?? DEFAULT_BASE_AUTH_URL, scopes: oauthConfig.scopes ?? [] }; this.oauth = new OauthClientImpl(_oauthConfig); } }; // src/v2/index.ts function createHighLevelClient2(clientConfig, authType, authConfig) { if (!authType || !authConfig) { return new HighLevelClient( clientConfig ); } if (authType === "oauth" && "clientId" in authConfig) { return new HighLevelClientWithOAuth( authConfig, clientConfig ); } if (authType === "integration" && "privateToken" in authConfig) { return new HighLevelIntegrationClient( authConfig, clientConfig ); } throw new HighLevelSDKError("INVALID_AUTH_TYPE"); } __name(createHighLevelClient2, "createHighLevelClient"); // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createHighLevelClient });