Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .talismanrc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@ fileignoreconfig:
- filename: test/sanity-check/api/stack-test.js
checksum: 198d5cf7ead33b079249dc3ecdee61a9c57453e93f1073ed0341400983e5aa53
version: "1.0"
fileignoreconfig:
- filename: test/sanity-check/api/previewToken-test.js
checksum: 9a42e079b7c71f76932896a0d2390d86ac626678ab20d36821dcf962820a886c
version: "1.0"
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
# Changelog
## [v1.21.5](https://github.com/contentstack/contentstack-management-javascript/tree/v1.21.5) (2025-06-09)
- Enhancement
- Preview token support added

## [v1.21.4](https://github.com/contentstack/contentstack-management-javascript/tree/v1.21.4) (2025-06-02)
- Enhancement
- Retry Logic modification on x-ratelimit-remaining Header

## [v1.21.3](https://github.com/contentstack/contentstack-management-javascript/tree/v1.21.3) (2025-05-26)
- Enhancement
- Update addSettings Method to Support Generic Stack Settings Update
Expand Down
30 changes: 19 additions & 11 deletions lib/core/concurrency-queue.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ export function ConcurrencyQueue ({ axios, config }) {
if (!this.config.retryOnError || networkError > this.config.retryLimit) {
return Promise.reject(responseHandler(error))
}
// Check rate limit remaining header before retrying

// Error handling
const wait = this.config.retryDelay
Expand All @@ -244,19 +245,26 @@ export function ConcurrencyQueue ({ axios, config }) {
} else {
return Promise.reject(responseHandler(error))
}
} else if ((response.status === 401 && this.config.refreshToken)) {
retryErrorType = `Error with status: ${response.status}`
networkError++

if (networkError > this.config.retryLimit) {
} else {
const rateLimitRemaining = response.headers['x-ratelimit-remaining']
if (rateLimitRemaining !== undefined && parseInt(rateLimitRemaining) <= 0) {
return Promise.reject(responseHandler(error))
}
this.running.shift()
// Cool down the running requests
delay(wait, response.status === 401)
error.config.retryCount = networkError
// deepcode ignore Ssrf: URL is dynamic
return axios(updateRequestConfig(error, retryErrorType, wait))

if ((response.status === 401 && this.config.refreshToken)) {
retryErrorType = `Error with status: ${response.status}`
networkError++

if (networkError > this.config.retryLimit) {
return Promise.reject(responseHandler(error))
}
this.running.shift()
// Cool down the running requests
delay(wait, response.status === 401)
error.config.retryCount = networkError
// deepcode ignore Ssrf: URL is dynamic
return axios(updateRequestConfig(error, retryErrorType, wait))
}
}
if (this.config.retryCondition && this.config.retryCondition(error)) {
retryErrorType = error.response ? `Error with status: ${response.status}` : `Error Code:${error.code}`
Expand Down
11 changes: 5 additions & 6 deletions lib/entity.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,21 +85,20 @@ export const upload = async ({ http, urlPath, stackHeaders, formData, params, me
}
}

export const create = ({ http, params = {}, createWithPreviewToken = false }) => {
export const create = ({ http, params }) => {
return async function (data, param) {
this.stackHeaders = {
...this.stackHeaders
}
const queryParams = {
...(createWithPreviewToken ? { create_with_preview_token: true } : {}),
...cloneDeep(param) // user param can override default
}

const headers = {
headers: {
...cloneDeep(params),
...cloneDeep(this.stackHeaders)
},
params: queryParams
params: {
...cloneDeep(param)
}
} || {}

try {
Expand Down
19 changes: 18 additions & 1 deletion lib/stack/deliveryToken/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import cloneDeep from 'lodash/cloneDeep'
import { create, update, deleteEntity, fetch, query } from '../../entity'
import { PreviewToken } from './previewToken'

/**
* Delivery tokens provide read-only access to the associated environments. Read more about <a href='https://www.contentstack.com/docs/developers/create-tokens/about-delivery-tokens'>DeliveryToken</a>.
Expand Down Expand Up @@ -59,6 +60,22 @@ export function DeliveryToken (http, data = {}) {
*
*/
this.fetch = fetch(http, 'token')

/**
* @description The Create a PreviewToken call creates a new previewToken in a particular stack of your Contentstack account.
* @memberof DeliveryToken
* @func previewToken
* @returns {PreviewToken} Instance of PreviewToken.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
* const deliveryToken = client.stack({ api_key: 'api_key'}).deliveryToken('delivery_token_uid')
* const previewToken = deliveryToken.previewToken()
* console.log(previewToken)
*/
this.previewToken = () => {
return new PreviewToken(http, { stackHeaders: this.stackHeaders, token: { uid: this.uid } })
}
} else {
/**
* @description The Create a DeliveryToken call creates a new deliveryToken in a particular stack of your Contentstack account.
Expand All @@ -84,7 +101,7 @@ export function DeliveryToken (http, data = {}) {
* client.stack().deliveryToken().create({ token })
* .then((deliveryToken) => console.log(deliveryToken))
*/
this.create = create({ http: http, createWithPreviewToken: true })
this.create = create({ http: http })

/**
* @description The ‘Get all deliveryToken’ request returns comprehensive information about all deliveryToken created in a stack.
Expand Down
50 changes: 50 additions & 0 deletions lib/stack/deliveryToken/previewToken/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import cloneDeep from 'lodash/cloneDeep'
import { create, deleteEntity } from '../../../entity'

/**
* Preview tokens provide read-only access to the associated environments. Read more about <a href='https://www.contentstack.com/docs/developers/create-tokens/about-preview-tokens'>PreviewToken</a>.
* @namespace PreviewToken
*/
export function PreviewToken (http, data = {}) {
this.stackHeaders = data.stackHeaders
if (data.token) {
Object.assign(this, cloneDeep(data.token))
this.urlPath = `/stacks/delivery_tokens/${this.uid}/preview_token`

/**
* @description The Delete PreviewToken call is used to delete an existing PreviewToken permanently from your Stack.
* @memberof PreviewToken
* @func delete
* @returns {Object} Response Object.
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
*
* client.stack({ api_key: 'api_key'}).deliveryToken('delivery_token_uid').previewToken().delete()
* .then((response) => console.log(response.notice))
*/
this.delete = deleteEntity(http)

/**
* @description The Create a PreviewToken call creates a new previewToken in a particular stack of your Contentstack account.
* @memberof PreviewToken
* @func create
* @returns {Promise<PreviewToken.PreviewToken>} Promise for PreviewToken instance
*
* @example
* import * as contentstack from '@contentstack/management'
* const client = contentstack.client()
* client.stack().deliveryToken('delivery_token_uid').previewToken().create()
* .then((previewToken) => console.log(previewToken))
*/
this.create = create({ http: http })
}
}

export function PreviewTokenCollection (http, data) {
const obj = cloneDeep(data.tokens) || []
const previewTokenCollection = obj.map((userdata) => {
return new PreviewToken(http, { token: userdata, stackHeaders: data.stackHeaders })
})
return previewTokenCollection
}
Loading
Loading