Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@volvo-cars/content-delivery-client

Package Overview
Dependencies
Maintainers
8
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@volvo-cars/content-delivery-client - npm Package Compare versions

Comparing version 0.5.0 to 0.6.0

dist/getLocalDataPaths-079a8297.js

17

dist/ContentDeliveryClient.d.ts

@@ -5,2 +5,3 @@ /// <reference types="node" />

import type { ContentType, ListEntriesResponseData } from './entries/types';
import { SitemapListResponseData } from './sitemap/types';
export type ContentEnvironment = 'live' | 'authoringPreview' | 'master';

@@ -46,3 +47,6 @@ export type ContentDeliveryDataSource = 'volvo-test' | 'volvo-qa' | 'volvo-prod' | string;

*/
apiKey: string;
apiKey: string | {
qa: string;
prod: string;
};
/**

@@ -60,2 +64,3 @@ * Path where dictionaries and other nececcary files can be written relative to your project root.

listEntries?: number;
sitemap?: number;
};

@@ -69,2 +74,6 @@ /**

} & Record<string, any>;
/**
* Allow the consumer to catch and log the error themselves
*/
disableLogging?: boolean;
};

@@ -112,2 +121,6 @@ export type CreateClientOptions = ClientConfig & {

dataSource?: ContentDeliveryDataSource;
/**
* ContentType Id to fetch entries from Contentstack datasource
*/
contentTypeId?: string;
};

