@progress/sitefinity-nextjs-sdk
Version:
Provides OOB widgets developed using the Next.js framework, which includes an abstraction layer for Sitefinity communication. Additionally, it offers an expanded API, typings, and tools for further development and integration.
941 lines • 55.2 kB
JavaScript
import { RootUrlService } from './root-url.service';
import { ServiceMetadata } from './service-metadata';
import { ODataFilterSerializer } from './services/odata-filter-serializer';
import { RENDERER_NAME, getProxyHeaders } from '../proxy/headers';
import { ErrorCodeException } from './errors/error-code.exception';
import { Tracer } from '@progress/sitefinity-nextjs-sdk/diagnostics/empty';
import { QueryParamNames } from './query-params-names';
import { getAdditionalFetchDataServerContext, getHostServerContext, getQueryParamsServerContext } from '../services/server-context';
import { getServerSideCookie } from '../server-side-cookie';
import { MovingDirection } from './args/change-location-priority.args';
import { getFilteredServerSideHeaders } from '../server-side-headers';
import { SF_WEBSERVICE_API_KEY, SF_WEBSERVICE_API_KEY_HEADER } from '../widgets/common/utils';
import { EMTPY_GUID } from '../editor/utils/guid';
/**
* Provides implementation for communicating with the Sitefinity REST API services.
* This class is used to perform CRUD operations on items, search for items, and manage content in Sitefinity.
*/
export class RestClient {
static contextQueryParams;
/**
* Gets a media item with extended properties by type and id.
* @param {ItemArgs} args The arguments for the request.
*@param {string} args.type The type name of the item to retrieve.
*@param {string} args.id The id of the item to retrieve.
*@param {string} [args.culture] The culture for the request.
*@param {string} [args.provider] The provider for the item if it is a part of non-default provider for the site and type.
* @returns {Promise<T>} The requested item.
*/
static getItemWithFallback(args) {
let queryParams = {
sf_fallback_prop_names: '*',
$select: '*'
};
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.GetItemWithFallback()${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }, true);
}
/**
* Gets a collection of taxons based on request arguments.
* @param {GetTaxonArgs}args The arguments for the request.
* @param {string} args.taxonomyId The taxonomy type id to retrieve taxons from.
* @param {string[]} args.taxaIds The ids of the taxons to retrieve. Used when selection mode is "Selected" or "UnderParent".
* @param {'All' | 'TopLevel' | 'UnderParent' | 'Selected' | 'ByContentType'} args.selectionMode The selection mode for the taxons.
* @param {string} args.contentType Filter taxons that refer a specific content type. Used when selection mode is "ByContentType".
* @param {boolean} args.showEmpty Whether to show taxons that have no related content items.
* @param {string} args.orderBy The order by clause for the taxons.
* @returns {Promise<Array<TaxonDto>>} A collection of matching taxons.
*/
static getTaxons(args) {
const queryParams = {
'showEmpty': args.showEmpty.toString(),
'$orderby': args.orderBy,
'@param': `[${(args.taxaIds || []).map(x => `'${x}'`).toString()}]`
};
const taxonomy = ServiceMetadata.taxonomies.find(x => x.Id === args.taxonomyId);
if (!taxonomy) {
throw `The taxonomy with id ${args.taxonomyId} does not exist`;
}
const action = `Default.GetTaxons(taxonomyId=${args.taxonomyId},selectedTaxaIds=@param,selectionMode='${args.selectionMode}',contentType='${args.contentType || ''}')`;
const wholeUrl = `${RestClient.buildItemBaseUrl(taxonomy['TaxaUrl'])}/${action}${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then(x => x.value);
}
static getSearchMetadata(args) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetSearchMetadata()`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, headers: args.additionalHeaders, traceContext: args.traceContext });
}
static getItemWithStatus(args) {
const filteredSimpleFields = this.getSimpleFields(args.type, args.fields || ['*']);
const filteredRelatedFields = this.getRelatedFields(args.type, args.fields || ['*']);
let queryParams = {
$select: filteredSimpleFields.join(','),
$expand: filteredRelatedFields.join(',')
};
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.GetItemWithStatus()${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders });
}
/**
* Gets a content item by type and id.
* @param {ItemArgs} args The arguments for the request.
* @param {string} args.type The type name of the item to retrieve.
* @param {string} args.id The id of the item to retrieve.
* @param {string} [args.culture] The culture for the request.
* @param {string[]} [args.fields] The fields to include in the response. By default the '*' wildcard is used and related fields are excluded.
* @param {string} [args.provider] The provider for the item if it is a part of non-default provider for the site and type.
* @param {Dictionary} [args.additionalQueryParams] Additional query parameters to include in the request.
* @param {Dictionary} [args.additionalHeaders] Additional headers to include in the request.
* @param {any} [args.additionalFetchData] Additional fetch data to include in the request.
* @param {any} [args.traceContext] The current OpenTelemetry trace context for the request if such is available. It could be found in the WidgetContext.
* @returns {Promise<T>} The requested item.
*/
static getItem(args) {
const filteredSimpleFields = this.getSimpleFields(args.type, args.fields || ['*']);
const filteredRelatedFields = this.getRelatedFields(args.type, args.fields || []);
let queryParams = {
'$select': filteredSimpleFields.join(','),
'$expand': filteredRelatedFields.join(',')
};
const wholeUrl = `${this.buildItemBaseUrl(args.type)}(${args.id})${this.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders });
}
/**
* Gets a shared content block by id.
* @param args The arguments for the request.
* @param {string} args.id The id of the shared content block to retrieve.
* @param {string} [args.cultureName] The culture for the request and the version of the shared content block content to retrieve.
* @returns {Promise<GenericContentItem>} The requested content block.
*/
static getSharedContent(args) {
let queryParams = {
sf_fallback_prop_names: 'Content'
};
if (args.cultureName) {
queryParams[QueryParamNames.Culture] = args.cultureName;
}
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.GenericContent)}/Default.GetItemById(itemId=${args.id})${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }, true);
}
/**
* Gets a collection of items based on the provided arguments.
* @param {GetAllArgs}args The get multiple items args.
* @param {string} args.type The type name of the items to retrieve.
* @param {number} [args.skip] The number of items to skip in the response.
* @param {number} [args.take] The maximum number of items to return in the response.
* @param {OrderBy} [args.orderBy] The order by clause to apply to the request.
* @param {string} [args.provider] The provider for the items if they are part of a non-default provider for the site and type.
* @param {string} [args.culture] The culture for the request.
* @param {string[]} [args.fields] The fields to include in the response. By default the '*' wildcard is used and related fields are excluded.
* @param {FilterClause | CombinedFilter | RelationFilter | DateOffsetPeriod | null} [args.filter] The filter to apply to the collection request.
* @param {boolean} [args.count] Whether to include the total count of items in the response.
* @param {Dictionary} [args.additionalQueryParams] Additional query parameters to include in the request.
* @param {Dictionary} [args.additionalHeaders] Additional headers to include in the request.
* @param {any} [args.additionalFetchData] Additional fetch data to include in the request.
* @param {any} [args.traceContext] The current OpenTelemetry trace context for the request if such is available. It could be found in the WidgetContext.
* @returns {Promise<CollectionResponse>} The wrepper object with a collection of the matched items if such exist. Otherwise an empty collection.
*/
static getItems(args) {
const filteredSimpleFields = this.getSimpleFields(args.type, args.fields || []);
const filteredRelatedFields = this.getRelatedFields(args.type, args.fields || []);
let queryParams = {
'$count': args.count,
'$orderby': args.orderBy && args.orderBy.length > 0 ? args.orderBy.map(x => `${x.Name} ${x.Type}`) : null,
'$select': filteredSimpleFields.join(','),
'$expand': filteredRelatedFields.join(','),
'$skip': args.skip,
'$top': args.take,
'$filter': args.filter ? new ODataFilterSerializer().serialize({ Type: args.type, Filter: args.filter }) : null
};
const wholeUrl = `${this.buildItemBaseUrl(args.type)}${this.buildQueryParams(RestClient.getQueryParams(args, queryParams))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then((x) => {
return { Items: x.value, TotalCount: x['@odata.count'] };
});
}
static createItem(args) {
let taxonomyPrefix = 'Taxonomy_';
if (args.type.startsWith(taxonomyPrefix)) {
const actualTaxonomyType = args.type.substring(taxonomyPrefix.length);
const taxonomy = ServiceMetadata.taxonomies.find(x => x['Name'] === actualTaxonomyType);
if (!taxonomy) {
throw `Taxonomy with the name ${taxonomy} does not exist`;
}
args.type = taxonomy['TaxaUrl'];
args.data['TaxonomyId'] = taxonomy.Id;
}
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: args.data,
method: 'POST',
headers: args.additionalHeaders
}).then((x) => {
return x;
});
}
static scheduleItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.Operation()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: {
action: 'Schedule',
actionParameters: {
PublicationDate: args.publicationDate.toISOString(),
ExpirationDate: args.expirationDate?.toISOString()
}
},
method: 'POST',
headers: args.additionalHeaders
});
}
static updateItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: args.data,
method: 'PATCH',
headers: args.additionalHeaders
});
}
static deleteItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
method: 'DELETE',
headers: args.additionalHeaders
}).then((x) => {
return x;
});
}
static publishItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.Operation()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: {
action: 'Publish',
actionParameters: {}
},
method: 'POST',
headers: args.additionalHeaders
});
}
static saveDraftItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/operation${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: {
action: 'SaveDraft',
actionParameters: {}
},
method: 'POST',
headers: args.additionalHeaders
});
}
static syncPage(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: Object.assign({}, args.data, { EnableSync: true }),
method: 'PATCH',
headers: args.additionalHeaders
});
}
static lockItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.SaveTemp()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: Object.assign({}, args.data),
method: 'POST',
headers: args.additionalHeaders
});
}
static relateItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/${args.relationName}/$ref${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
const relatedTypeName = ServiceMetadata.getRelatedType(args.type, args.relationName);
if (!relatedTypeName) {
throw `Cannot find the type behind the field -> ${args.relationName}`;
}
let relatedItemUri = `${RestClient.buildItemBaseUrl(relatedTypeName)}(${args.relatedItemId})`;
if (args.relatedItemProvider) {
relatedItemUri = relatedItemUri + `?sf_provider=${args.relatedItemProvider}`;
}
return RestClient.sendRequest({
url: wholeUrl,
data: {
'@odata.id': relatedItemUri
},
method: 'POST',
headers: args.additionalHeaders
});
}
static lockPage(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.Lock()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: {
state: {
Version: args.version
}
},
method: 'POST',
headers: args.additionalHeaders
});
}
static createWidget(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.AddWidget()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
const properties = [];
if (args.properties) {
Object.keys(args.properties).forEach((x) => {
properties.push({
Name: x,
Value: args.properties[x]
});
});
}
const dto = {
widget: {
Id: null,
Name: args.name,
SiblingKey: args.siblingKey,
ParentPlaceholderKey: args.parentPlaceholderKey,
PlaceholderName: args.placeholderName,
Properties: properties
}
};
return RestClient.sendRequest({
url: wholeUrl,
data: dto,
method: 'POST',
headers: args.additionalHeaders
});
}
static updateWidget(page, propertyValues) {
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Pages)}(${page.Id})/Default.SetProperties()${RestClient.buildQueryParams(RestClient.getQueryParams(propertyValues, undefined))}`;
return RestClient.sendRequest({
url: wholeUrl,
data: propertyValues,
method: 'POST',
headers: propertyValues.additionalHeaders
});
}
static uploadItem(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
const headers = args.additionalHeaders || {};
const data = Object.assign({}, args.fields, { Title: args.title, ParentId: args.parentId, UrlName: args.urlName });
headers['X-Sf-Properties'] = JSON.stringify(data);
headers['X-File-Name'] = args.fileName;
headers['Content-Type'] = args.contentType;
headers['Content-Length'] = args.binaryData.length.toString();
headers['Content-Encoding'] = 'base64';
headers['DirectUpload'] = true.toString();
return RestClient.sendRequest({
url: wholeUrl,
data: args.binaryData,
method: 'POST',
headers
}).then((x) => {
return x;
});
}
static performSearch(args) {
const query = {
['indexCatalogue']: args.indexCatalogue,
['searchQuery']: encodeURIComponent(args.searchQuery).toLowerCase(),
['wordsMode']: args.wordsMode,
['$orderBy']: args.orderBy,
['sf_culture']: args.culture,
['$skip']: args.skip?.toString(),
['$top']: args.take?.toString(),
['searchFields']: args.searchFields,
['highlightedFields']: args.highlightedFields,
['resultsForAllSites']: '',
['scoringInfo']: args.scoringInfo,
['filter']: args.filter,
['indexFields']: args.indexFields
};
if (args.resultsForAllSites != null) {
query['resultsForAllSites'] = args.resultsForAllSites ? '1' : '2';
}
const serviceUrl = args.webServicePath ?? `${RootUrlService.getServerCmsUrl() || ''}/${RootUrlService.getSearchWebServicePath()}`;
const wholeUrl = `${serviceUrl}/Default.PerformSearch()${RestClient.buildQueryParams(RestClient.getQueryParams(args, query))}`;
const searchResultsDocumentsDefaultKeys = ['HighLighterResult', 'Language', 'Provider', 'Link', 'Title', 'ContentType', 'Id', 'ThumbnailUrl'];
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then(x => {
const mappedSearchResults = x.SearchResults.map(searchResult => {
const document = {
HighLighterResult: searchResult.HighLighterResult,
Language: searchResult.Language,
Provider: searchResult.Provider,
Link: searchResult.Link,
Title: searchResult.Title,
ContentType: searchResult.ContentType,
Id: searchResult.Id,
ThumbnailUrl: searchResult.ThumbnailUrl,
IndexedFields: new Map()
};
Object.keys(searchResult)
.filter(p => !p.includes('@odata.type'))
.forEach(propertyName => {
// exclude the default properties and the odata typevalue properties
if (!searchResultsDocumentsDefaultKeys.includes(propertyName)) {
document.IndexedFields.set(propertyName, searchResult[propertyName]);
}
});
return document;
});
return {
totalCount: x.TotalCount,
searchResults: mappedSearchResults
};
});
}
static getSearchSuggestions(args) {
const query = {
['indexName']: args.indexCatalogue,
['searchQuery']: encodeURIComponent(args.searchQuery).toLowerCase(),
['sf_culture']: args.culture,
['siteId']: args.culture,
['scoringInfo']: args.scoringInfo,
['suggestionFields']: args.suggestionFields,
['resultsForAllSites']: ''
};
if (args.resultsForAllSites !== null) {
query['resultsForAllSites'] = args.resultsForAllSites ? 'True' : 'False';
}
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetSuggestions()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, query))}`;
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders });
}
static getFacatebleFields(args) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetFacetableFields(indexCatalogName='${args.indexCatalogue}')`;
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then(x => x.value);
}
static async getFacets(args) {
const facetsStr = JSON.stringify(args.facets);
const additionalQueryParams = {
['searchQuery']: encodeURIComponent(args.searchQuery)?.toLowerCase(),
['sf_culture']: args.culture,
['indexCatalogName']: args.indexCatalogue,
['filter']: args.filter,
['resultsForAllSites']: args.resultsForAllSites,
['searchFields']: args.searchFields,
['facetFields']: facetsStr
};
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetFacets()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, additionalQueryParams))}`;
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then(x => x.value);
}
static getResetPasswordModel(token, traceContext, headers) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetResetPasswordModel()`;
return RestClient.sendRequest({ url: wholeUrl, data: { securityToken: token }, method: 'POST', traceContext, headers });
}
static getRegistrationSettings(args) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.RegistrationSettings()${RestClient.buildQueryParams(RestClient.getQueryParams(args, {}))}`;
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders });
}
static activateAccount(encryptedParam, traceContext, headers) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.AccountActivation()${RestClient.buildQueryParams({ qs: encodeURIComponent(encryptedParam) })}`;
return RestClient.sendRequest({ url: wholeUrl, traceContext, headers }, true);
}
static getExternalProviders(args) {
const serviceUrl = RootUrlService.getServerCmsServiceUrl();
const wholeUrl = `${serviceUrl}/Default.GetExternalProviders()`;
return RestClient.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then((x) => x.value);
}
static getCurrentUser(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl('users')}/current${RestClient.buildQueryParams(RestClient.getQueryParams(args, {}))}`;
return RestClient.sendRequest({
url: wholeUrl,
method: 'GET',
additionalFetchData: args?.additionalFetchData,
traceContext: args?.traceContext,
headers: args?.additionalHeaders
}).then((x) => {
return x.value;
});
}
static getCurrentSite(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl('sites')}/current`;
return RestClient.sendRequest({
url: wholeUrl,
method: 'GET',
additionalFetchData: args?.additionalFetchData,
traceContext: args?.traceContext,
headers: args?.additionalHeaders
}).then((x) => {
return x.value;
});
}
static getSites(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl('sites')}${RestClient.buildQueryParams(RestClient.getQueryParams(args, {}))}`;
return RestClient.sendRequest({
url: wholeUrl,
method: 'GET',
additionalFetchData: args?.additionalFetchData,
traceContext: args?.traceContext,
headers: args?.additionalHeaders
}).then((x) => {
return x.value;
});
}
static getNavigation(args) {
let queryMap = {
'selectionModeString': args.selectionMode,
'showParentPage': args.showParentPage ? args.showParentPage.toString() : undefined,
'sf_page_node': args.currentPage,
'selectedPages': args.selectedPages && args.selectedPages.length > 0 ? JSON.stringify(args.selectedPages) : undefined,
'levelsToInclude': args.levelsToInclude ? args.levelsToInclude.toString() : null,
'selectedPageId': args.selectedPageId
};
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Pages)}/Default.HierarhicalByLevelsResponse()${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryMap))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then((x) => {
return x.value;
});
}
static getBreadcrumb(args) {
let queryMap = {};
Object.keys(args).filter(x => args[x]).map((x) => {
if (x === 'detailItemInfo') {
queryMap[x] = JSON.stringify(args[x]);
}
else {
queryMap[x] = args[x].toString();
}
});
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Pages)}/Default.GetBreadcrumb()${RestClient.buildQueryParams(RestClient.getQueryParams(args, queryMap))}`;
return this.sendRequest({ url: wholeUrl, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext, headers: args.additionalHeaders }).then((x) => {
return x.value;
});
}
static setHomePage(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Pages)}/Default.SetHomePage()${RestClient.buildQueryParams(RestClient.getQueryParams(args, undefined))}`;
return this.sendRequest({
url: wholeUrl,
data: {
pageId: args.id
},
method: 'POST',
headers: args.additionalHeaders
});
}
static async getPreviewLink(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.Operation()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return this.sendRequest({
url: wholeUrl,
data: {
'action': 'Preview'
},
method: 'POST',
headers: args.additionalHeaders
});
}
static async getPageSharePreviewLink(pageId) {
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Pages)}(${pageId})/Default.SharePreviewLink()${RestClient.buildQueryParams(RestClient.getQueryParams())}`;
return this.sendRequest({
url: wholeUrl,
method: 'GET'
});
}
static async getContentLocations(args) {
const wholeUrl = `${RootUrlService.getClientCmsUrl()}/Sitefinity/Services/LocationService/${RestClient.buildQueryParams({ itemType: args.type, provider: args.provider })}`;
return this.sendRequest({
url: wholeUrl,
method: 'GET',
headers: args.additionalHeaders,
additionalFetchData: args.additionalFetchData
});
}
static async getDisplayPages(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/DisplayPages${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return this.sendRequest({
url: wholeUrl,
method: 'GET',
headers: args.additionalHeaders,
additionalFetchData: args.additionalFetchData
});
}
static async getProviders(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}/sfproviders`;
return this.sendRequest({
url: wholeUrl,
method: 'GET',
headers: args.additionalHeaders,
additionalFetchData: args.additionalFetchData
}).then((x) => {
return x.value;
});
}
static async changeLocationPriority(args) {
const direction = args.direction || MovingDirection.Top;
const directionCode = direction.toString();
const wholeUrl = `${RootUrlService.getClientCmsUrl()}/Sitefinity/Services/LocationService/${RestClient.buildQueryParams({ 'id': args.id, 'direction': directionCode })}`;
return this.sendRequest({
url: wholeUrl,
method: 'PUT',
headers: args.additionalHeaders
});
}
static async getFormLayout(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(RestSdkTypes.Form)}(${args.id})/Default.Model()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return RestClient.sendRequest({ url: wholeUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext });
}
static async getWidgetModel(args) {
args.additionalQueryParams = args.additionalQueryParams || {};
args.additionalQueryParams.sfwidgetsegment = args.widgetSegmentId || '';
args.additionalQueryParams.segment = args.segmentId || '';
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.HierarchicalWidgetModel(componentId='${args.widgetId}')${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return RestClient.sendRequest({ url: wholeUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData, traceContext: args.traceContext });
}
static async getLazyWidget(args) {
args.additionalQueryParams = args.additionalQueryParams || {};
args.additionalQueryParams.sfwidgetsegment = args.widgetSegmentId || '';
args.additionalQueryParams.segment = args.segmentId || '';
let lazyComponentsUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.LazyComponents()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return RestClient.sendRequest({ url: lazyComponentsUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData }).then(x => x.Components.find(y => y.Id === args.widgetId));
}
static async getLazyWidgets(args) {
let url = encodeURIComponent(args.url);
let concatChar = '?';
if (url.indexOf('?')) {
concatChar = '&';
}
let lazyComponentsUrl = RootUrlService.getServerCmsServiceUrl() + `/Default.LazyComponents(url=@param)?@param='${url}'${concatChar}correlationId=${args.correlationId}`;
const headers = { 'Cookie': args.cookie };
const referrer = args.referrer;
if (referrer && referrer.length > 0) {
headers['SF_URL_REFERER'] = referrer;
}
else {
headers['SF_NO_URL_REFERER'] = 'true';
}
return RestClient.sendRequest({ url: lazyComponentsUrl, headers, additionalFetchData: args.additionalFetchData }).then(x => x.Components);
}
static async getPageLayout(args) {
let layoutResponse;
let headers = args.additionalHeaders || {};
RestClient.addAuthHeaders(args.cookie, headers);
const serverSideHeaders = await getFilteredServerSideHeaders();
if (serverSideHeaders) {
Object.entries(serverSideHeaders).forEach(([headerKey, headerValue]) => {
headers[headerKey] = headerValue;
});
}
const headerKeys = Object.keys(headers).map(x => x.toLowerCase());
if (typeof window === 'undefined' || process.env.NODE_ENV === 'test') {
const host = getHostServerContext();
const proxyHeaders = getProxyHeaders(host);
Object.entries(proxyHeaders).forEach(([headerKey, headerValue]) => {
if (!headerKeys.includes(headerKey.toLowerCase())) {
headers[headerKey] = headerValue;
}
});
}
const queryParams = args.queryParams || {};
if (args.relatedFields) {
queryParams['$expand'] = args.relatedFields.join(',');
}
const sysParamsQueryString = RestClient.buildQueryParams(queryParams);
let url = `${args.pagePath}${sysParamsQueryString}`;
if (process.env.NEXT_PUBLIC_SF_NEXT_GEN === 'true' || process.env.NEXT_PUBLIC_SF_NEXT_GEN === '1') {
if (url[0] !== '/') {
url = '/' + url;
}
const encodedUrl = `'${encodeURIComponent(url)}'`;
const queryParams = Object.assign({ '@param': encodedUrl });
url = `${RootUrlService.getServerCmsServiceUrl()}/Default.Model(url=@param)${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, queryParams))}`;
}
else {
if (!args.pagePath.includes('http') && !args.pagePath.includes('https')) {
if (!url.startsWith('/')) {
url = '/' + url;
}
url = RootUrlService.getServerCmsUrl() + url;
}
}
let requestData = { url: url, headers: headers, method: 'GET' };
let requestInit = { headers, method: requestData.method, redirect: 'manual' };
const additionalFetchData = getAdditionalFetchDataServerContext();
if (additionalFetchData) {
requestInit = Object.assign(requestInit, additionalFetchData);
}
if (args.additionalFetchData) {
requestInit = Object.assign(requestInit, args.additionalFetchData);
}
let httpLayoutResponse = null;
try {
httpLayoutResponse = await Tracer.withContext(() => fetch(requestData.url, requestInit), args.traceContext);
}
catch (error) {
if (error instanceof ErrorCodeException && error.code === 'NotFound') {
throw error;
}
if (error instanceof ErrorCodeException && error.code === 'Unauthorized') {
throw `Could not authorize fetching layout for url '${args.pagePath}'. Contact your system administator or check your access token.`;
}
}
if (!httpLayoutResponse) {
throw 'Error while fetching the page';
}
if (httpLayoutResponse.status === 302 && httpLayoutResponse.headers.has('urlparameters')) {
let urlParameters = httpLayoutResponse.headers.get('urlparameters').split('/');
args.pagePath = httpLayoutResponse.headers.get('location');
const layoutRecursive = await this.getPageLayout(args);
layoutRecursive.layout.UrlParameters = urlParameters;
return layoutRecursive;
}
if ((httpLayoutResponse.status === 301 || httpLayoutResponse.status === 302)) {
let location = httpLayoutResponse.headers.get('location');
if (location.startsWith('/')) {
location = location.substring(1);
}
if (!args.followRedirects) {
return {
isRedirect: true,
redirect: {
Location: location,
Permenant: httpLayoutResponse.status === 301
}
};
}
else {
args.pagePath = location;
const layoutRecursive = await this.getPageLayout(args);
return layoutRecursive;
}
}
if (httpLayoutResponse.status === 404) {
throw new ErrorCodeException('NotFound', 'page not found');
}
layoutResponse = await RestClient.handleApiResponse(httpLayoutResponse, requestData, true);
const cacheControl = httpLayoutResponse.headers.get('Cache-Control');
if (cacheControl && layoutResponse) {
layoutResponse.CacheControl = cacheControl;
}
return {
isRedirect: false,
layout: layoutResponse
};
}
static async getTemplates(args) {
const apiPath = RestClient.getSystemRoutePath();
const wholeUrl = `${RootUrlService.getServerCmsUrl()}/${apiPath}/${args.type}/Default.GetPageTemplates(selectedPages=[${args.selectedPages.map(x => `'${x}'`).join(',')}])${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
if (process.env.NODE_ENV === 'test') {
const additionalHeaders = {
'X-SFRENDERER-PROXY': 'true',
'X-SFRENDERER-PROXY-NAME': RENDERER_NAME
};
args.additionalHeaders = Object.assign(args.additionalHeaders || {}, additionalHeaders);
}
return RestClient.sendRequest({ url: wholeUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData }).then(x => x.value);
}
static async getState(args) {
const wholeUrl = `${RestClient.buildItemBaseUrl(args.type)}(${args.id})/Default.GetState()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return RestClient.sendRequest({ url: wholeUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData });
}
static async changeTemplate(args) {
const wholeUrl = `${RootUrlService.getServerCmsUrl()}/sf/system/${ServiceMetadata.getSetNameFromType(args.type)}/Default.ChangePageTemplate()${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
const data = {
selectedPages: args.selectedPages,
templateId: args.templateId ?? EMTPY_GUID,
templateName: args.templateName
};
return RestClient.sendRequest({ url: wholeUrl, method: 'POST', data, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData });
}
static async getTemplatesStatistics(args) {
const apiPath = RestClient.getSystemRoutePath();
args.additionalQueryParams = args.additionalQueryParams || {};
args.additionalQueryParams['@param'] = `[${args.templateNames.map(x => `'${x}'`).join(',')}]`;
const wholeUrl = `${RootUrlService.getServerCmsUrl()}/${apiPath}/pages/Default.GetTemplateStatistics(templateNames=@param, renderer='${RENDERER_NAME}')${RestClient.buildQueryParams(RestClient.getQueryParams(undefined, args.additionalQueryParams))}`;
return RestClient.sendRequest({ url: wholeUrl, headers: args.additionalHeaders, additionalFetchData: args.additionalFetchData }).then(x => x.value);
}
static getSimpleFields(type, fields) {
let star = '*';
if (fields != null && fields.length === 1 && fields[0] === star) {
return [star];
}
let simpleFields = ServiceMetadata.getSimpleFields(type);
return fields.filter(x => simpleFields.some(y => y === x));
}
static getRelatedFields(type, fields) {
let star = '*';
if (fields != null && fields.length === 1 && fields[0] === star) {
return [star];
}
const result = [];
const relatedFields = ServiceMetadata.getRelationFields(type);
const pattern = /(?<fieldName>.+?)\((?<nested>.+)\)/;
fields.forEach((field) => {
const fieldMatch = field.match(pattern);
if (!fieldMatch && relatedFields.some(x => x === field)) {
result.push(field);
}
else if (fieldMatch && fieldMatch.groups) {
const fieldName = fieldMatch.groups['fieldName'];
if (relatedFields.some(x => x === fieldName)) {
const innerFields = fieldMatch.groups['nested'];
const relatedFieldsInput = this.parseInnerFields(innerFields.replaceAll(' ', ''));
const relatedTypeName = ServiceMetadata.getRelatedType(type, fieldName);
if (relatedTypeName) {
let relatedSimpleFields = ServiceMetadata.getSimpleFields(relatedTypeName);
relatedSimpleFields = relatedFieldsInput.filter(x => relatedSimpleFields.some(y => y === x));
let simpleFieldsJoined = null;
if (relatedSimpleFields.length > 0) {
simpleFieldsJoined = relatedSimpleFields.join(',');
simpleFieldsJoined = `$select=${simpleFieldsJoined}`;
}
const relatedRelationFields = RestClient.getRelatedFields(relatedTypeName, relatedFieldsInput);
let relatedRelationFieldsJoined = null;
if (relatedRelationFields.length > 0) {
relatedRelationFieldsJoined = relatedRelationFields.join(',');
relatedRelationFieldsJoined = `$expand=${relatedRelationFieldsJoined}`;
}
let resultString = null;
if (relatedRelationFieldsJoined && simpleFieldsJoined) {
resultString = `${fieldName}(${simpleFieldsJoined};${relatedRelationFieldsJoined})`;
}
else if (relatedRelationFieldsJoined) {
resultString = `${fieldName}(${relatedRelationFieldsJoined})`;
}
else if (simpleFieldsJoined) {
resultString = `${fieldName}(${simpleFieldsJoined})`;
}
if (resultString) {
result.push(resultString);
}
}
}
}
});
return result;
}
static parseInnerFields(input) {
const allFields = [];
let fieldStartIndex = 0;
let charIterator = 0;
let openingBraceCounter = 0;
let closingBraceCounter = 0;
for (let i = 0; i < input.length; i++) {
charIterator++;
const character = input[i];
if (character === '(') {
openingBraceCounter++;
}
if (character === ')') {
closingBraceCounter++;
}
if (character === ',') {
if (openingBraceCounter > 0 && openingBraceCounter === closingBraceCounter) {
let relatedField = input.substring(fieldStartIndex, fieldStartIndex + charIterator - fieldStartIndex - 1).trim();
allFields.push(relatedField);
fieldStartIndex = charIterator;
openingBraceCounter = 0;
closingBraceCounter = 0;
}
else if (openingBraceCounter === 0 && closingBraceCounter === 0) {
let basicField = input.substring(fieldStartIndex, fieldStartIndex + charIterator - fieldStartIndex - 1).trim();
allFields.push(basicField);
fieldStartIndex = charIterator;
}
}
}
if (fieldStartIndex < charIterator) {
let lastField = input.substring(fieldStartIndex, fieldStartIndex + charIterator - fieldStartIndex).trim();
allFields.push(lastField);
}
return allFields;
}
static buildQueryParams(queryParams) {
if (!queryParams) {
return '';
}
if (!queryParams) {
queryParams = {};
}
if (typeof window === 'undefined') {
const queryParamsFromServerContext = getQueryParamsServerContext();
queryParams = Object.assign({}, queryParamsFromServerContext || {}, queryParams);
}
else {
queryParams = Object.assign({}, RestClient.contextQueryParams || {}, queryParams);
}
let result = '';
Object.keys(queryParams).forEach((key) => {
const value = queryParams[key];
if (value) {
result += `${key}=${value}&`;
}
});
if (result !== '') {
result = '?' + result;
result = result.substring(0, result.length - 1);
}
return result;
}
static addAuthHeaders(cookie, headers) {
if (!!cookie && process.env.NODE_ENV !== 'test') {
headers['Cookie'] = cookie;
}
else if (process.env['SF_ACCESS_KEY']) {
headers['X-SF-Access-Key'] = process.env['SF_ACCESS_KEY'];
}
if (process.env[SF_WEBSERVICE_API_KEY]) {
headers[SF_WEBSERVICE_API_KEY_HEADER] = process.env[SF_WEBSERVICE_API_KEY];
}
}
static getQueryParams(args, queryParams) {
let queryParamsFromArgs = {};
if (args) {
const commonArgs = args;
if (commonArgs) {
if (commonArgs.provider) {
queryParamsFromArgs[QueryParamNames.Provider] = commonArgs.provider;
}
if (commonArgs.culture) {
queryParamsFromArgs[QueryParamNames.Culture] = commonArgs.culture;
}
}
}
if (typeof window === 'undefined') {
const queryParamsFromServerContext = getQueryParamsServerContext();
return Object.assign({}, queryParamsFromServerContext || {}, queryParamsFromArgs, args?.additionalQueryParams || {}, queryParams || {});
}
return Object.assign({}, RestClient.contextQueryParams || {}, queryParamsFromArgs, args?.additionalQueryParams || {}, queryParams || {});
}
static buildHeaders(requestData) {
let headers = { 'X-Requested-With': 'react' };
if ((requestData.method === 'POST' || requestData.method === 'PATCH') && !headers['Content-Type']) {
headers['Content-Type'] = 'application/json';
}
if (typeof window === 'undefined') {
const host = getHostServerContext() || requestData.headers?.host;
const proxyHeaders = getProxyHeaders(host);
Object.keys(proxyHeaders).forEach((headerKey) => {
headers[headerKey] = proxyHeaders[headerKey];
});
}
if (!requestData.headers) {
return headers;
}
return Object.assign(headers, requestData.headers);
}
static async sendRequest(request, throwErrorAsJson) {
const headers = this.buildHeaders(request);
const headerKeys = Object.keys(headers).map(x => x.toLowerCase());
const serverSideHeaders = await getFilteredServerSideHeaders();
if (serverSideHeaders) {
Object.entries(serverSideHeaders).forEach(([headerKey, headerValue]) => {
if (!headerKeys.includes(headerKey.toLowerCase())) {
headers[headerKey] = headerValue;
}
});
}
const cookie = await getServerSideCookie();
RestClient.addAuthHeaders(cookie, headers);
request.method = request.method || 'GET';
let args = { headers, method: request.method };
if (request.data && headers['Content-Type'] === 'application/json') {
args.body = JSON.stringify(request.data);
}
if (headers['Content-Encoding'] === 'base64') {
args.body =