@oracle/content-management-sdk
Version:
Oracle Content Management JavaScript SDK
1,248 lines (1,172 loc) • 116 kB
JavaScript
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
_setPrototypeOf(subClass, superClass);
}
function _setPrototypeOf(o, p) {
_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
o.__proto__ = p;
return o;
};
return _setPrototypeOf(o, p);
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
function _unsupportedIterableToArray(o, minLen) {
if (!o) return;
if (typeof o === "string") return _arrayLikeToArray(o, minLen);
var n = Object.prototype.toString.call(o).slice(8, -1);
if (n === "Object" && o.constructor) n = o.constructor.name;
if (n === "Map" || n === "Set") return Array.from(o);
if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen);
}
function _arrayLikeToArray(arr, len) {
if (len == null || len > arr.length) len = arr.length;
for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i];
return arr2;
}
function _createForOfIteratorHelperLoose(o, allowArrayLike) {
var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
if (it) return (it = it.call(o)).next.bind(it);
if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") {
if (it) o = it;
var i = 0;
return function () {
if (i >= o.length) return {
done: true
};
return {
done: false,
value: o[i++]
};
};
}
throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
/**
* Copyright (c) 2017, 2022, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
*/
// jshint ignore: start
/* eslint-disable class-methods-use-this */
/* eslint-disable max-classes-per-file */
/* eslint-disable prefer-promise-reject-errors */
/* eslint-disable no-prototype-builtins */
/* eslint-disable global-require */
/* eslint-disable import/no-dynamic-require */
/* eslint-disable no-restricted-syntax */
// Detect whether we're running in a browser or in NodeJS.
// Note that some other environments (e.g. React-Native) are not detected and may not
// work properly.
var isNodeJS = typeof window === 'undefined' && typeof process === 'object';
//
// ------------------------------- Cross-browser Utility functions ---------------------
//
var utils = {
bind: function bind(func, owner) {
// eslint-disable-next-line func-names
return function () {
return func.apply(owner, [].slice.call(arguments));
};
},
extend: function extend(dest, orig) {
for (var prop in orig) {
if (orig.hasOwnProperty(prop)) {
// eslint-disable-next-line no-param-reassign
dest[prop] = orig[prop];
}
}
return dest;
}
};
//
// ------------------------------- Internal Logger -------------------------------------
//
var logger = function logger() {
var theLogger = {
logLevel: 'none',
logLevels: ['error', 'warn', 'info', 'debug', 'log']
};
var dontLog = function dontLog( /* message */) {}; // swallow messages - default
theLogger.updateLogger = function updateLogger(newLogger) {
if (newLogger) {
// setup loggers for each logLevel
for (var i = 0; i < this.logLevels.length; i += 1) {
var logLevel = theLogger.logLevels[i];
theLogger[logLevel] = typeof newLogger[logLevel] === 'function' ? utils.bind(newLogger[logLevel], newLogger) : dontLog;
}
}
};
theLogger.updateLogger({}); // setup with no logging
return theLogger;
}();
//
// ------------------------------- Internal Implementation -------------------------------------
//
// RequireJS config support
var requireConfig = {
requirePaths: {},
getContentLayoutRequirePath: function getContentLayoutRequirePath(info) {
var contentServer = info.contentServer;
var cacheBuster = typeof info.cacheBuster === 'object' ? info.cacheBuster : {
layoutKey: info.cacheBuster,
systemKey: info.cacheBuster
};
var layoutCacheBuster = cacheBuster.layoutKey ? "/" + cacheBuster.layoutKey : '';
var systemCacheBuster = cacheBuster.systemKey ? "/" + cacheBuster.systemKey : '';
// setup require config for this Content client's layouts if not already created
if (!this.requirePaths[contentServer]) {
// generate a unique require path to Content Layouts for this client
var baseRequirePath = "contentLayoutPath" + Math.floor(100000000 + Math.random() * 900000000);
var paths = {};
// create paths for 'published' and 'draft'
paths[baseRequirePath + "published"] = contentServer + "/_compdelivery" + layoutCacheBuster;
paths[baseRequirePath + "draft"] = contentServer + "/_themes/_components" + layoutCacheBuster;
paths[baseRequirePath + "system"] = contentServer + "/_sitescloud" + systemCacheBuster + "/sitebuilder/contentlayouts";
// cache the base requireJS path for re-use with this content server
this.requirePaths[contentServer] = baseRequirePath;
// configure require to support these paths
requirejs.config({
paths: paths
});
}
return this.requirePaths[contentServer];
},
preloadContentLayout: function preloadContentLayout(requireLayout, resolve, reject) {
// require in the content layout to populate the require cache but don't render the item
require([requireLayout], function /* ContentLayout */
() {
// resolve the promise
resolve();
}, function (err) {
// note that can't find the layout and reject
logger.warn('ContentClient.renderLayout: Unable to render the layout. Ensure you can access the layout: If running against published content, that the layout has been published. If draft, that you are logged onto the Sites server');
reject("Failed to get layout: " + requireLayout + " with error: " + err);
});
},
renderContentLayout: function renderContentLayout(requireLayout, layoutParams, container, resolve, reject) {
// require in the render.js for the layout
require([requireLayout], function (ContentLayout) {
var renderLayout = new ContentLayout(layoutParams);
// call render to add the component to the page
var renderPromise = renderLayout.render(container);
if (typeof renderPromise === 'object' && typeof renderPromise.then === 'function') {
renderPromise.then(function /* status */
() {
// resolve the passed in Promise
resolve();
}, function (errorStatus) {
// failed to render, reject the passed in promise
reject(errorStatus);
});
} else {
// simply resolve the passed in promise
resolve();
}
}, function (err) {
// note that can't find the layout and reject
logger.warn('ContentClient.renderLayout: Unable to render the layout. Ensure you can access the layout: If published, that the layout has been published. If draft, that you are logged onto the Sites server');
reject("failed to get layout: " + requireLayout + " with error: " + err);
});
}
};
// Node specific API
var RestAPINode = /*#__PURE__*/function () {
function RestAPINode(args) {
Object.assign(this, args);
}
var _proto = RestAPINode.prototype;
_proto.extractServer = function extractServer(contentServerURL) {
var url = require('url');
var contentServer = contentServerURL || 'http://localhost';
var parsedURL = url.parse(contentServer);
// extract the server part of the URL
return parsedURL.protocol + "//" + parsedURL.hostname + (parsedURL.port ? ":" + parsedURL.port : '');
};
_proto.callRestServer = function callRestServer(targetURL, restArgs) {
try {
var _temp2 = function _temp2(token) {
var nodePromise = new Promise(function (resolve, reject) {
// parse the URL
var options = url.parse(targetURL);
var protocolCall = protocolCalls[options.protocol || 'https:'];
var restRequest;
/* jshint node: true */
var proxyType = options.protocol || 'https:';
var proxy = proxyType === 'https:' ? process.env.oce_https_proxy : process.env.oce_http_proxy;
/* jshint node: false */
if (proxy) {
try {
logger.debug("Using proxy: " + proxy);
// eslint-disable-next-line import/no-unresolved
// eslint-disable-next-line import/no-extraneous-dependencies
var HttpsProxyAgent = require('https-proxy-agent');
logger.debug('Loaded proxy agent');
var agent = new HttpsProxyAgent(proxy);
logger.debug("Using proxy: " + proxy + " connecting to " + targetURL);
options.agent = agent;
} catch (e) {
logger.warn("Could not initialize https-proxy-agent. Is the package installed in your application?.\n Making direct call to " + targetURL);
}
}
// define function to call the consumer's "beforeSend" method if one was defined,
// to add additional values to the request options
var beforeSendOK = function beforeSendOK(currentOptions) {
return new Promise(function (bsResolve, bsReject) {
try {
// if the consumer specified a "beforeSend" callback function then call it
// if the result is a promise then resolve the promise
if (typeof restArgs.beforeSend === 'function') {
var beforeSendResult = restArgs.beforeSend(currentOptions);
if (beforeSendResult && typeof beforeSendResult.then === 'function') {
return beforeSendResult.then(function () {
return bsResolve(beforeSendResult);
})["catch"](function (e) {
return bsReject({
// error in user code, reject the call
status: e,
statusText: 'Error in beforeSend() callback promise'
});
});
}
return bsResolve(beforeSendResult === undefined || beforeSendResult);
}
return bsResolve(true);
} catch (e) {
// error in user code, reject the call
return bsReject({
status: e,
statusText: 'Error in beforeSend() callback'
});
}
});
};
// function to handle request response into JSON
var requestResponse = function requestResponse(response) {
var chunksArray = [];
var responseStatus = response.statusCode;
response.on('data', function (chunk) {
chunksArray.push(chunk);
});
response.on('end', function () {
// This is needed because the chunks may contain UTF-8 strings and
// concatenating them into a string as we receive each chunk can
// lead to corrupted characters.
var body = "" + Buffer.concat(chunksArray);
if (responseStatus >= 200 && responseStatus < 300) {
try {
var jsonResponse = JSON.parse(body);
logger.debug(jsonResponse);
resolve(jsonResponse);
} catch (e) {
reject({
error: body
});
}
} else {
// return the error response object to be handled by calling function
logger.debug("HTTP call failed. Response code " + responseStatus + "\n" + body);
reject(response);
}
});
};
// store the call type in options
options.method = restArgs.method.toUpperCase() || '';
options.headers = {};
if (token && token !== '') {
options.headers.Authorization = token;
}
if (options.method === 'GET' && targetURL) {
// handle 'GET' request
// allow the user to update the "options"
beforeSendOK(options).then(function (result) {
if (result) {
restRequest = protocolCall.get(options, requestResponse);
} else {
// aborted the call
logger.debug('Call aborted by beforeSend');
reject({
error: 'call aborted by beforeSend()'
});
}
});
} else if (options.method === 'POST' && restArgs.noCSRFToken && restArgs.postData) {
// handle 'POST' request
// setup the JSON body
var bodyString = JSON.stringify(restArgs.postData);
options.headers['Content-Type'] = 'application/json';
options.headers['X-Requested-With'] = 'XMLHttpRequest';
options.headers['Content-Length'] = bodyString.length;
// do http or https get writing the bodyString
beforeSendOK(options).then(function (result) {
if (result) {
restRequest = protocolCall.request(options, requestResponse).write(bodyString);
} else {
// aborted the call
logger.debug('Call aborted by beforeSend');
reject({
error: 'call aborted by beforeSend()'
});
}
});
} else {
// unsupported method
reject({
error: "unsupported REST request: " + JSON.stringify(restArgs)
});
}
// set up common handling
if (restRequest) {
// handle errors
restRequest.on('error', function (error) {
reject({
error: error
});
});
// handle timeout
restRequest.on('socket', function (socket) {
socket.setTimeout(restArgs.timeout);
socket.on('timeout', function () {
reject({
error: "request timed out after: " + restArgs.timeout
});
});
});
} else {
logger.debug('no restRequest');
}
});
// return the promise
return Promise.resolve(nodePromise).then(function (response2) {
return typeof self.coerceData === 'function' ? self.coerceData(response2) : Promise.resolve(response2);
});
};
var _this = this;
var self = _this;
logger.debug("_rest.callRestServer: Calling " + restArgs.method + " request with:");
logger.debug(targetURL);
logger.debug(restArgs);
// require in the node REST call dependencies
var protocolCalls = {
'http:': require('http'),
'https:': require('https')
};
var url = require('url');
var _temp = restArgs.tokenManager !== null && restArgs.tokenManager !== undefined;
return Promise.resolve(_temp ? Promise.resolve(restArgs.tokenManager.getAuthValue()).then(_temp2) : _temp2(restArgs.authorization));
} catch (e) {
return Promise.reject(e);
}
};
return RestAPINode;
}(); // Browser specific API
var RestAPIBrowser = /*#__PURE__*/function () {
function RestAPIBrowser(args) {
Object.assign(this, args);
}
var _proto2 = RestAPIBrowser.prototype;
_proto2.extractServer = function extractServer(contentServerURL) {
// use the server URL if given, or default to the window URL
var contentServer = contentServerURL || window.location && window.location.href;
var parsedURL = document.createElement('a');
// parse the URL
parsedURL.href = contentServer;
// extract the server part of the URL
return parsedURL.protocol + "//" + parsedURL.hostname + (parsedURL.port ? ":" + parsedURL.port : '');
};
_proto2.callRestServer = function callRestServer(targetURL, restArgs) {
try {
var _this2 = this;
var self = _this2;
logger.debug("_rest.callRestServer: Calling " + restArgs.method + " request with:");
logger.debug(restArgs);
var xmlHTTPPromise = new Promise(function (resolve, reject) {
// define function to call the consumer's "beforeSend" method if one was defined,
// to add additional values to the request options
var beforeSendOK = function beforeSendOK(currentXHR) {
return new Promise(function (bsResolve, bsReject) {
try {
// if the consumer specified a "beforeSend" callback function then call it
// if the result is a promise then resolve the promise
if (typeof restArgs.beforeSend === 'function') {
var beforeSendResult = restArgs.beforeSend(currentXHR);
if (beforeSendResult && typeof beforeSendResult.then === 'function') {
return beforeSendResult.then(function () {
return bsResolve(beforeSendResult);
})["catch"](function (e) {
return bsReject({
// error in user code, reject the call
status: e,
statusText: 'Error in beforeSend() callback promise'
});
});
}
return bsResolve(beforeSendResult === undefined || beforeSendResult);
}
return bsResolve(true);
} catch (e) {
// error in user code, reject the call
return bsReject({
status: e,
statusText: 'Error in beforeSend() callback'
});
}
});
};
// create the XMLHttpRequest object and parameters
var xhr = new XMLHttpRequest();
var xhrParams = {
method: restArgs.method && restArgs.method.toUpperCase() || '',
url: targetURL,
timeout: restArgs.timeout,
headers: {}
};
var doRequest = true;
// add authorization header, if provided
if (restArgs.authorization) {
// for /published API calls, only add header if not 'session' or
// 'anonymous' (e.g. Basic Auth in non-POD environments)
if (restArgs.contentType !== 'published' || ['session', 'anonymous'].indexOf(restArgs.authorization) === -1) {
xhrParams.headers = {
Authorization: restArgs.authorization
};
}
}
// add the individual request parameters
if (xhrParams.method === 'GET' && xhrParams.url) {
// 'GET' request
} else if (xhrParams.method === 'POST' && xhrParams.url && restArgs.noCSRFToken && restArgs.postData) {
// 'POST' request
xhrParams.headers['Content-Type'] = 'application/json; charset=UTF-8';
xhrParams.headers['X-Requested-With'] = 'XMLHttpRequest';
xhrParams.data = restArgs.postData;
} else if (['POST', 'PUT'].indexOf(xhrParams.method) !== -1 && xhrParams.url && restArgs.postData) {
// 'POST'/'PUT' request with X-CSRF-Token
xhrParams.headers['Content-Type'] = 'application/json; charset=UTF-8';
xhrParams.headers['X-Requested-With'] = 'XMLHttpRequest';
xhrParams.headers['X-CSRF-Token'] = self.getCSRFToken(xhrParams.url);
xhrParams.data = restArgs.postData;
} else if (xhrParams.method === 'DELETE' && xhrParams.url) {
// 'DELETE' request with X-CSRF-Token
xhrParams.headers['X-CSRF-Token'] = self.getCSRFToken(xhrParams.url);
} else {
logger.error('_rest.callRestServer: invalid arguments:');
logger.error(restArgs);
reject({
status: 400,
statusText: "Expected to see arguments:\n { \"method\": \"GET/POST/PUT/DELETE\", \"url\": url } but received: " + JSON.stringify(restArgs)
});
// note that no request to make
doRequest = false;
}
// execute the request
if (doRequest) {
// handle the promise actions for the responses
xhr.onload = function onload() {
if (this.status >= 200 && this.status < 300) {
resolve(JSON.parse(xhr.response ? xhr.response : xhr.responseText));
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function onerror() {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.ontimeout = function ontimeout() {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.open(xhrParams.method, xhrParams.url);
// add in the headers
for (var header in xhrParams.headers) {
if (xhrParams.headers.hasOwnProperty(header)) {
xhr.setRequestHeader(header, xhrParams.headers[header]);
}
}
// VBCS adapts XMLHttpRequest to use fetch but doesn't support timeout.
// This check silently ignores timeouts if they are not supported.
var timeoutOverridden = Object.getOwnPropertyDescriptor(xhr, 'timeout');
if (timeoutOverridden === undefined || timeoutOverridden.writable) {
xhr.timeout = xhrParams.timeout; // for IE, need to set timeout after open()
}
// handle the beforeSend() callback and then make the request
beforeSendOK(xhr).then(function (result) {
if (result) {
if (xhrParams.data) {
xhr.send(JSON.stringify(xhrParams.data));
} else {
xhr.send();
}
}
});
}
});
// return the promise
return Promise.resolve(xmlHTTPPromise).then(function (response) {
return typeof self.coerceData === 'function' ? self.coerceData(response) : Promise.resolve(response);
});
} catch (e) {
return Promise.reject(e);
}
};
return RestAPIBrowser;
}(); // Content REST API handle '/content' prefix
var ContentAPIConfiguration = {
contextRoot: '/content',
defaultVersion: 'v1',
supportedVersions: [{
semanticVersion: '1.0.0',
contentVersion: 'v1'
}, {
semanticVersion: '1.1.0',
contentVersion: 'v1.1'
}],
state: {
published: 'published',
draft: 'management',
preview: 'preview'
}
};
var ContentAPI = /*#__PURE__*/function () {
function ContentAPI() {
// Make these objects part of the interface of this class
if (isNodeJS) {
this.restAPI = new RestAPINode(ContentAPIConfiguration);
} else {
this.restAPI = new RestAPIBrowser(ContentAPIConfiguration);
}
}
var _proto3 = ContentAPI.prototype;
_proto3.extractServer = function extractServer(contentServerURL) {
return this.restAPI.extractServer(contentServerURL);
};
_proto3.callRestServer = function callRestServer(targetURL, restArgs) {
try {
var _this3 = this;
return Promise.resolve(_this3.restAPI.callRestServer(targetURL, restArgs));
} catch (e) {
return Promise.reject(e);
}
};
ContentAPI.getContentVersion = function getContentVersion(caller, requestedVersion) {
// get semantic version
var regEx = /\s*((([<>]?=?)\s*(v)?([0-9]+)(\.([0-9]+))?(\.([0-9]+))?))\s*/g;
var parsedVersion = regEx.exec(requestedVersion || '0.0.0') || [];
var semanticVersion = (parsedVersion[5] || '0') + "." + (parsedVersion[7] || '0') + "." + (parsedVersion[9] || '0');
// get the Supported Version based on the semantic version
for (var i = 0; i < ContentAPIConfiguration.supportedVersions.length; i += 1) {
if (ContentAPIConfiguration.supportedVersions[i].semanticVersion === semanticVersion) {
return ContentAPIConfiguration.supportedVersions[i].contentVersion;
}
}
// if we got to here, no version match
// warn user that non-supported version requested
logger.warn("Content SDK: \"" + caller + "\" has unrecognized Content Version: \"" + requestedVersion + "\".\n Defaulting to: version=\"" + this.defaultVersion + "\".\nTo avoid this message, use one of the supported versions when creating a content client: \n" + JSON.stringify(this.supportedVersions));
// return the default version
return this.defaultVersion;
};
_proto3.getCSRFToken = function getCSRFToken( /* requestURL */
) {
// Required for Management API
return 'CSRFToken';
};
_proto3.createPrefix = function createPrefix(args) {
// standard prefix is: "http://<server>:<port>/content/[management||publish]/api/[v1|v1.1]"
return args.contentServer + ContentAPIConfiguration.contextRoot + "/" + ContentAPIConfiguration.state[args.contentType] + "/api/" + this.contentVersion;
};
_proto3.createSuffix = function createSuffix(args) {
// standard suffix is:
// {search string}&[access-token|channelToken]={channelToken}&cb={cacheBuster}
var search = args.search || '';
var channelToken = args.channelToken ? this.properties.tokenName + "=" + args.channelToken : '';
var cacheBusterValue = typeof args.cacheBuster === 'object' ? args.cacheBuster.contentKey : args.cacheBuster;
var cacheBuster = cacheBusterValue ? "cb=" + cacheBusterValue : '';
var suffix = '';
// add in search
suffix += search;
// add in channelToken
suffix += (suffix && channelToken ? '&' : '') + channelToken;
// add in cacheBuster
suffix += (suffix && cacheBuster ? '&' : '') + cacheBuster;
return suffix;
}
// Format the fully qualified REST URL
// path: section of the URL beyond the standard REST API
// args:
// contentServer: '<protocol>://<host>:<port>' of the content server
// contentType: [management|published]
// search: search string to add as query string
// channelToken: 'channelToken=<channelToken>' to be added
// cacheBuster: 'cb=<cacheBuster>' to be added
;
_proto3.formatURL = function formatURL(path, restArgs) {
var prefix = this.createPrefix(restArgs);
var suffix = this.createSuffix(restArgs);
var url = prefix + path + (suffix ? (path.indexOf('?') === -1 ? '?' : '&') + suffix : '');
logger.info(url);
return url;
};
_proto3.resolveGetTypesPath = function resolveGetTypesPath( /* args */
) {
return '/types';
}
// args.typeName: restrict aggregate query to specific types
;
_proto3.resolveGetTypePath = function resolveGetTypePath(args) {
return "/types/" + args.typeName;
};
_proto3.isDigitalAsset = function isDigitalAsset(id) {
return /^DigitalAsset_/i.test(id) || id.length === 36 && (/^CONT/.test(id) || /^CORE/.test(id));
};
_proto3.getRenditionURL = function getRenditionURL(itemGUID, slug, renditionName, restArgs) {
var url = '';
if (slug || itemGUID) {
if (slug || this.isDigitalAsset(itemGUID)) {
// Content URL
var format = restArgs.format;
var download = restArgs.download;
var cacheBusterValue = typeof restArgs.cacheBuster === 'object' ? restArgs.cacheBuster.contentKey : restArgs.cacheBuster;
var joinChar = '?'; // character to use to join query parameters
// secure and non-secure assets now use the same path
var digitalAssets = restArgs.secureContent ? this.properties.secureAssetURLName : this.properties.assetURLName;
var rendition = renditionName || this.properties.digitalAssetDefault;
var identifier = itemGUID || ".by.slug/" + slug;
url = this.createPrefix(restArgs) + "/" + digitalAssets + "/" + identifier + "/" + rendition;
// add in any query parameters
if (cacheBusterValue) {
url += joinChar + "cb=" + cacheBusterValue;
joinChar = '&';
}
if (format) {
url += joinChar + "format=" + format;
joinChar = '&';
}
if (download) {
url += joinChar + "download=true";
joinChar = '&';
} else if (download === false) {
url += joinChar + "download=false";
joinChar = '&';
}
if (restArgs.contentType === 'published' && restArgs.channelToken) {
url += joinChar + this.properties.tokenName + "=" + restArgs.channelToken;
joinChar = '&';
}
} else {
// Documents URL
url = restArgs.contentServer + "/documents/file/" + itemGUID;
}
}
logger.info(url);
return url;
};
_proto3.makeQueryParameters = function makeQueryParameters(args) {
var queryParams = utils.extend({}, args);
var searchParams = {
postData: {},
getData: '',
assetVersion: ''
};
var parameters = '';
var search = queryParams.search;
// remove Content SDK arguments and old properties we don't want to add as query parameters
delete queryParams.ids;
delete queryParams.IDs;
delete queryParams.id;
delete queryParams.ID;
delete queryParams.itemGUID;
delete queryParams.itemGUIDs;
delete queryParams.slug;
delete queryParams.timeout;
delete queryParams.search;
delete queryParams.types;
delete queryParams.beforeSend;
delete queryParams.contentType;
delete queryParams.language;
// define the string to separate each parameter on the URL
var separator = '';
// construct the URL query string from the properties passed in
for (var property in queryParams) {
if (queryParams.hasOwnProperty(property)) {
// if it's a valid URL property, include it
if (property === encodeURI(property)) {
var propVal = queryParams[property];
// convert the "orderBy" array property if required
// CaaS only supports a single orderBy value, so just use the first item in the array
if (property === 'orderBy' && Array.isArray(propVal) && propVal.length === 1) {
var order = propVal[0].order && propVal[0].order.toLowerCase() || '';
var orderEntry = order ? ":" + (order === 'des' ? 'desc' : order) : '';
propVal = propVal[0].name + orderEntry;
}
if (property !== 'expand') {
if (property === 'version') {
if (propVal !== undefined && propVal) {
searchParams.assetVersion = propVal;
}
} else if (typeof propVal !== 'object') {
// we're only handling scalar parameters in GET requests
parameters += separator + property + "=" + encodeURI(propVal);
separator = '&';
}
}
}
}
}
// add in any old style 'search' properties
parameters += search ? separator + search : '';
// note that 'GET' call should be used and pass back the parameters
searchParams.method = 'GET';
searchParams.getData = parameters;
// note if should use aggregate call
// aggregate calls should be used for "itemDepth" != 0 and "expand" parameters
searchParams.useAggregate = queryParams.itemDepth || queryParams.expand;
return searchParams;
};
return ContentAPI;
}(); // Content API v1: Inherit from base with v1 specific overrides
var ContentApiV1Impl = /*#__PURE__*/function (_ContentAPI) {
_inheritsLoose(ContentApiV1Impl, _ContentAPI);
function ContentApiV1Impl() {
var _this4;
_this4 = _ContentAPI.call(this) || this;
_this4.contentVersion = 'v1';
_this4.properties = {
tokenName: 'access-token',
digitalAssetDefault: 'default',
assetURLName: 'digital-assets',
secureAssetURLName: 'secure-digital-assets'
};
return _this4;
}
var _proto4 = ContentApiV1Impl.prototype;
_proto4.resolveGetItemListPath = function resolveGetItemListPath(args) {
return "/items" + (args.useAggregate ? '/aggregate' : '') + (args.types ? "?field:type:equals=" + args.types : '');
};
_proto4.resolveGetItemPath = function resolveGetItemPath(args) {
return "/items/" + args.itemGUID + (args.useAggregate ? '/aggregate' : '');
};
_proto4.resolveSearchPath = function resolveSearchPath( /* args */
) {
return '/items/queries';
};
_proto4.resolveGetBulkItemListPath = function resolveGetBulkItemListPath(args) {
// args.itemGUIDs: array of IDs to add to the URL
return "/items/bulk" + (args.useAggregate ? '/aggregate' : '') + "?ids=" + args.itemGUIDs.join(',');
};
return ContentApiV1Impl;
}(ContentAPI); // Content API v1.1: Inherit from v1 with v1.1 specific overrides
var ContentApiV11Impl = /*#__PURE__*/function (_ContentApiV1Impl) {
_inheritsLoose(ContentApiV11Impl, _ContentApiV1Impl);
function ContentApiV11Impl(contentVersion) {
var _this5;
_this5 = _ContentApiV1Impl.call(this) || this;
if (contentVersion) {
_this5.requestedContentVersion = contentVersion;
}
_this5.contentVersion = 'v1.1';
_this5.properties = {
tokenName: 'channelToken',
digitalAssetDefault: 'native',
assetURLName: 'assets',
secureAssetURLName: 'assets'
};
return _this5;
}
var _proto5 = ContentApiV11Impl.prototype;
_proto5.resolveGetItemListPath = function resolveGetItemListPath(args) {
var itemListURL = '/items';
var joinChar = '?';
// add in query
if (args.types) {
itemListURL += joinChar + "field:type:equals=" + args.types;
joinChar = '&';
}
// add in aggregate
if (args.useAggregate) {
itemListURL += joinChar + "expand=\"all\"";
joinChar = '&';
}
return itemListURL;
};
_proto5.resolveGetItemPath = function resolveGetItemPath(args) {
var language = args.language ? "/variations/language/" + args.language + "?fields=all" : '';
var nextParam = language ? '&' : '?';
var aggregate = args.useAggregate ? nextParam + "expand=" + args.useAggregate : '';
var slug = args.slug ? ".by.slug/" + args.slug : '';
// Ignored if language is given to not create an invalid URL
var versionStr = '';
if (!language) {
if (args.assetVersion) {
versionStr = "/versions/" + args.assetVersion;
}
}
if (args.itemGUID) {
// Get Published Item by ID:
// .../items/{id}
//
// Get Published Item by ID for specified language:
// .../items/{id}/variations/language/{languageValue}
return "/items/" + args.itemGUID + versionStr + language + aggregate;
}
// Get Published Item by slug:
// .../items/.by.slug/{slug}
//
// Get published item by slug for specified language:
// .../items/.by.slug/{slug}/variations/language/{languageValue}
return "/items/" + slug + versionStr + language + aggregate;
}
// Get categories for a given taxonomy
;
_proto5.resolveQueryTaxonomyCategoriesPath = function resolveQueryTaxonomyCategoriesPath(args) {
return "/taxonomies/" + args.taxonomyGUID + "/categories";
}
// get details about a given taxonomy category
;
_proto5.resolveQueryTaxonomyCategoriesDetails = function resolveQueryTaxonomyCategoriesDetails(args) {
return "/taxonomies/" + args.taxonomyGUID + "/categories/" + args.categoryGUID;
};
_proto5.resolveGetTaxonomiesPath = function resolveGetTaxonomiesPath( /* args */
) {
return '/taxonomies';
};
_proto5.resolveGetRecommendationPath = function resolveGetRecommendationPath(args) {
if (args.id) {
return "/personalization/recommendationResults/.by.id/" + args.id;
}
return "/personalization/recommendationResults/" + args.apiName;
};
_proto5.resolveSearchPath = function resolveSearchPath( /* args */
) {
return '/items';
};
_proto5.resolveGetBulkItemListPath = function resolveGetBulkItemListPath(args) {
// args.itemGUIDs: array of IDs to add to the URL
var idQuery = "(id eq \"" + args.itemGUIDs.join('" or id eq "') + "\")";
var languageQuery = args.language ? "(language eq \"" + args.language + "\")" : '';
return "/items?q=" + (languageQuery ? "(" + idQuery + " and " + languageQuery + ")" : idQuery);
};
_proto5.coerceData = function coerceData(response) {
var self = this;
return new Promise(function (resolve /* , reject */) {
// if the requested content version is v1, coerce data from v1.1 to v1 format
if (self.requestedContentVersion === 'v1') {
if (typeof response.fields === 'object') {
// coerce single item
if (!response.data) {
response.data = response.fields;
}
} else if (Array.isArray(response.items)) {
// coerce array of items
response.items.forEach(function (item) {
if (typeof item.fields === 'object' && !item.data) {
// eslint-disable-next-line no-param-reassign
item.data = item.fields;
}
});
}
}
// resolve with updated data
return resolve(response);
});
};
return ContentApiV11Impl;
}(ContentApiV1Impl); // setup the REST API, content version is handled within the underlying REST call
var restAPIFactory = {
createRestAPI: function createRestAPI(contentVersion) {
var validContentVersion = ContentAPI.getContentVersion('ContentSDK create content client', contentVersion);
if (validContentVersion === 'v1') {
// only support v1.1 now, so create a v1.1 API and set the requestd content version to v1
// we will coerce the data on fetch to be in the v1 format
// ToDo: wait for deprecation and fix up tests that are expecting
// 'v1' in the URL before making this change
return new ContentApiV11Impl('v1');
}
return new ContentApiV11Impl();
}
};
var OptionsValidation = /*#__PURE__*/function () {
function OptionsValidation() {}
// A function to validate some of the options being passed into the SDK
OptionsValidation.processOptions = function processOptions(options) {
var validDeliveryOptions = [OptionsValidation.deliveryREST];
var validPreviewOptions = [OptionsValidation.previewREST, OptionsValidation.managementREST];
var defaultOptions = {
deliveryClientAPI: OptionsValidation.deliveryREST,
previewClientAPI: OptionsValidation.managementREST
};
if (options && typeof options === 'object') {
// Value unspecified. Use default
if (!options.deliveryClientAPI) {
// eslint-disable-next-line no-param-reassign
options.deliveryClientAPI = defaultOptions.deliveryClientAPI;
} else if (!validDeliveryOptions.includes(options.deliveryClientAPI)) {
throw new Error("options.deliveryClientAPI is invalid. It may only be set to 'deliveryREST'");
}
// Value unspecified. Use default
if (!options.previewClientAPI) {
// eslint-disable-next-line no-param-reassign
options.previewClientAPI = OptionsValidation.previewREST;
} else if (!validPreviewOptions.includes(options.previewClientAPI)) {
throw new Error("options.previewClientAPI is invalid. It may only be set to 'previewREST' or 'managementREST'");
}
return options;
}
return defaultOptions;
};
return OptionsValidation;
}();
// Supported configurations
OptionsValidation.deliveryREST = 'deliveryREST';
OptionsValidation.previewREST = 'previewREST';
OptionsValidation.managementREST = 'managementREST';
/**
* Copyright (c) 2017, 2022, Oracle and/or its affiliates.
* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
*/
/* eslint-disable import/named */
/* eslint-disable import/no-extraneous-dependencies */
/*
* This file contains the TokenManager class, which contains methods used to create and maintain
* authentication tokens to access to an instance of Oracle Content Management.
*
* The constructor of the class takes in OAUTHValues and a tokenString, which represent an object
* containing the clientId, clientSecret, clientScopeUrl, and idpUrl used to create
* access tokens and the direct access token, respectively. If both are provided, the
* OAUTHValues take precedence.
*
* The AUTH environment variable is used to specify the Authentication header value
* (including "Basic"/"Bearer") when the value does not change, corresponding to the tokenString
* in the constructor.
*
* The AUTH_PARAMS environment variable is used to specify the Authentication object values
* to get a new access token on expiry of the old one, corresponding to the OAUTHValues
* in the constructor.
*
* A "delivery client" is used to view content which has been published to a public
* channel or published to a secure channel. The "preview client" is used to view content
* which has been assigned to a channel but has not yet been published.
*
* The minimal information which needs to be specified is the server URL, the rest API version
* to use and the channel token for the channel which contains the data to display in the app.
*
* When previewing content or using content in a secure channel, authentication is required.
* @ignore
*/
var TokenManager = /*#__PURE__*/function () {
function TokenManager(oauthValues, tokenString) {
if (oauthValues !== undefined && oauthValues !== null) {
this.clientId = oauthValues.clientId;
this.clientSecret = oauthValues.clientSecret;
this.clientScopeUrl = oauthValues.clientScopeUrl;
this.idpUrl = oauthValues.idpUrl;
} else {
this.clientId = null;
this.clientSecret = null;
this.clientScopeUrl = null;
this.idpUrl = null;
}
this.expiry = -1;
this.currentToken = tokenString;
}
/**
* Gets the Bearer authorization needed when using preview content or
* content published to a secure channel.
*
* This will create a NEW access_token with a new expiry
*
* This is only called when rendering on the server, therefore we are safe
* to use node-fetch and do not have to have a client version
*/
var _proto = TokenManager.prototype;
_proto.getBearerAuth = function getBearerAuth() {
try {
var _this = this;
// base64 encode CLIENT_ID:CLIENT_SECRET
var authString = _this.clientId + ":" + _this.clientSecret;
var authValue = Buffer.from(authString).toString('base64');
// URL encode the CLIENT_SCOPE_URL
var encodedScopeUrl = encodeURIComponent(_this.clientScopeUrl);
// build the full REST end point URL for getting the access token
var restURL = new URL('/oauth2/v1/token', _this.idpUrl);
// make a request to the server to get the access token
var body = "grant_type=client_credentials&scope=" + encodedScopeUrl;
var options = {
hostname: restURL.hostname,
port: 443,
path: restURL.pathname,
method: 'POST',
headers: {
Authorization: "Basic " + authValue,
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': body.length
}
};
var isNodeJS = typeof window === 'undefined' && typeof process === 'object';
if (isNodeJS) {
return Promise.resolve(new Promise(function (resolve, reject) {
// eslint-disable-next-line global-require
var https = require('https');
var req = https.request(options, function (res) {
var returnData = '';
res.on('data', function (chunk) {
returnData += chunk;
});
res.on('end', function () {
var responseJSON = JSON.parse(returnData);
var accessToken = responseJSON.access_token;
var expiry = responseJSON.expires_in;
resolve({
authHeaderValue: "Bearer " + accessToken,
expiry: expiry
});
});
});
req.on('error', function (error) {
reject(error);
});
req.write(body);
req.end();
}));
}
// Return an empty value if it is not running on a server
return Promise.resolve({
authHeaderValue: ''
});
} catch (e) {
return Promise.reject(e);
}
}
/**
* Returns the auth value for any requests
*/
;
_proto.getAuthValue = function getAuthValue() {
try {
var _temp3 = function _temp3() {
return _this2.currentToken;
};
var _this2 = this;
var _temp2 = function () {
if (_this2.clientId !== null) {
var _temp = function () {
if (_this2.expiry - 5000 < Date.now()) {
return Promise.resolve(_this2.getBearerAuth()).then(function (authDetails) {
var globalAuthValue = authDetails.authHeaderValue;
// Auth Expiry
// calculate expiry, get the current date (in ms), add the expiry ms, then
// create a new Date object, using the adjusted milliseconds time
var currDateMS = Date.now();
currDateMS += authDetails.expiry;
_this2.expiry = new Date(currDateMS);
_this2.currentToken = globalAuthValue;
});
}
}();
if (_temp && _temp.then) return _temp.then(function () {});
}
}();
// if no token exists, create one if OAUTH values given OR
// if the auth token has expired, refresh it, otherwise existing value will be returned
// add a 5 second buffer to the expiry time
// This code only runs if it has the object with the OAUTH server details
return Promise.resolve(_temp2 && _temp2.then ? _temp2.then(_temp3) : _temp3(_temp2));
} catch (e) {
return Promise.reject(e);
}
};
return TokenManager;
}();
//
// ------------------------------- Content Client SDK -------------------------------------
//
/**
* Client object to interact with content published in Oracle Content Management:
* <ul>
* <li>Read the published content items</li>
* <li>Render published content using named content layouts</li>
* </ul>
* @alias ContentDeliveryClient
*/
var ContentDeliveryClientImpl = /*#__PURE__*/function () {
/**
* @param {ClientParameters} args - A JavaScript object containing the parameters
* to create the content delivery client instance.
* @returns {ContentDeliveryClient}
*/
function ContentDeliveryClientImpl(args) {
// create the restAPI based on the content version
this.restAPI = restAPIFactory.createRestAPI(args.contentVersion);
// update the logger entries
logger.updateLogger(args.logger);
// store the given properties
this.info = {
accessToken: args.channelToken || args.accessToken,
channelToken: args.channelToken || args.accessToken,
cacheBuster: args.cacheBuster,
beforeSend: args.beforeSend,
clientType: 'delivery',
contentServer: this.restAPI.extractServer(args.contentServer),
contentType: 'published',
secureContent: args.secureContent || false,
timeout: args.timeout || 0,
contentVersion: this.restAPI.requestedContentVersion || this.restAPI.contentVersion,
authorization: args.authorization,
assetTransform: args.assetTransform,
tokenManager: new TokenManager(args.authorizationParams, args.authorization)
};
// store if running in compiler
this.isCompiler = args.isCompiler;
// note supported content types
this.validContentTypes = ['published'];
this.validLayoutTypes = this.validContentTypes;
// define the external API
this.publicSDK = {
getInfo: utils.bind(this.getInfo, this),
getItem: utils.bind(this.getItem, this),
getItems: utils.bind(this.getItems, this),
getAuthorizationHeaderValue: utils.bind(this.getAuthorizationHeaderValue, this),
searchItems: utils.bind(this.queryItems, this),
queryItems: utils.bind(this.queryItems, this),
graphql: utils.bind(this.graphql, this),
getRenditionURL: utils.bind(this.getRenditionURL, this),
getLayoutInfo: utils.bind(this.getLayoutInfo, this),
getRecommendationResults: utils.bind(this.getRecommendationResults, this),
loadContentLayout: utils.bind(this.loadContentLayout, this),
renderItem: utils.bind(this.renderItem, this),
expandMacros: utils.bind(this.expandMacros, this),
getTaxonomies: utils.bind(this.getTaxonomies, this),
queryTaxonomyCategories: utils.bind(this.queryTaxonomyCategories, this),
getTaxonomyCategory: utils.bind(this.getTaxonomyCategory, this)
};
logger.debug('ContentClient.create: Content Info:');
logger.debug(this.info);
}
// common function for evaluating parameters to be used for the REST call
var _proto = ContentDeliveryClientImpl.prototype;
_proto.resolveRESTArgs = function resolveRESTArgs(method, args) {
var searchParams = this.restAPI.makeQueryParameters(args);
var restArgs = utils.extend({}, this.info); // start with the Client properties
// add in the defaults
restArgs.method = method;
restArgs.contentType = this.getContentType(args.contentType);
// add in authorization
restArgs.authorization = this.getInfo().authorization;
// add in the language locale
restArgs.language = args.language;
// override call specific properties
restArgs.beforeSend = args.beforeSend || restArgs.beforeSend;
restArgs.timeout = args.timeout || restArgs.timeout;
//
// ad