UNPKG

@apptus/esales-api

Version:

Library for making requests to Elevate 4 API v3

155 lines (133 loc) 5.18 kB
import { assert, assertString } from './util/mod.ts'; /** Used to determine server settings to use. */ type Touchpoint = 'desktop' | 'mobile'; /** Session is used to handle session information for a specific visitor. */ interface Session { /** * Method for retrieving session information, synchronously * or asynchronously. Returns a `SessionMetadata` object that * contains `customerKey` and `sessionKey`. * * @example * ```ts * declare const session: Session; * * const { customerKey, sessionKey } = await session(); * ``` */ (): SessionMetadata | Promise<SessionMetadata>; } /** Metadata information regarding a visitor, used during requests to the Elevate Storefront API. */ interface SessionMetadata { /** * A key that uniquely identifies the current visitor. Using UUIDs as keys are recommended. * @see https://docs.elevate.voyado.cloud/elevate/4/integration/api/common/query-parameters/#mandatory-parameters */ customerKey: string; /** * A unique key, identifying the session. Using UUIDs as keys are recommended. * @see https://docs.elevate.voyado.cloud/elevate/4/integration/api/common/query-parameters/#mandatory-parameters */ sessionKey: string; } /** * Configuration required during initialization for the Elevate Storefront API. * * @example * ```ts * const config: Config = { ... }; * const api = elevate(config); * ``` */ interface Config { /** * The ID for the Elevate cluster for all subsequent API requests. * Production/Test/Development clusters each have their own unique ID. * The value for `clusterId` can be found in credentials tab in * the Voyado Elevate app, * * The value should be: * - An identifier in a format similar to `'w00000000'` * - A URL with the origin to the Elevate cluster, e.g. * `'https://w00000000.api.esales.apptus.cloud/'` * * @example * ```ts * const api = elevate({ clusterId: 'w00000000' }); * ``` */ clusterId: string; /** Required for loading correct products and behavior data. */ market: string; /** Required for loading localized product and facet data. */ locale: string; /** Used to determine various server settings. */ touchpoint: Touchpoint; /** Configures how session metadata (customerKey & sessionKey) is retrieved before requests to the API */ session: Session; } /** * Subset of Config for interacting with the Notifications API. * @see Config */ type NotificationConfig = Pick<Config, 'clusterId' | 'market' | 'session'>; /** * Created from a validated `Config`. Used internally. * @internal */ interface BaseOptions extends Omit<NotificationConfig, 'clusterId'> { clusterUrl: string; } /** * Created from a validated `Config`. Used internally. * @internal */ interface FullOptions extends Omit<Config, 'clusterId'> { clusterUrl: string; } function validateBaseConfig(config: unknown): asserts config is NotificationConfig { assert(typeof config === 'object' && config !== null, 'API config must be an "object"'); const c: Partial<NotificationConfig> = config; assertString(c.clusterId, 'Property "clusterId" must be a non-empty string'); assertString(c.market, 'Property "market" must be a non-empty string'); assert(typeof c.session === 'function', 'Property "session" must be a method.'); } /** * Validates that user supplied config is in a correct format. `unknown` is used as parameter * value to indicate that we do not yet trust the user input. * * @param config raw configuration for creating the API library to be validated */ export function validateConfig(config: unknown): asserts config is Config { validateBaseConfig(config); const c: Partial<Config> = config; const touchpoints: Touchpoint[] = ['desktop', 'mobile']; assertString(c.locale, 'Property "locale" must be a string and valid locale, e.g. "en-US".'); assert(touchpoints.includes(c.touchpoint!), `Property "touchpoint" must be one of: ${touchpoints.join(', ')}`); } function resolveClusterUrl<T extends NotificationConfig>(config: T) { const { clusterId, ...rest } = config; const clusterUrl = (() => { /** Ensures consistent casing and trailing slash of URL's */ const normalizeUrl = (url: string) => new URL(url).href; try { // Will throw for invalid URL, and normalize trailing slash return normalizeUrl(clusterId); } catch { /* empty */ } return normalizeUrl(`https://${clusterId}.api.esales.apptus.cloud/`); })(); return { ...rest, clusterUrl }; } /** Prepares user-supplied configuration for internal use. */ export function resolveConfig(config: Config): FullOptions { // TODO(csv): Allow this code to be removed in a production build? validateConfig(config); return resolveClusterUrl(config); } /** Prepares user-supplied configuration for internal use. */ export function resolveNotificationConfig(config: NotificationConfig): BaseOptions { // TODO(csv): Allow this code to be removed in a production build? validateBaseConfig(config); return resolveClusterUrl(config); } export type { Config, NotificationConfig, BaseOptions, FullOptions, Session, SessionMetadata, Touchpoint };