@@ -120,2 +133,3 @@ export type GetAllDictionariesOptions = GetOptions & {

};
export type GetSitemapListOptions = Omit<GetOptions, 'locale' | 'environment' | 'market'>;
export interface ContentDeliveryClient {

@@ -152,3 +166,4 @@ /**

listEntries<T extends ContentType>(contentType: T, options: GetOptions): Promise<ListEntriesResponseData<T>>;
getSitemapList(options?: GetSitemapListOptions): Promise<SitemapListResponseData>;
}
export declare function createClient({ forceLocalData, fallbackToLocalData, ...config }: CreateClientOptions): ContentDeliveryClient;

@@ -10,3 +10,5 @@ export type ContentType = 'ContentType' | 'EditorialComponent' | 'PageType';

sysId?: string;
createdAt?: string;
updatedAt?: string;
};
} & Record<string, any>)[];

3

dist/errors.d.ts

@@ -26,3 +26,3 @@ import type { ContentEnvironment } from './ContentDeliveryClient';

applicationId: string;
locale: string;
locale?: string;
dataSource?: string;

@@ -32,2 +32,3 @@ environment?: ContentEnvironment;

operationId?: string;
status: number;
constructor(message: string, { applicationId, dataSource, locale, environment, operationId, market, }: RequestDetails, error?: Error[] | (Error & {

@@ -34,0 +35,0 @@ errors?: Error[];

import flatten from 'flat';
import { getMarketSite, getMarketSiteByLocale } from '@volvo-cars/market-sites';
const canonicalDictionaryNameRegex = /^[A-Za-z0-9]+\.[A-Za-z0-9]+$/;
const canonicalDictionaryNameRegex = /^[A-Za-z0-9]+\.[A-Za-z0-9_]+$/;
function validateCanonicalDictionaryName(canonicalDictionaryName) {

@@ -50,3 +50,3 @@ if (!canonicalDictionaryNameRegex.test(canonicalDictionaryName)) {

getLocalDictionary
} = await import('./getLocalDictionaries-687d3c8d.js');
} = await import('./getLocalDictionaries-d7bfaf0f.js');
return this.flattenDictionaries({

@@ -60,3 +60,3 @@ [canonicalDictionaryName]: await getLocalDictionary(canonicalDictionaryName, (_this$config$path = this.config.path) != null ? _this$config$path : '')

getLocalDictionaries
} = await import('./getLocalDictionaries-687d3c8d.js');
} = await import('./getLocalDictionaries-d7bfaf0f.js');
canonicalDictionaryNames.forEach(validateCanonicalDictionaryName);

@@ -69,3 +69,3 @@ return this.flattenDictionaries(Object.fromEntries(await getLocalDictionaries(canonicalDictionaryNames, (_this$config$path2 = this.config.path) != null ? _this$config$path2 : '')));

getLocalDictionaries
} = await import('./getLocalDictionaries-687d3c8d.js');
} = await import('./getLocalDictionaries-d7bfaf0f.js');
return this.flattenDictionaries(Object.fromEntries(await getLocalDictionaries([], (_this$config$path3 = this.config.path) != null ? _this$config$path3 : '')));

@@ -77,3 +77,3 @@ }

getLocalEntry
} = await import('./getLocalEntry-98f1ae6f.js');
} = await import('./getLocalEntry-bdb7cfb2.js');
return getLocalEntry(_canonicalName, (_this$config$path4 = this.config.path) != null ? _this$config$path4 : '');

@@ -84,2 +84,5 @@ }

}
async getSitemapList(_options) {
return [];
}
async flattenDictionaries(target) {

@@ -132,3 +135,4 @@ const {

}, error) {
super(`${message} in ${locale} @ ${dataSource} '${environment || 'live'}'`);
var _this$errors$;
super(`${message}${locale ? ` in ${locale}` : ''} @ ${dataSource} '${environment || 'live'}'`);
this.name = 'ContentDeliveryError';

@@ -142,2 +146,3 @@ this.errors = [];

this.operationId = void 0;
this.status = 500;
this.applicationId = applicationId;

@@ -160,2 +165,3 @@ this.dataSource = dataSource;

}
this.status = ((_this$errors$ = this.errors[0]) == null ? void 0 : _this$errors$.status) || 500;
}

@@ -222,24 +228,42 @@ }

const BASE_API_URL = 'https://gw.consumer.api.volvocars.com/content-delivery/v1/applications';
async function sendRequest({
applicationId,
dataSource,
path,
market = false,
locale,
accept,
environment,
operationId,
contentType,
timeout,
config,
limit
}, {
const BASE_API_URL_PROD = 'https://gw.consumer.api.volvocars.com/content-delivery/v1/applications';
const BASE_API_URL_QA = 'https://gw.qa.consumer.api.volvocars.com/content-delivery/v1/applications';
const sendRequest = async (options, {
retry = true
} = {}) {
} = {}) => {
var _fetchOptions;
const {
applicationId,
dataSource,
path,
market = false,
locale,
accept,
acceptHeaderType = 'contentdelivery',
environment,
operationId,
contentType,
contentTypeId,
timeout,
config,
limit,
baseUrl
} = options;
const timer = new Timeout(timeout);
const url = new URL(BASE_API_URL);
const isProdDataSource = !(dataSource != null && dataSource.endsWith('-qa') || dataSource != null && dataSource.endsWith('-test'));
const optInEnvSpecificUrl = typeof config.apiKey === 'object';
const defaultApiUrl = optInEnvSpecificUrl ? isProdDataSource ? BASE_API_URL_PROD : BASE_API_URL_QA : BASE_API_URL_PROD;
const url = new URL(baseUrl || defaultApiUrl);
const apiKeyEnv = isProdDataSource ? 'prod' : 'qa';
const apiKey = typeof config.apiKey === 'string' ? config.apiKey : config.apiKey[apiKeyEnv];
if (url.origin.startsWith('https://gw.consumer.api.volvocars.com') && !isProdDataSource && !(dataSource != null && dataSource.startsWith('dotcom-sitecore-'))) {
console.log(`[Warning: ContentDeliveryClient] QA and TEST dataSources will soon only work with
QA consumer portal(https://gw.qa.consumer.api.volvocars.com), make sure to change "apiKey"
config option from a string to an object with different values for each environment:
detected [${dataSource}] with production consumer portal URL`);
}
url.pathname += `/${applicationId}${path}`;
url.searchParams.set('Locale', locale);
if (locale) {
url.searchParams.set('Locale', locale);
}
if (dataSource) {

@@ -253,3 +277,3 @@ url.searchParams.set('DataSource', dataSource);

url.searchParams.set('environment', environment);
if (market) {
if (market && locale) {
const {

@@ -266,2 +290,10 @@ siteSlug

}
if (contentTypeId) {
var _dataSource$toLowerCa;
if (dataSource != null && (_dataSource$toLowerCa = dataSource.toLowerCase()) != null && _dataSource$toLowerCa.startsWith('contentstack')) {
url.searchParams.set('contentTypeId', contentTypeId);
} else {
throw new Error(`The 'contentTypeId' option is only supported for Contentstack datasource`);
}
}
if (limit) {

@@ -277,18 +309,17 @@ url.searchParams.set('limit', limit.toString());

}
const response = await Promise.race([timer.run(), fetch(url.href, {
headers: {
Accept: `application/vnd.volvocars.api.contentdelivery.${accept}+json`,
'VCC-Api-Key': config.apiKey,
...(operationId && {
'VCC-Api-OperationId': operationId
})
},
...fetchOptions
}).then(response => {
let response;
try {
response = await Promise.race([timer.run(), fetch(url.href, {
headers: {
Accept: `application/vnd.volvocars.api.${acceptHeaderType}.${accept}+json`,
'VCC-Api-Key': apiKey,
...(operationId && {
'VCC-Api-OperationId': operationId
})
},
...fetchOptions
})]);
} finally {
timer.clear();
return response;
}, error => {
timer.clear();
throw error;
})]);
}
if (response.status === 429 && retry && !timeout) {

@@ -300,15 +331,3 @@ const retryAfter = Number(response.headers.get('Retry-After') || 10) + 5;

await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return sendRequest({
applicationId,
dataSource,
path,
market,
locale,
accept,
environment,
operationId,
contentType,
timeout,
config
}, {
return sendRequest(options, {
retry: false

@@ -323,3 +342,3 @@ });

throw new RequestError('error' in result ? result.error.message : result.message, response.status, response.url);
}
};
let keepAliveAgent;

@@ -463,3 +482,3 @@ async function getKeepAliveAgent() {

// Throw a NotFoundError to allow catching and falling back to local data
throw new DictionaryNotFoundError('Empty dictionaries response', requestDetails);
throw new DictionaryNotFoundError('Empty dictionaries response', requestDetails, new RequestError('Empty dictionaries response', 404, '/dictionaries'));
}

@@ -486,3 +505,3 @@ return results;

var _obj$contentType;
if ((obj == null ? void 0 : (_obj$contentType = obj.contentType) == null ? void 0 : _obj$contentType.type) === 'EditorialComponent' && key === 'fields') {
if ((obj == null || (_obj$contentType = obj.contentType) == null ? void 0 : _obj$contentType.type) === 'EditorialComponent' && key === 'fields') {
acc['content'] = traverse(value);

@@ -496,3 +515,8 @@ } else {

if (key === 'contentType' && 'sys' in obj) {
value.sysId = obj.sys.id;
value = {
...value,
sysId: obj.sys.id,
createdAt: obj.sys.createdAt,
updatedAt: obj.sys.updatedAt
};
}

@@ -508,20 +532,20 @@ acc[key] = traverse(value);

function transformImageOrFile(value) {
var _value$file, _value$file2, _value$file2$mediaTyp, _value$file9, _value$file10;
var _value$file, _value$file2, _value$file9, _value$file10;
if (!(value != null && (_value$file = value.file) != null && _value$file.url)) {
return null;
}
if (value != null && (_value$file2 = value.file) != null && (_value$file2$mediaTyp = _value$file2.mediaType) != null && _value$file2$mediaTyp.includes('image')) {
var _value$file3, _value$file4, _value$file4$details, _value$file4$details$, _value$file5, _value$file6, _value$file7, _value$file7$details, _value$file7$details$, _value$file8, _value$file8$details, _value$file8$details$;
if (value != null && (_value$file2 = value.file) != null && (_value$file2 = _value$file2.mediaType) != null && _value$file2.includes('image')) {
var _value$file3, _value$file4, _value$file5, _value$file6, _value$file7, _value$file8;
return {
src: (value == null ? void 0 : (_value$file3 = value.file) == null ? void 0 : _value$file3.url) || '',
alt: (value == null ? void 0 : (_value$file4 = value.file) == null ? void 0 : (_value$file4$details = _value$file4.details) == null ? void 0 : (_value$file4$details$ = _value$file4$details.image) == null ? void 0 : _value$file4$details$.alt) || '',
title: (value == null ? void 0 : value.title) || (value == null ? void 0 : (_value$file5 = value.file) == null ? void 0 : _value$file5.title) || '',
description: (value == null ? void 0 : value.description) || (value == null ? void 0 : (_value$file6 = value.file) == null ? void 0 : _value$file6.description) || '',
width: (value == null ? void 0 : (_value$file7 = value.file) == null ? void 0 : (_value$file7$details = _value$file7.details) == null ? void 0 : (_value$file7$details$ = _value$file7$details.image) == null ? void 0 : _value$file7$details$.width) || 0,
height: (value == null ? void 0 : (_value$file8 = value.file) == null ? void 0 : (_value$file8$details = _value$file8.details) == null ? void 0 : (_value$file8$details$ = _value$file8$details.image) == null ? void 0 : _value$file8$details$.height) || 0
src: (value == null || (_value$file3 = value.file) == null ? void 0 : _value$file3.url) || '',
alt: (value == null || (_value$file4 = value.file) == null || (_value$file4 = _value$file4.details) == null || (_value$file4 = _value$file4.image) == null ? void 0 : _value$file4.alt) || '',
title: (value == null ? void 0 : value.title) || (value == null || (_value$file5 = value.file) == null ? void 0 : _value$file5.title) || '',
description: (value == null ? void 0 : value.description) || (value == null || (_value$file6 = value.file) == null ? void 0 : _value$file6.description) || '',
width: (value == null || (_value$file7 = value.file) == null || (_value$file7 = _value$file7.details) == null || (_value$file7 = _value$file7.image) == null ? void 0 : _value$file7.width) || 0,
height: (value == null || (_value$file8 = value.file) == null || (_value$file8 = _value$file8.details) == null || (_value$file8 = _value$file8.image) == null ? void 0 : _value$file8.height) || 0
};
}
return {
mimeType: (value == null ? void 0 : (_value$file9 = value.file) == null ? void 0 : _value$file9.mediaType) || '',
src: (value == null ? void 0 : (_value$file10 = value.file) == null ? void 0 : _value$file10.url) || '',
mimeType: (value == null || (_value$file9 = value.file) == null ? void 0 : _value$file9.mediaType) || '',
src: (value == null || (_value$file10 = value.file) == null ? void 0 : _value$file10.url) || '',
title: (value == null ? void 0 : value.title) || '',

@@ -532,3 +556,3 @@ description: (value == null ? void 0 : value.description) || ''

function handleBooleans(value) {
return value === 'true' ? true : value === 'false' ? false : typeof value === 'undefined' ? null : value;
return value === 'true' || value === 'True' ? true : value === 'false' || value === 'False' ? false : typeof value === 'undefined' ? null : value;
}

@@ -545,3 +569,4 @@

market: options.market,
timeout: options.timeout
timeout: options.timeout,
contentTypeId: options.contentTypeId
};

@@ -578,3 +603,4 @@ let result;

timeout: options.timeout,
contentType
contentType,
contentTypeId: options.contentTypeId
};

@@ -600,2 +626,35 @@ try {

const SITEMAP_BASE_API_URL = 'https://gw.consumer.api.volvocars.com/sitemap/v1/applications';
async function getSitemapList(config, options) {
var _options$environment;
const requestDetails = {
applicationId: config.applicationId,
dataSource: options.dataSource,
operationId: options.operationId,
locale: options.locale,
environment: (_options$environment = options.environment) != null ? _options$environment : 'live',
market: options.market,
timeout: options.timeout
};
try {
const result = await sendRequest({
...requestDetails,
config,
path: `/sitemap`,
accept: 'sitemapitemlistsuccessresponse',
acceptHeaderType: 'sitemapservice',
baseUrl: SITEMAP_BASE_API_URL
});
return result;
} catch (error) {
let message = 'Failed fetching sitemap list';
if (error instanceof RequestError) {
message += ` '${error.status}: ${error.message}'`;
} else if (error.message) {
message += ` (${error.message})`;
}
throw new ContentDeliveryError(message, requestDetails, error);
}
}
class Cache {

@@ -673,2 +732,3 @@ /**

this.listEntriesCache = void 0;
this.sitemapCache = void 0;
this.dictionariesListCache = void 0;

@@ -698,3 +758,4 @@ this.localDataClient = void 0;

entries: revalidateDefault,
listEntries: revalidateDefault
listEntries: revalidateDefault,
sitemap: revalidateDefault
};

@@ -717,2 +778,3 @@ if (typeof config.revalidate === 'object') {

this.listEntriesCache = new Cache(this.config.revalidate.listEntries);
this.sitemapCache = new Cache(this.config.revalidate.sitemap);
}

@@ -1052,2 +1114,43 @@ get isValidating() {

}
async getSitemapList(rawOptions) {
const options = getOptionsWithDefaults({
locale: '',
...rawOptions
}, this.config);
validateDataSourceAndEnvironment(this.config, options);
const operationDetails = {
environment: options.environment,
dataSource: options.dataSource,
locale: ''
};
const cacheKey = {
...operationDetails,
name: 'sitemap'
};
if (this.config.revalidate.sitemap === 0 || !this.sitemapCache.has(cacheKey)) {
try {
const sitemap = await getSitemapList(this.config, options);
if (this.sitemapCache) {
this.sitemapCache.set(cacheKey, sitemap);
}
return sitemap;
} catch (error) {
this.logError('sitemap', operationDetails, error);
throw error;
}
}
if (this.sitemapCache.isStale(cacheKey)) {
this.pendingRevalidations++;
getSitemapList(this.config, options).then(sitemap => {
this.sitemapCache.set(cacheKey, sitemap);
}).catch(error => {
// Failing to refresh a stale sitemap list is not a fatal error, because
// there's already some content in the cache.
this.logError('sitemap', operationDetails, error);
}).finally(() => {
this.pendingRevalidations--;
});
}
return this.sitemapCache.get(cacheKey);
}
logError(type, {

@@ -1058,3 +1161,3 @@ locale,

}, error) {
if (process.env.NODE_ENV !== 'test') {
if (process.env.NODE_ENV !== 'test' && !this.config.disableLogging) {
console.log(`Failed fetching ${type} for locale '${locale}' in dataSource '${dataSource} @ ${environment}'.`);

@@ -1065,3 +1168,3 @@ console.error(getMessages(error));

logFallback() {
if (process.env.NODE_ENV !== 'test') {
if (process.env.NODE_ENV !== 'test' && !this.config.disableLogging) {
console.log('Falling back to local data...');

@@ -1068,0 +1171,0 @@ }

@@ -26,3 +26,3 @@ var flatten = require('flat');

const canonicalDictionaryNameRegex = /^[A-Za-z0-9]+\.[A-Za-z0-9]+$/;
const canonicalDictionaryNameRegex = /^[A-Za-z0-9]+\.[A-Za-z0-9_]+$/;
function validateCanonicalDictionaryName(canonicalDictionaryName) {

@@ -73,3 +73,3 @@ if (!canonicalDictionaryNameRegex.test(canonicalDictionaryName)) {

getLocalDictionary
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-c67434bc.js'); });
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-cf79408b.js'); });
return this.flattenDictionaries({

@@ -83,3 +83,3 @@ [canonicalDictionaryName]: await getLocalDictionary(canonicalDictionaryName, (_this$config$path = this.config.path) != null ? _this$config$path : '')

getLocalDictionaries
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-c67434bc.js'); });
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-cf79408b.js'); });
canonicalDictionaryNames.forEach(validateCanonicalDictionaryName);

@@ -92,3 +92,3 @@ return this.flattenDictionaries(Object.fromEntries(await getLocalDictionaries(canonicalDictionaryNames, (_this$config$path2 = this.config.path) != null ? _this$config$path2 : '')));

getLocalDictionaries
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-c67434bc.js'); });
} = await Promise.resolve().then(function () { return require('./getLocalDictionaries-cf79408b.js'); });
return this.flattenDictionaries(Object.fromEntries(await getLocalDictionaries([], (_this$config$path3 = this.config.path) != null ? _this$config$path3 : '')));

@@ -100,3 +100,3 @@ }

getLocalEntry
} = await Promise.resolve().then(function () { return require('./getLocalEntry-d8c829fa.js'); });
} = await Promise.resolve().then(function () { return require('./getLocalEntry-718c5d08.js'); });
return getLocalEntry(_canonicalName, (_this$config$path4 = this.config.path) != null ? _this$config$path4 : '');

@@ -107,2 +107,5 @@ }

}
async getSitemapList(_options) {
return [];
}
async flattenDictionaries(target) {

@@ -155,3 +158,4 @@ const {

}, error) {
super(`${message} in ${locale} @ ${dataSource} '${environment || 'live'}'`);
var _this$errors$;
super(`${message}${locale ? ` in ${locale}` : ''} @ ${dataSource} '${environment || 'live'}'`);
this.name = 'ContentDeliveryError';

@@ -165,2 +169,3 @@ this.errors = [];

this.operationId = void 0;
this.status = 500;
this.applicationId = applicationId;

@@ -183,2 +188,3 @@ this.dataSource = dataSource;

}
this.status = ((_this$errors$ = this.errors[0]) == null ? void 0 : _this$errors$.status) || 500;
}

@@ -245,24 +251,42 @@ }

const BASE_API_URL = 'https://gw.consumer.api.volvocars.com/content-delivery/v1/applications';
async function sendRequest({
applicationId,
dataSource,
path,
market = false,
locale,
accept,
environment,
operationId,
contentType,
timeout,
config,
limit
}, {
const BASE_API_URL_PROD = 'https://gw.consumer.api.volvocars.com/content-delivery/v1/applications';
const BASE_API_URL_QA = 'https://gw.qa.consumer.api.volvocars.com/content-delivery/v1/applications';
const sendRequest = async (options, {
retry = true
} = {}) {
} = {}) => {
var _fetchOptions;
const {
applicationId,
dataSource,
path,
market = false,
locale,
accept,
acceptHeaderType = 'contentdelivery',
environment,
operationId,
contentType,
contentTypeId,
timeout,
config,
limit,
baseUrl
} = options;
const timer = new Timeout(timeout);
const url = new URL(BASE_API_URL);
const isProdDataSource = !(dataSource != null && dataSource.endsWith('-qa') || dataSource != null && dataSource.endsWith('-test'));
const optInEnvSpecificUrl = typeof config.apiKey === 'object';
const defaultApiUrl = optInEnvSpecificUrl ? isProdDataSource ? BASE_API_URL_PROD : BASE_API_URL_QA : BASE_API_URL_PROD;
const url = new URL(baseUrl || defaultApiUrl);
const apiKeyEnv = isProdDataSource ? 'prod' : 'qa';
const apiKey = typeof config.apiKey === 'string' ? config.apiKey : config.apiKey[apiKeyEnv];
if (url.origin.startsWith('https://gw.consumer.api.volvocars.com') && !isProdDataSource && !(dataSource != null && dataSource.startsWith('dotcom-sitecore-'))) {
console.log(`[Warning: ContentDeliveryClient] QA and TEST dataSources will soon only work with
QA consumer portal(https://gw.qa.consumer.api.volvocars.com), make sure to change "apiKey"
config option from a string to an object with different values for each environment:
detected [${dataSource}] with production consumer portal URL`);
}
url.pathname += `/${applicationId}${path}`;
url.searchParams.set('Locale', locale);
if (locale) {
url.searchParams.set('Locale', locale);
}
if (dataSource) {

@@ -276,3 +300,3 @@ url.searchParams.set('DataSource', dataSource);

url.searchParams.set('environment', environment);
if (market) {
if (market && locale) {
const {

@@ -289,2 +313,10 @@ siteSlug

}
if (contentTypeId) {
var _dataSource$toLowerCa;
if (dataSource != null && (_dataSource$toLowerCa = dataSource.toLowerCase()) != null && _dataSource$toLowerCa.startsWith('contentstack')) {
url.searchParams.set('contentTypeId', contentTypeId);
} else {
throw new Error(`The 'contentTypeId' option is only supported for Contentstack datasource`);
}
}
if (limit) {

@@ -300,18 +332,17 @@ url.searchParams.set('limit', limit.toString());

}
const response = await Promise.race([timer.run(), fetch(url.href, {
headers: {
Accept: `application/vnd.volvocars.api.contentdelivery.${accept}+json`,
'VCC-Api-Key': config.apiKey,
...(operationId && {
'VCC-Api-OperationId': operationId
})
},
...fetchOptions
}).then(response => {
let response;
try {
response = await Promise.race([timer.run(), fetch(url.href, {
headers: {
Accept: `application/vnd.volvocars.api.${acceptHeaderType}.${accept}+json`,
'VCC-Api-Key': apiKey,
...(operationId && {
'VCC-Api-OperationId': operationId
})
},
...fetchOptions
})]);
} finally {
timer.clear();
return response;
}, error => {
timer.clear();
throw error;
})]);
}
if (response.status === 429 && retry && !timeout) {

@@ -323,15 +354,3 @@ const retryAfter = Number(response.headers.get('Retry-After') || 10) + 5;

await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return sendRequest({
applicationId,
dataSource,
path,
market,
locale,
accept,
environment,
operationId,
contentType,
timeout,
config
}, {
return sendRequest(options, {
retry: false

@@ -346,3 +365,3 @@ });

throw new RequestError('error' in result ? result.error.message : result.message, response.status, response.url);
}
};
let keepAliveAgent;

@@ -486,3 +505,3 @@ async function getKeepAliveAgent() {

// Throw a NotFoundError to allow catching and falling back to local data
throw new DictionaryNotFoundError('Empty dictionaries response', requestDetails);
throw new DictionaryNotFoundError('Empty dictionaries response', requestDetails, new RequestError('Empty dictionaries response', 404, '/dictionaries'));
}

@@ -509,3 +528,3 @@ return results;

var _obj$contentType;
if ((obj == null ? void 0 : (_obj$contentType = obj.contentType) == null ? void 0 : _obj$contentType.type) === 'EditorialComponent' && key === 'fields') {
if ((obj == null || (_obj$contentType = obj.contentType) == null ? void 0 : _obj$contentType.type) === 'EditorialComponent' && key === 'fields') {
acc['content'] = traverse(value);

@@ -519,3 +538,8 @@ } else {

if (key === 'contentType' && 'sys' in obj) {
value.sysId = obj.sys.id;
value = {
...value,
sysId: obj.sys.id,
createdAt: obj.sys.createdAt,
updatedAt: obj.sys.updatedAt
};
}

@@ -531,20 +555,20 @@ acc[key] = traverse(value);

function transformImageOrFile(value) {
var _value$file, _value$file2, _value$file2$mediaTyp, _value$file9, _value$file10;
var _value$file, _value$file2, _value$file9, _value$file10;
if (!(value != null && (_value$file = value.file) != null && _value$file.url)) {
return null;
}
if (value != null && (_value$file2 = value.file) != null && (_value$file2$mediaTyp = _value$file2.mediaType) != null && _value$file2$mediaTyp.includes('image')) {
var _value$file3, _value$file4, _value$file4$details, _value$file4$details$, _value$file5, _value$file6, _value$file7, _value$file7$details, _value$file7$details$, _value$file8, _value$file8$details, _value$file8$details$;
if (value != null && (_value$file2 = value.file) != null && (_value$file2 = _value$file2.mediaType) != null && _value$file2.includes('image')) {
var _value$file3, _value$file4, _value$file5, _value$file6, _value$file7, _value$file8;
return {
src: (value == null ? void 0 : (_value$file3 = value.file) == null ? void 0 : _value$file3.url) || '',
alt: (value == null ? void 0 : (_value$file4 = value.file) == null ? void 0 : (_value$file4$details = _value$file4.details) == null ? void 0 : (_value$file4$details$ = _value$file4$details.image) == null ? void 0 : _value$file4$details$.alt) || '',
title: (value == null ? void 0 : value.title) || (value == null ? void 0 : (_value$file5 = value.file) == null ? void 0 : _value$file5.title) || '',
description: (value == null ? void 0 : value.description) || (value == null ? void 0 : (_value$file6 = value.file) == null ? void 0 : _value$file6.description) || '',
width: (value == null ? void 0 : (_value$file7 = value.file) == null ? void 0 : (_value$file7$details = _value$file7.details) == null ? void 0 : (_value$file7$details$ = _value$file7$details.image) == null ? void 0 : _value$file7$details$.width) || 0,
height: (value == null ? void 0 : (_value$file8 = value.file) == null ? void 0 : (_value$file8$details = _value$file8.details) == null ? void 0 : (_value$file8$details$ = _value$file8$details.image) == null ? void 0 : _value$file8$details$.height) || 0
src: (value == null || (_value$file3 = value.file) == null ? void 0 : _value$file3.url) || '',
alt: (value == null || (_value$file4 = value.file) == null || (_value$file4 = _value$file4.details) == null || (_value$file4 = _value$file4.image) == null ? void 0 : _value$file4.alt) || '',
title: (value == null ? void 0 : value.title) || (value == null || (_value$file5 = value.file) == null ? void 0 : _value$file5.title) || '',
description: (value == null ? void 0 : value.description) || (value == null || (_value$file6 = value.file) == null ? void 0 : _value$file6.description) || '',
width: (value == null || (_value$file7 = value.file) == null || (_value$file7 = _value$file7.details) == null || (_value$file7 = _value$file7.image) == null ? void 0 : _value$file7.width) || 0,
height: (value == null || (_value$file8 = value.file) == null || (_value$file8 = _value$file8.details) == null || (_value$file8 = _value$file8.image) == null ? void 0 : _value$file8.height) || 0
};
}
return {
mimeType: (value == null ? void 0 : (_value$file9 = value.file) == null ? void 0 : _value$file9.mediaType) || '',
src: (value == null ? void 0 : (_value$file10 = value.file) == null ? void 0 : _value$file10.url) || '',
mimeType: (value == null || (_value$file9 = value.file) == null ? void 0 : _value$file9.mediaType) || '',
src: (value == null || (_value$file10 = value.file) == null ? void 0 : _value$file10.url) || '',
title: (value == null ? void 0 : value.title) || '',

@@ -555,3 +579,3 @@ description: (value == null ? void 0 : value.description) || ''

function handleBooleans(value) {
return value === 'true' ? true : value === 'false' ? false : typeof value === 'undefined' ? null : value;
return value === 'true' || value === 'True' ? true : value === 'false' || value === 'False' ? false : typeof value === 'undefined' ? null : value;
}

@@ -568,3 +592,4 @@

market: options.market,
timeout: options.timeout
timeout: options.timeout,
contentTypeId: options.contentTypeId
};

@@ -601,3 +626,4 @@ let result;

timeout: options.timeout,
contentType
contentType,
contentTypeId: options.contentTypeId
};

@@ -623,2 +649,35 @@ try {

const SITEMAP_BASE_API_URL = 'https://gw.consumer.api.volvocars.com/sitemap/v1/applications';
async function getSitemapList(config, options) {
var _options$environment;
const requestDetails = {
applicationId: config.applicationId,
dataSource: options.dataSource,
operationId: options.operationId,
locale: options.locale,
environment: (_options$environment = options.environment) != null ? _options$environment : 'live',
market: options.market,
timeout: options.timeout
};
try {
const result = await sendRequest({
...requestDetails,
config,
path: `/sitemap`,
accept: 'sitemapitemlistsuccessresponse',
acceptHeaderType: 'sitemapservice',
baseUrl: SITEMAP_BASE_API_URL
});
return result;
} catch (error) {
let message = 'Failed fetching sitemap list';
if (error instanceof RequestError) {
message += ` '${error.status}: ${error.message}'`;
} else if (error.message) {
message += ` (${error.message})`;
}
throw new ContentDeliveryError(message, requestDetails, error);
}
}
class Cache {

@@ -696,2 +755,3 @@ /**

this.listEntriesCache = void 0;
this.sitemapCache = void 0;
this.dictionariesListCache = void 0;

@@ -721,3 +781,4 @@ this.localDataClient = void 0;

entries: revalidateDefault,
listEntries: revalidateDefault
listEntries: revalidateDefault,
sitemap: revalidateDefault
};

@@ -740,2 +801,3 @@ if (typeof config.revalidate === 'object') {

this.listEntriesCache = new Cache(this.config.revalidate.listEntries);
this.sitemapCache = new Cache(this.config.revalidate.sitemap);
}

@@ -1075,2 +1137,43 @@ get isValidating() {

}
async getSitemapList(rawOptions) {
const options = getOptionsWithDefaults({
locale: '',
...rawOptions
}, this.config);
validateDataSourceAndEnvironment(this.config, options);
const operationDetails = {
environment: options.environment,
dataSource: options.dataSource,
locale: ''
};
const cacheKey = {
...operationDetails,
name: 'sitemap'
};
if (this.config.revalidate.sitemap === 0 || !this.sitemapCache.has(cacheKey)) {
try {
const sitemap = await getSitemapList(this.config, options);
if (this.sitemapCache) {
this.sitemapCache.set(cacheKey, sitemap);
}
return sitemap;
} catch (error) {
this.logError('sitemap', operationDetails, error);
throw error;
}
}
if (this.sitemapCache.isStale(cacheKey)) {
this.pendingRevalidations++;
getSitemapList(this.config, options).then(sitemap => {
this.sitemapCache.set(cacheKey, sitemap);
}).catch(error => {
// Failing to refresh a stale sitemap list is not a fatal error, because
// there's already some content in the cache.
this.logError('sitemap', operationDetails, error);
}).finally(() => {
this.pendingRevalidations--;
});
}
return this.sitemapCache.get(cacheKey);
}
logError(type, {

@@ -1081,3 +1184,3 @@ locale,

}, error) {
if (process.env.NODE_ENV !== 'test') {
if (process.env.NODE_ENV !== 'test' && !this.config.disableLogging) {
console.log(`Failed fetching ${type} for locale '${locale}' in dataSource '${dataSource} @ ${environment}'.`);

@@ -1088,3 +1191,3 @@ console.error(getMessages(error));

logFallback() {
if (process.env.NODE_ENV !== 'test') {
if (process.env.NODE_ENV !== 'test' && !this.config.disableLogging) {
console.log('Falling back to local data...');

@@ -1091,0 +1194,0 @@ }

@@ -1,4 +0,5 @@

import type { ClientConfig, ContentDeliveryClient, GetOptions } from './ContentDeliveryClient';
import type { ClientConfig, ContentDeliveryClient, GetOptions, GetSitemapListOptions } from './ContentDeliveryClient';
import type { FlattenedDictionaries } from './dictionaries/types';
import type { ContentType, ListEntriesResponseData } from './entries/types';
import type { SitemapListResponseData } from './sitemap/types';
export declare class LocalDataClient implements ContentDeliveryClient {

@@ -15,3 +16,4 @@ applicationId: string;

listEntries<T extends ContentType>(_contentType: T, _options: GetOptions): Promise<ListEntriesResponseData<T>>;
getSitemapList(_options?: GetSitemapListOptions): Promise<SitemapListResponseData>;
private flattenDictionaries;
}
import { ClientConfig } from '.';
import { ContentDeliveryClient, ContentDeliveryDataSource, ContentEnvironment, GetAllDictionariesOptions, GetOptions } from './ContentDeliveryClient';
import { ContentDeliveryClient, ContentDeliveryDataSource, ContentEnvironment, GetAllDictionariesOptions, GetOptions, GetSitemapListOptions } from './ContentDeliveryClient';
import { FlattenedDictionaries } from './dictionaries/types';
import { ContentType, ListEntriesResponseData } from './entries/types';
import { LocalDataClient } from './LocalDataClient';
import { SitemapListResponseData } from './sitemap/types';
export type FinalClientConfig = Omit<ClientConfig, 'dataSource'> & {

@@ -14,2 +15,3 @@ defaultEnvironment: ContentEnvironment;

listEntries: number;
sitemap: number;
};

@@ -24,2 +26,3 @@ };

private listEntriesCache;
private sitemapCache;
private dictionariesListCache;

@@ -35,4 +38,5 @@ private localDataClient?;

listEntries<T extends ContentType>(contentType: T, rawOptions: GetOptions): Promise<ListEntriesResponseData<T>>;
getSitemapList(rawOptions?: GetSitemapListOptions): Promise<SitemapListResponseData>;
private logError;
private logFallback;
}

@@ -6,4 +6,4 @@ /// <reference types="node" />

constructor(seconds?: number);
run(): Promise<void>;
run(): Promise<never>;
clear(): void;
}

@@ -8,4 +8,5 @@ import { GetOptions } from '../../ContentDeliveryClient';

timeout?: number | undefined;
contentTypeId?: string | undefined;
dataSource: string | undefined;
environment: import("../../ContentDeliveryClient").ContentEnvironment;
};

@@ -5,3 +5,3 @@ import type { ClientConfig, ContentEnvironment } from '../ContentDeliveryClient';

applicationId: string;
locale: string;
locale?: string;
environment: ContentEnvironment;

@@ -12,2 +12,3 @@ dataSource?: string;

contentType?: ContentType;
contentTypeId?: string;
timeout?: number;

@@ -20,6 +21,8 @@ limit?: number;

accept: string;
acceptHeaderType?: string;
baseUrl?: string;
};
export declare function sendRequest<Results>({ applicationId, dataSource, path, market, locale, accept, environment, operationId, contentType, timeout, config, limit, }: RequestDetails & SendRequestOptions, { retry }?: {
export declare const sendRequest: <Results>(options: RequestDetails & SendRequestOptions, { retry }?: {
retry?: boolean | undefined;
}): Promise<Results>;
}) => Promise<Results>;
export {};
{
"name": "@volvo-cars/content-delivery-client",
"version": "0.5.0",
"version": "0.6.0",
"license": "UNLICENSED",

@@ -32,5 +32,5 @@ "source": "index.ts",

"@types/flat": "^5.0.1",
"@volvo-cars/market-sites": "1.7.3",
"@volvo-cars/market-sites": "1.8.0",
"flat": "^5.0.0",
"glob": "^8.1.0"
"glob": "^10.3.4"
},

@@ -40,8 +40,9 @@ "devDependencies": {

"@vcc-www/utils": "0.0.0",
"@volvo-cars/content-management-client": "0.21.0",
"@volvo-cars/content-management-client": "0.22.0",
"microbundle": "^0.15.1",
"msw": "^1.2.1",
"typescript": "5.0.2"
"typescript": "5.2.2"
},
"module": "dist/index.esm.js"
"module": "dist/index.esm.js",
"types": "dist/index.d.ts"
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc