From c6b7c1e9e04af8db207fcadc20f8964a483dbc94 Mon Sep 17 00:00:00 2001 From: Deepak Kharah <42672761+Deepak-Kharah@users.noreply.github.com> Date: Mon, 23 Oct 2023 12:47:12 +0530 Subject: [PATCH 1/6] feat: Support new REST preview service The REST preview service introduces its own preview token and API endpoint for Live preview. This values will be used to fetch entry data for live preview. Replaced api.contentstack.io to rest-preview.contentstack.com and replaced to fixes: https://contentstack.atlassian.net/browse/VC-311 --- config.js | 2 +- index.d.ts | 3 ++- src/core/lib/utils.js | 7 ++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/config.js b/config.js index edabbd85..f223550f 100755 --- a/config.js +++ b/config.js @@ -13,7 +13,7 @@ const config = { }, live_preview: { enable: false, - host: 'api.contentstack.io' + host: 'rest-preview.contentstack.com' } }; diff --git a/index.d.ts b/index.d.ts index 4e709118..c93dca39 100644 --- a/index.d.ts +++ b/index.d.ts @@ -74,7 +74,8 @@ export interface ContentTypeCollection { export interface LivePreview { host: string - management_token: string + preview_token?: string + management_token?: string enable: boolean } diff --git a/src/core/lib/utils.js b/src/core/lib/utils.js index 7714e358..5fe22827 100755 --- a/src/core/lib/utils.js +++ b/src/core/lib/utils.js @@ -242,7 +242,7 @@ export function sendRequest(queryObject, options) { if(queryObject.requestParams.headers['access_token']) delete queryObject.requestParams.headers['access_token']; - queryObject.requestParams.headers['authorization'] = queryObject.live_preview.management_token + queryObject.requestParams.headers['authorization'] = queryObject.live_preview.preview_token || queryObject.live_preview.management_token; } else if(queryObject.live_preview.live_preview) { cachePolicy = 1; // cache then network } @@ -472,7 +472,8 @@ function generateReferenceMap (references) { async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, options, handlerOptions) { const {live_preview:livePreview, requestParams} = stack; - const { content_type_uid: livePreviewContentTypeUid, management_token } = livePreview; + const { content_type_uid: livePreviewContentTypeUid, preview_token } = + livePreview; async function findReferenceAndFetchEntry(referenceMap, entry, setReference) { @@ -509,7 +510,7 @@ async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, optio stack.requestParams.method = "GET" delete stack.requestParams.headers.access_token - stack.requestParams.headers.authorization = management_token + stack.requestParams.headers.authorization = preview_token; const data = await Request(stack, options); data.entry._content_type_uid = livePreviewContentTypeUid; From 4cf1d647e0208ffb96c2be119816291feb1169ac Mon Sep 17 00:00:00 2001 From: Deepak Kharah <42672761+Deepak-Kharah@users.noreply.github.com> Date: Thu, 26 Oct 2023 17:25:12 +0530 Subject: [PATCH 2/6] feat: make management token optional --- index.d.ts | 18 ++++++++++++++---- src/core/lib/utils.js | 4 ++-- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/index.d.ts b/index.d.ts index c93dca39..24a891c7 100644 --- a/index.d.ts +++ b/index.d.ts @@ -72,11 +72,21 @@ export interface ContentTypeCollection { count?: number } -export interface LivePreview { - host: string - preview_token?: string - management_token?: string +export type LivePreview = { + host?: string enable: boolean +} & (LivePreivewConfigWithManagementToken | LivePreivewConfigWithPreviewToken) + +export interface LivePreivewConfigWithManagementToken { + /** + * @deprecated Please use `preview_token` instead to enable live preview. + * The `management_token` will be removed in future releases. + */ + management_token: string; +} + +export interface LivePreivewConfigWithPreviewToken { + preview_token: string; } export interface LivePreviewQuery { diff --git a/src/core/lib/utils.js b/src/core/lib/utils.js index 5fe22827..be34304c 100755 --- a/src/core/lib/utils.js +++ b/src/core/lib/utils.js @@ -472,7 +472,7 @@ function generateReferenceMap (references) { async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, options, handlerOptions) { const {live_preview:livePreview, requestParams} = stack; - const { content_type_uid: livePreviewContentTypeUid, preview_token } = + const { content_type_uid: livePreviewContentTypeUid, preview_token, management_token } = livePreview; @@ -510,7 +510,7 @@ async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, optio stack.requestParams.method = "GET" delete stack.requestParams.headers.access_token - stack.requestParams.headers.authorization = preview_token; + stack.requestParams.headers.authorization = preview_token || management_token; const data = await Request(stack, options); data.entry._content_type_uid = livePreviewContentTypeUid; From 12cc5108514d5983801c74fadcdf4cebd627aa3e Mon Sep 17 00:00:00 2001 From: Deepak Kharah <42672761+Deepak-Kharah@users.noreply.github.com> Date: Wed, 8 Nov 2023 19:03:51 +0530 Subject: [PATCH 3/6] feat: add live preview hash in header --- src/core/lib/utils.js | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/core/lib/utils.js b/src/core/lib/utils.js index be34304c..10f82bb0 100755 --- a/src/core/lib/utils.js +++ b/src/core/lib/utils.js @@ -239,9 +239,20 @@ export function sendRequest(queryObject, options) { if(queryObject.requestParams.body['environment']) { delete queryObject.requestParams.body['environment']; } + if(queryObject.requestParams.headers['access_token']) delete queryObject.requestParams.headers['access_token']; + delete queryObject.requestParams.headers['authorization']; + delete queryObject.requestParams.headers['preview_token']; + + if (queryObject.live_preview.preview_token) { + queryObject.requestParams.headers['preview_token'] = queryObject.live_preview.preview_token; + queryObject.requestParams.headers['live_preview'] = queryObject.live_preview.live_preview; + } else if (queryObject.live_preview.management_token) { + queryObject.requestParams.headers['authorization'] = queryObject.live_preview.management_token; + } + queryObject.requestParams.headers['authorization'] = queryObject.live_preview.preview_token || queryObject.live_preview.management_token; } else if(queryObject.live_preview.live_preview) { cachePolicy = 1; // cache then network @@ -510,7 +521,15 @@ async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, optio stack.requestParams.method = "GET" delete stack.requestParams.headers.access_token - stack.requestParams.headers.authorization = preview_token || management_token; + delete stack.requestParams.headers.preview_token + + if (preview_token) { + stack.requestParams.headers.preview_token = preview_token; + stack.requestParams.headers.live_preview = livePreview.live_preview; + } else if (management_token) { + stack.requestParams.headers.authorization = + management_token; + } const data = await Request(stack, options); data.entry._content_type_uid = livePreviewContentTypeUid; From 17bf5a9e75da7362bc5d82a00a392009faf1aa47 Mon Sep 17 00:00:00 2001 From: Deepak Kharah <42672761+Deepak-Kharah@users.noreply.github.com> Date: Wed, 22 Nov 2023 07:36:30 +0530 Subject: [PATCH 4/6] fix: typo in the interface name The interface `LivePreivewConfigWithPreviewToken` should be `LivePreviewConfigWithPreviewToken` --- index.d.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/index.d.ts b/index.d.ts index 24a891c7..1bad8345 100644 --- a/index.d.ts +++ b/index.d.ts @@ -75,7 +75,7 @@ export interface ContentTypeCollection { export type LivePreview = { host?: string enable: boolean -} & (LivePreivewConfigWithManagementToken | LivePreivewConfigWithPreviewToken) +} & (LivePreivewConfigWithManagementToken | LivePreviewConfigWithPreviewToken) export interface LivePreivewConfigWithManagementToken { /** @@ -85,7 +85,7 @@ export interface LivePreivewConfigWithManagementToken { management_token: string; } -export interface LivePreivewConfigWithPreviewToken { +export interface LivePreviewConfigWithPreviewToken { preview_token: string; } From a0dcd569231cc8f26c58b1224112fab3157d0ad3 Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 2 Feb 2024 11:22:33 +0530 Subject: [PATCH 5/6] fix: added deepak's changes for entry and query --- src/core/lib/utils.js | 9 +++------ src/core/modules/entry.js | 2 +- src/core/modules/query.js | 4 ++-- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/core/lib/utils.js b/src/core/lib/utils.js index 10f82bb0..f0a1f781 100755 --- a/src/core/lib/utils.js +++ b/src/core/lib/utils.js @@ -233,8 +233,8 @@ export function sendRequest(queryObject, options) { queryObject.requestParams.body = merge(queryObject.requestParams.body, cloneQueryObj); if (queryObject.live_preview && queryObject.live_preview.enable === true && queryObject.live_preview.live_preview && queryObject.live_preview.live_preview !== "init") { - if(queryObject.live_preview.content_type_uid === queryObject.content_type_uid) { - queryObject.requestParams.body = merge(queryObject.requestParams.body, {live_preview: queryObject.live_preview.live_preview || "init"}); + + queryObject.requestParams.body = merge(queryObject.requestParams.body, {live_preview: queryObject.live_preview.live_preview || "init"}); cachePolicy = 2; // network else cache if(queryObject.requestParams.body['environment']) { delete queryObject.requestParams.body['environment']; @@ -252,10 +252,7 @@ export function sendRequest(queryObject, options) { } else if (queryObject.live_preview.management_token) { queryObject.requestParams.headers['authorization'] = queryObject.live_preview.management_token; } - - queryObject.requestParams.headers['authorization'] = queryObject.live_preview.preview_token || queryObject.live_preview.management_token; - } else if(queryObject.live_preview.live_preview) { - cachePolicy = 1; // cache then network + } } } diff --git a/src/core/modules/entry.js b/src/core/modules/entry.js index 6e51f244..6c5ecf49 100755 --- a/src/core/modules/entry.js +++ b/src/core/modules/entry.js @@ -359,7 +359,7 @@ export default class Entry { */ fetch(fetchOptions) { var host = this.config.host + ':' + this.config.port - if(this.live_preview && this.live_preview.enable === true && this.live_preview.content_type_uid === this.content_type_uid ) { + if(this.live_preview && this.live_preview.enable === true && this.live_preview.live_preview && this.live_preview.live_preview !== "init" ) { host = this.live_preview.host } if (this.entry_uid) { diff --git a/src/core/modules/query.js b/src/core/modules/query.js index 589c779d..434bcfa6 100755 --- a/src/core/modules/query.js +++ b/src/core/modules/query.js @@ -771,7 +771,7 @@ export default class Query extends Entry { */ find(fetchOptions) { var host = this.config.host + ':' + this.config.port - if (this.type && this.type !== 'asset' && this.live_preview && this.live_preview.enable === true && this.live_preview.content_type_uid === this.content_type_uid ) { + if (this.type && this.type !== 'asset' && this.live_preview && this.live_preview.enable === true && this.live_preview.live_preview && this.live_preview.live_preview !== "init") { host = this.live_preview.host; } const baseURL = this.config.protocol + "://" + host + '/' + this.config.version @@ -808,7 +808,7 @@ export default class Query extends Entry { */ findOne() { let host = this.config.protocol + "://" + this.config.host + ':' + this.config.port + '/' + this.config.version - if(this.type && this.type !== 'asset' && this.live_preview && this.live_preview.enable === true && this.live_preview.content_type_uid === this.content_type_uid ) { + if(this.type && this.type !== 'asset' && this.live_preview && this.live_preview.enable === true && this.live_preview.live_preview && this.live_preview.live_preview !== "init" ) { host = this.config.protocol + "://" + this.live_preview.host + '/' + this.config.version } const url = getRequestUrl(this.type, this.config, this.content_type_uid, host) From 427aa04534b0b7ed7ce7226385012754b23fbbeb Mon Sep 17 00:00:00 2001 From: Abhinav Gupta Date: Fri, 2 Feb 2024 11:39:28 +0530 Subject: [PATCH 6/6] fix: fixed missing bracket --- src/core/lib/utils.js | 204 ++++-------------------------------------- 1 file changed, 18 insertions(+), 186 deletions(-) diff --git a/src/core/lib/utils.js b/src/core/lib/utils.js index f0a1f781..1311ef0c 100755 --- a/src/core/lib/utils.js +++ b/src/core/lib/utils.js @@ -233,26 +233,21 @@ export function sendRequest(queryObject, options) { queryObject.requestParams.body = merge(queryObject.requestParams.body, cloneQueryObj); if (queryObject.live_preview && queryObject.live_preview.enable === true && queryObject.live_preview.live_preview && queryObject.live_preview.live_preview !== "init") { - queryObject.requestParams.body = merge(queryObject.requestParams.body, {live_preview: queryObject.live_preview.live_preview || "init"}); - cachePolicy = 2; // network else cache - if(queryObject.requestParams.body['environment']) { - delete queryObject.requestParams.body['environment']; - } - - if(queryObject.requestParams.headers['access_token']) - delete queryObject.requestParams.headers['access_token']; - - delete queryObject.requestParams.headers['authorization']; - delete queryObject.requestParams.headers['preview_token']; - - if (queryObject.live_preview.preview_token) { - queryObject.requestParams.headers['preview_token'] = queryObject.live_preview.preview_token; - queryObject.requestParams.headers['live_preview'] = queryObject.live_preview.live_preview; - } else if (queryObject.live_preview.management_token) { - queryObject.requestParams.headers['authorization'] = queryObject.live_preview.management_token; - } - + cachePolicy = 2; // network else cache + if(queryObject.requestParams.body['environment']) { + delete queryObject.requestParams.body['environment']; + } + if(queryObject.requestParams.headers['access_token']) + delete queryObject.requestParams.headers['access_token']; + delete queryObject.requestParams.headers['authorization']; + delete queryObject.requestParams.headers['preview_token']; + + if (queryObject.live_preview.preview_token) { + queryObject.requestParams.headers['preview_token'] = queryObject.live_preview.preview_token; + queryObject.requestParams.headers['live_preview'] = queryObject.live_preview.live_preview; + } else if (queryObject.live_preview.management_token) { + queryObject.requestParams.headers['authorization'] = queryObject.live_preview.management_token; } } } @@ -355,56 +350,10 @@ export function sendRequest(queryObject, options) { if (err || !_data) { callback(true, resolve, reject); } else { - try { - - const doesQueryRequestForReferences = - queryObject._query && - Array.isArray( - queryObject._query.include - ) && - queryObject._query.include.length > 0; - - if (doesQueryRequestForReferences) { - const referencesToBeResolved = - queryObject._query.include; - - const referencesToBeResolvedMap = - generateReferenceMap( - referencesToBeResolved - ); - - if (isSingle) { - await updateLivePreviewReferenceEntry( - referencesToBeResolvedMap, - _data.entry, - queryObject, - options - ); - } else { - await Promise.all(_data.entries.map(async (entry) => { - await updateLivePreviewReferenceEntry( - referencesToBeResolvedMap, - entry, - queryObject, - options - - ); - })) - } - - } - } catch (error) { - } - try { - if (!tojson) - _data = - resultWrapper(_data); - return resolve( - spreadResult(_data) - ); - } catch (e) { - return reject(e); + if (!tojson) { + _data = resultWrapper(_data); } + return resolve(spreadResult(_data)); } } catch (e) { return reject(e); @@ -413,7 +362,7 @@ export function sendRequest(queryObject, options) { }else { callback(true, resolve, reject); } - + }); case 2: case 0: @@ -456,120 +405,3 @@ export function sendRequest(queryObject, options) { }) } } - - -function generateReferenceMap (references) { - const map = {}; - - function mapSingleReference(reference) { - reference = reference.replace(/[\[]/gm, ".").replace(/[\]]/gm, ""); //to accept [index] - let keys = reference.split("."), - last = keys.pop(); - - keys.reduce(function (o, k) { - return (o[k] = o[k] || {}); - }, map)[last] = { }; - } - - references.forEach(function (reference) { - mapSingleReference(reference); - }); - - return map; -}; - -async function updateLivePreviewReferenceEntry(referenceMap, entry, stack, options, handlerOptions) { - const {live_preview:livePreview, requestParams} = stack; - const { content_type_uid: livePreviewContentTypeUid, preview_token, management_token } = - livePreview; - - - async function findReferenceAndFetchEntry(referenceMap, entry, setReference) { - if ( typeof entry === "undefined") - return; - if (Array.isArray(entry)) { - await Promise.all(entry.map((subEntry, i) => { - const setReference = (val) => { - entry[i] = val; - } - return findReferenceAndFetchEntry(referenceMap, subEntry, setReference) - })); - } else { - if (entry._content_type_uid === livePreviewContentTypeUid) { - - try { - stack.requestParams = JSON.parse(JSON.stringify(requestParams)); - - const includeReference = getIncludeParamForReference(referenceMap) - stack.requestParams.body.include = includeReference - stack.requestParams.body.live_preview = livePreview.live_preview - stack.requestParams.body.content_type_uid = livePreviewContentTypeUid - - const livePreviewUrl = livePreview.host.match( - /^((http[s]?):(\/\/)?)?(.+)$/ - ); - - const livePreviewHost = - (livePreviewUrl[1] || "https://") + livePreviewUrl[4]; - const entryUid = entry.uid; - - const url = `${livePreviewHost}/v3/content_types/${entry._content_type_uid}/entries/${entryUid}`; - stack.requestParams.url = url - stack.requestParams.method = "GET" - - delete stack.requestParams.headers.access_token - delete stack.requestParams.headers.preview_token - - if (preview_token) { - stack.requestParams.headers.preview_token = preview_token; - stack.requestParams.headers.live_preview = livePreview.live_preview; - } else if (management_token) { - stack.requestParams.headers.authorization = - management_token; - } - - const data = await Request(stack, options); - data.entry._content_type_uid = livePreviewContentTypeUid; - data.entry.uid = entryUid; - setReference(data.entry); - - } catch (err) { - console.log("errror", err) - } - } else { - - await Promise.all(Object.entries(referenceMap).map(async function ([ - currentRefFieldKey, - subReferenceMap, - ]) { - // recurse - const setRef = (val) => { - entry[currentRefFieldKey] = val; - } - await findReferenceAndFetchEntry(subReferenceMap, entry[currentRefFieldKey], () => {}); - })); - } - } - } - - await findReferenceAndFetchEntry(referenceMap, entry, () => {}); - -} - -function getIncludeParamForReference(referenceMap) { - const newRefences = []; - - function buildParamStringRecursively(currentReferenceMap, includeParamTillNow) { - if (Object.keys(currentReferenceMap).length === 0) { - newRefences.push(includeParamTillNow.substring(1)); - } else { - - Object.entries(currentReferenceMap).forEach(([referenceFieldKey, subReferenceMap]) => { - buildParamStringRecursively(subReferenceMap, [includeParamTillNow, referenceFieldKey].join(".")); - }); - } - } - - buildParamStringRecursively(referenceMap, ""); - return newRefences.filter((currentReference) => currentReference !== ""); -}