diff --git a/src/clients/IOClients.ts b/src/clients/IOClients.ts index a7f5f320d..3d4c81e01 100644 --- a/src/clients/IOClients.ts +++ b/src/clients/IOClients.ts @@ -5,7 +5,7 @@ import { CatalogGraphQL } from './apps/catalogGraphQL/index' import { ID, MasterData, PaymentProvider } from './external' import { Apps, Assets, BillingMetrics, Events, Registry, Router, VBase, Workspaces } from './infra' import { IOClient, IOClientConstructor } from './IOClient' -import { LicenseManager, Segment, Session, TenantClient } from './janus' +import { LicenseManager, Segment, Session, TenantClient, Catalog } from './janus' export type ClientsImplementation = new ( clientOptions: Record, @@ -93,6 +93,10 @@ export class IOClients { return this.getOrSet('catalogGraphQL', CatalogGraphQL) } + public get catalog() { + return this.getOrSet('catalog', Catalog) + } + public get paymentProvider() { return this.getOrSet('paymentProvider', PaymentProvider) } diff --git a/src/clients/janus/Catalog/index.ts b/src/clients/janus/Catalog/index.ts new file mode 100644 index 000000000..3f21f3801 --- /dev/null +++ b/src/clients/janus/Catalog/index.ts @@ -0,0 +1,24 @@ +import { inflightUrlWithQuery, RequestConfig } from '../../../HttpClient' +import { JanusClient } from '../JanusClient' +import { SalesChannel } from './types' + +const BASE_URL = '/api/catalog_system' + +const routes = { + salesChannel: (salesChannelId: number) => `${BASE_URL}/pub/saleschannel/${salesChannelId}`, +} + +export class Catalog extends JanusClient { + public getSalesChannel(id: number, config?: RequestConfig) { + const metric = 'catalog-saleschannel' + return this.http.get(routes.salesChannel(id), { + inflightKey: inflightUrlWithQuery, + metric, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } +} diff --git a/src/clients/janus/Catalog/types.ts b/src/clients/janus/Catalog/types.ts new file mode 100644 index 000000000..22fe9b91f --- /dev/null +++ b/src/clients/janus/Catalog/types.ts @@ -0,0 +1,5 @@ +export interface SalesChannel { + Id: number + CultureInfo: string + CurrencyCode: string +} diff --git a/src/clients/janus/LicenseManager.ts b/src/clients/janus/LicenseManager.ts deleted file mode 100644 index 2c90e9c42..000000000 --- a/src/clients/janus/LicenseManager.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { stringify } from 'qs' - -import { RequestConfig, RequestTracingConfig } from '../../HttpClient' -import { JanusClient } from './JanusClient' - -const TWO_MINUTES_S = 2 * 60 - -const BASE_URL = '/api/license-manager' - -const routes = { - accountData: `${BASE_URL}/account`, - resourceAccess: `${BASE_URL}/resources`, - topbarData: `${BASE_URL}/site/pvt/newtopbar`, -} - -const inflightKey = ({baseURL, url, params}: RequestConfig) => { - return baseURL! + url! + stringify(params, {arrayFormat: 'repeat', addQueryPrefix: true}) -} - -export class LicenseManager extends JanusClient { - public getAccountData (VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig) { - const metric = 'lm-account-data' - return this.http.get(routes.accountData, { - forceMaxAge: TWO_MINUTES_S, - headers: { - VtexIdclientAutCookie, - }, - inflightKey, - metric, - tracing: { - requestSpanNameSuffix: metric, - ...tracingConfig?.tracing, - }, - }) - } - - public getTopbarData (VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig) { - const metric = 'lm-topbar-data' - return this.http.get(routes.topbarData, { - headers: { - VtexIdclientAutCookie, - }, - metric, - tracing: { - requestSpanNameSuffix: metric, - ...tracingConfig?.tracing, - }, - }) - } - - public canAccessResource (VtexIdclientAutCookie: string, resourceKey: string, tracingConfig?: RequestTracingConfig) { - const metric = 'lm-resource-access' - return this.http.get(`${routes.resourceAccess}/${resourceKey}/access`, { - headers: { - VtexIdclientAutCookie, - }, - metric, - tracing: { - requestSpanNameSuffix: metric, - ...tracingConfig?.tracing, - }, - }).then(() => true, () => false) - } -} diff --git a/src/clients/janus/LicenseManager/assertBindingInput.ts b/src/clients/janus/LicenseManager/assertBindingInput.ts new file mode 100644 index 000000000..b0dba6d21 --- /dev/null +++ b/src/clients/janus/LicenseManager/assertBindingInput.ts @@ -0,0 +1,25 @@ +import { OptionsCreateBinding } from './types' + +const assertBindingInput = ({ addrs, canonicalAddr, supportedLocales, defaultLocale }: OptionsCreateBinding) => { + if (addrs.length === 0) { + throw new Error('A binding must have at least one address') + } + + const canonicalAddrExists = addrs.some((addr) => canonicalAddr.host === addr.host && canonicalAddr.path === addr.path) + + if (!canonicalAddrExists) { + throw new Error('The canonical address must exist within the address list') + } + + if (supportedLocales.length === 0) { + throw new Error('A binding must have at least one locale') + } + + const defaultLocaleExists = supportedLocales.some((locale) => defaultLocale === locale) + + if (!defaultLocaleExists) { + throw new Error('The default locale must exist within the supported locales') + } +} + +export default assertBindingInput diff --git a/src/clients/janus/LicenseManager/index.ts b/src/clients/janus/LicenseManager/index.ts new file mode 100644 index 000000000..578164246 --- /dev/null +++ b/src/clients/janus/LicenseManager/index.ts @@ -0,0 +1,213 @@ +import { RequestTracingConfig, RequestConfig, inflightUrlWithQuery } from '../../../HttpClient' +import { JanusClient } from '../JanusClient' +import assertBindingInput from './assertBindingInput' +import { + OptionsListBindings, + APIBindingRes, + OptionsGetBinding, + OptionsCreateBinding, + APIBindingCreate, + Addr, + APICreateBindingRes, + OptionsDeleteBinding, + OptionsUpdateBinding, + APIBindingUpdate, +} from './types' + +const TWO_MINUTES_S = 2 * 60 + +const BASE_URL = '/api/license-manager' + +const routes = { + accountData: () => `${BASE_URL}/account`, + resourceAccess: (resourceKey: string) => `${BASE_URL}/resources/${encodeURIComponent(resourceKey)}/access`, + topbarData: () => `${BASE_URL}/site/pvt/newtopbar`, + listBindings: (tenant: string) => `${BASE_URL}/binding/site/${encodeURIComponent(tenant)}`, + getBinding: (bindingId: string) => `${BASE_URL}/binding/${encodeURIComponent(bindingId)}`, + createBinding: () => `${BASE_URL}/binding`, + deleteBinding: (bindingId: string) => `${BASE_URL}/binding/${encodeURIComponent(bindingId)}`, + updateBinding: (bindingId: string) => `${BASE_URL}/binding/${encodeURIComponent(bindingId)}`, +} + +export class LicenseManager extends JanusClient { + public getAccountData(VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig) { + const metric = 'lm-account-data' + return this.http.get(routes.accountData(), { + forceMaxAge: TWO_MINUTES_S, + headers: { + VtexIdclientAutCookie, + }, + inflightKey: inflightUrlWithQuery, + metric, + tracing: { + requestSpanNameSuffix: metric, + ...tracingConfig?.tracing, + }, + }) + } + + public getTopbarData(VtexIdclientAutCookie: string, tracingConfig?: RequestTracingConfig) { + const metric = 'lm-topbar-data' + return this.http.get(routes.topbarData(), { + headers: { + VtexIdclientAutCookie, + }, + metric, + tracing: { + requestSpanNameSuffix: metric, + ...tracingConfig?.tracing, + }, + }) + } + + public canAccessResource(VtexIdclientAutCookie: string, resourceKey: string, tracingConfig?: RequestTracingConfig) { + const metric = 'lm-resource-access' + return this.http + .get(routes.resourceAccess(resourceKey), { + headers: { + VtexIdclientAutCookie, + }, + metric, + tracing: { + requestSpanNameSuffix: metric, + ...tracingConfig?.tracing, + }, + }) + .then( + () => true, + () => false + ) + } + + public listBindings = ({ tenant, adminUserAuthToken }: OptionsListBindings, config?: RequestConfig) => { + const metric = 'lm-list-bindings' + return this.http.get(routes.listBindings(tenant), { + inflightKey: inflightUrlWithQuery, + memoizeable: true, + metric, + headers: { + VtexIdclientAutCookie: adminUserAuthToken, + }, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } + + public getBinding = ({ adminUserAuthToken, bindingId }: OptionsGetBinding, config?: RequestConfig) => { + const metric = 'lm-get-binding' + return this.http.get(routes.getBinding(bindingId), { + inflightKey: inflightUrlWithQuery, + memoizeable: true, + metric, + headers: { + VtexIdclientAutCookie: adminUserAuthToken, + }, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } + + public createBinding = (options: OptionsCreateBinding, config?: RequestConfig) => { + assertBindingInput(options) + + const metric = 'lm-create-binding' + const { tenant, adminUserAuthToken, defaultLocale, supportedLocales, salesChannelId, addrs, canonicalAddr } = + options + + const bindingObj: APIBindingCreate = { + SiteName: tenant, + DefaultLocale: defaultLocale, + SupportedLocales: supportedLocales, + DefaultSalesChannelId: salesChannelId, + Addresses: addrs.map((addr: Addr) => ({ + Host: addr.host, + BasePath: addr.path, + IsCanonical: canonicalAddr.host === addr.host && canonicalAddr.path === addr.path, + Localization: { + '': defaultLocale, + }, + })), + } + + return this.http.post(routes.createBinding(), bindingObj, { + inflightKey: inflightUrlWithQuery, + metric, + headers: { + VtexIdclientAutCookie: adminUserAuthToken, + }, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } + + public deleteBinding = ({ adminUserAuthToken, bindingId }: OptionsDeleteBinding, config?: RequestConfig) => { + const metric = 'lm-delete-binding' + + return this.http.delete(routes.deleteBinding(bindingId), { + inflightKey: inflightUrlWithQuery, + metric, + headers: { + VtexIdclientAutCookie: adminUserAuthToken, + }, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } + + public updateBinding = (options: OptionsUpdateBinding, config?: RequestConfig) => { + assertBindingInput(options) + + const metric = 'lm-update-binding' + const { + tenant, + adminUserAuthToken, + bindingId, + defaultLocale, + supportedLocales, + salesChannelId, + addrs, + canonicalAddr, + } = options + + const bindingObj: APIBindingUpdate = { + Id: bindingId, + SiteName: tenant, + DefaultLocale: defaultLocale, + SupportedLocales: supportedLocales, + DefaultSalesChannelId: salesChannelId, + Addresses: addrs.map((addr: Addr) => ({ + Host: addr.host, + BasePath: addr.path, + IsCanonical: canonicalAddr.host === addr.host && canonicalAddr.path === addr.path, + Localization: { + '': defaultLocale, + }, + })), + } + + return this.http.put(routes.updateBinding(bindingId), bindingObj, { + inflightKey: inflightUrlWithQuery, + metric, + headers: { + VtexIdclientAutCookie: adminUserAuthToken, + }, + ...config, + tracing: { + requestSpanNameSuffix: metric, + ...config?.tracing, + }, + }) + } +} diff --git a/src/clients/janus/LicenseManager/types.ts b/src/clients/janus/LicenseManager/types.ts new file mode 100644 index 000000000..9d2e3fbd0 --- /dev/null +++ b/src/clients/janus/LicenseManager/types.ts @@ -0,0 +1,62 @@ +export interface OptionsListBindings { + tenant: string + adminUserAuthToken: string +} + +export interface OptionsGetBinding { + adminUserAuthToken: string + bindingId: string +} + +export interface OptionsDeleteBinding { + adminUserAuthToken: string + bindingId: string +} + +export interface Addr { + host: string + path: string +} + +export interface OptionsCreateBinding { + tenant: string + adminUserAuthToken: string + defaultLocale: string + supportedLocales: string[] + salesChannelId: number | null + addrs: Addr[] + canonicalAddr: Addr +} + +export interface OptionsUpdateBinding extends OptionsCreateBinding { + bindingId: string +} + +export interface APIAddress { + Host: string + IsCanonical: boolean + BasePath: string + Localization: { + [k: string]: string + } +} + +export interface APIBindingCreate { + Addresses: APIAddress[] + SiteName: string + DefaultSalesChannelId: number | null + DefaultLocale: string + SupportedLocales: string[] +} + +export interface APIBindingUpdate extends APIBindingCreate { + Id: string +} + +export interface APIBindingRes extends APIBindingCreate { + Id: string +} + +export interface APICreateBindingRes { + Id: string +} diff --git a/src/clients/janus/index.ts b/src/clients/janus/index.ts index 54081815a..ee8018761 100644 --- a/src/clients/janus/index.ts +++ b/src/clients/janus/index.ts @@ -3,3 +3,4 @@ export * from './LicenseManager' export * from './Segment' export * from './Session' export * from './Tenant' +export * from './Catalog'