diff --git a/lib/stack/taxonomy/index.js b/lib/stack/taxonomy/index.js index 10c5b9ab..f8096a8a 100644 --- a/lib/stack/taxonomy/index.js +++ b/lib/stack/taxonomy/index.js @@ -266,6 +266,53 @@ export function Taxonomy (http, data = {}) { throw error(err) } } + + /** + * @description The Publish taxonomy call initiates a job to publish a taxonomy and/or specific terms to the specified environments and locales. + * @memberof Taxonomy + * @func publish + * @param {Object} data - Publish details + * @param {string} [api_version=''] - Optional API version (e.g., '3.2') + * @returns {Promise} Response object with publish job details + * @example + * import * as contentstack from '@contentstack/management' + * const client = contentstack.client() + * + * const publishData = { + * locales: ["en-us"], + * environments: ["development"], + * items: [ + * { + * uid: "taxonomy_testing", + * term_uid: "vehicles" + * }, + * { + * uid: "taxonomy_testing", + * term_uid: "cars" + * } + * ] + * } + * client.stack({ api_key: 'api_key'}).taxonomy().publish(publishData, '3.2') + * .then((response) => console.log(response)) + */ + this.publish = async function (data, api_version = '') { + try { + const headers = { + headers: { ...cloneDeep(this.stackHeaders) } + } + if (api_version) { + headers.headers.api_version = api_version + } + const response = await http.post(`${this.urlPath}/publish`, data, headers) + if (response.data) { + return response.data + } else { + throw error(response) + } + } catch (err) { + throw error(err) + } + } } } export function TaxonomyCollection (http, data) { diff --git a/package-lock.json b/package-lock.json index f8b2033e..abeab3ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3084,6 +3084,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-crypto/-/plugin-crypto-12.0.1.tgz", "integrity": "sha512-qPuhN3QrT7ZZLcLCyKOSNhuijUi9G5guMRVrxq63r9YNOxxQjPm59gVxLM+7xGnHnM6cimY57tuKsjK7y9LM1g==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1" @@ -3093,6 +3094,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/plugin-thirty-two/-/plugin-thirty-two-12.0.1.tgz", "integrity": "sha512-MtT+uqRso909UkbrrYpJ6XFjj9D+x2Py7KjTO9JDPhL0bJUYVu5kFP4TFZW4NFAywrAtFRxOVY261u0qwb93gA==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1", @@ -3103,6 +3105,7 @@ "version": "12.0.1", "resolved": "https://registry.npmjs.org/@otplib/preset-default/-/preset-default-12.0.1.tgz", "integrity": "sha512-xf1v9oOJRyXfluBhMdpOkr+bsE+Irt+0D5uHtvg6x1eosfmHCsCC6ej/m7FXiWqdo0+ZUI6xSKDhJwc8yfiOPQ==", + "deprecated": "Please upgrade to v13 of otplib. Refer to otplib docs for migration paths", "license": "MIT", "dependencies": { "@otplib/core": "^12.0.1", @@ -3437,9 +3440,9 @@ } }, "node_modules/@types/express-serve-static-core": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.0.tgz", - "integrity": "sha512-jnHMsrd0Mwa9Cf4IdOzbz543y4XJepXrbia2T4b6+spXC2We3t1y6K44D3mR8XMFSXMCf3/l7rCgddfx7UNVBA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz", + "integrity": "sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==", "dev": true, "license": "MIT", "peer": true, @@ -3550,9 +3553,9 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-FOvQ0YPD5NOfPgMzJihoT+Za5pdkDJWcbpuj1DjaKZIr/gxodQjY/uWEFlTNqW2ugXHUiL8lRQgw63dzKHZdeQ==", + "version": "4.17.23", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-RDvF6wTulMPjrNdCoYRC8gNR880JNGT8uB+REUpC2Ns4pRqQJhGz90wh7rgdXDPpCczF3VGktDuFGVnz8zP7HA==", "dev": true, "license": "MIT" }, @@ -3596,9 +3599,9 @@ "license": "MIT" }, "node_modules/@types/node": { - "version": "25.0.3", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.3.tgz", - "integrity": "sha512-W609buLVRVmeW693xKfzHeIV6nJGGz98uCPfeXI1ELMLXVeKYZ9m15fAMSaUPBHYLGFsVRcMmSCksQOrZV9BYA==", + "version": "25.0.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.0.6.tgz", + "integrity": "sha512-NNu0sjyNxpoiW3YuVFfNz7mxSQ+S4X2G28uqg2s+CzoqoQjLPsWSbsFFyztIAqt2vb8kfEAsJNepMGPTxFDx3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4879,9 +4882,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.9.11", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.11.tgz", - "integrity": "sha512-Sg0xJUNDU1sJNGdfGWhVHX0kkZ+HWcvmVymJbj6NSgZZmW/8S9Y2HQ5euytnIgakgxN6papOAWiwDo1ctFDcoQ==", + "version": "2.9.14", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz", + "integrity": "sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg==", "dev": true, "license": "Apache-2.0", "bin": { @@ -4920,9 +4923,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, "license": "MIT", "dependencies": { @@ -4932,7 +4935,7 @@ "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", - "qs": "^6.14.0", + "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" }, @@ -5193,9 +5196,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001762", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001762.tgz", - "integrity": "sha512-PxZwGNvH7Ak8WX5iXzoK1KPZttBXNPuaOvI2ZYU7NrlM+d9Ov+TUvlLOBNGzVXAntMSMMlJPd+jY6ovrVjSmUw==", + "version": "1.0.30001764", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz", + "integrity": "sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g==", "dev": true, "funding": [ { @@ -7771,9 +7774,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.1.tgz", - "integrity": "sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", "dependencies": { @@ -15241,9 +15244,9 @@ } }, "node_modules/ws": { - "version": "8.18.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz", - "integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==", + "version": "8.19.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz", + "integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==", "dev": true, "license": "MIT", "engines": { diff --git a/test/sanity-check/api/terms-test.js b/test/sanity-check/api/terms-test.js index 7d4179f3..2230a810 100644 --- a/test/sanity-check/api/terms-test.js +++ b/test/sanity-check/api/terms-test.js @@ -2,6 +2,7 @@ import { describe, it, beforeEach } from 'mocha' import { expect } from 'chai' import { jsonReader } from '../utility/fileOperations/readwrite' import { contentstackClient } from '../utility/ContentstackClient.js' +import { environmentCreate } from '../mock/environment.js' import { stageBranch } from '../mock/branch.js' var client = {} @@ -42,6 +43,7 @@ describe('Terms API Test', () => { }) it('should create taxonomy', async () => { const response = await client.stack({ api_key: process.env.API_KEY }).taxonomy().create({ taxonomy }) + await client.stack({ api_key: process.env.API_KEY }).environment().create(environmentCreate) expect(response.uid).to.be.equal(taxonomy.uid) await new Promise(resolve => setTimeout(resolve, 5000)) }, 10000) @@ -127,6 +129,35 @@ describe('Terms API Test', () => { .catch(done) }) + it('should publish with api_version', done => { + const publishData = { + locales: ['en-us'], + environments: ['development'], + items: [ + { + uid: taxonomy.uid, + term_uid: 'term_test' + }, + { + uid: taxonomy.uid, + term_uid: 'term_test_child1' + }, + { + uid: taxonomy.uid, + term_uid: 'term_test_child2' + } + ] + } + makeTaxonomy() + .publish(publishData, '3.2') + .then((response) => { + expect(response.notice).to.not.equal(null) + expect(response.job_id).to.not.equal(undefined) + done() + }) + .catch(done) + }) + it('should search the term with the string passed', done => { makeTerms(taxonomy.uid).search(termString) .then((response) => { @@ -195,6 +226,10 @@ function makeTerms (taxonomyUid, termUid = null) { return client.stack({ api_key: process.env.API_KEY }).taxonomy(taxonomyUid).terms(termUid) } +function makeTaxonomy () { + return client.stack({ api_key: process.env.API_KEY }).taxonomy() +} + describe('Terms Query Parameters Sanity Tests', () => { beforeEach(async () => { const user = jsonReader('loggedinuser.json') @@ -359,6 +394,7 @@ describe('Terms Query Parameters Sanity Tests', () => { skip: 0, limit: 10 }) + await client.stack({ api_key: process.env.API_KEY }).environment(environmentCreate.environment.name).delete() expect(terms).to.have.property('items') expect(terms.items).to.be.an('array') // Count property might not be available in all environments diff --git a/test/unit/taxonomy-test.js b/test/unit/taxonomy-test.js index 64e6cea6..78301809 100644 --- a/test/unit/taxonomy-test.js +++ b/test/unit/taxonomy-test.js @@ -759,6 +759,33 @@ describe('Contentstack Taxonomy test', () => { }) .catch(done) }) + + it('Taxonomy publish test with api_version', done => { + var mock = new MockAdapter(Axios) + mock.onPost('/taxonomies/publish').reply(200, { + notice: 'Taxonomy publish job initiated successfully.', + job_id: 'job_456' + }) + const publishData = { + locales: ['en-us', 'fr-fr'], + environments: ['production'], + scheduled_at: '2025-10-01T10:00:00.000Z', + items: [ + { + uid: 'taxonomy_testing', + term_uid: 'vehicles' + } + ] + } + makeTaxonomy() + .publish(publishData, '3.2') + .then((response) => { + expect(response.notice).to.be.equal('Taxonomy publish job initiated successfully.') + expect(response.job_id).to.be.equal('job_456') + done() + }) + .catch(done) + }) }) function makeTaxonomy (data = {}) { diff --git a/types/stack/taxonomy/index.d.ts b/types/stack/taxonomy/index.d.ts index bb9b0cea..bd11f182 100644 --- a/types/stack/taxonomy/index.d.ts +++ b/types/stack/taxonomy/index.d.ts @@ -10,6 +10,7 @@ export interface Taxonomy extends SystemFields, SystemFunction { export interface Taxonomies extends Creatable, Queryable { import(data: TaxonomyData, params?: any): Promise + publish(data: TaxonomyPublishData, api_version?: string): Promise } export interface TaxonomyData extends AnyProperty { @@ -17,3 +18,19 @@ export interface TaxonomyData extends AnyProperty { uid: string description: string } + +export interface TaxonomyPublishData { + locales: Array + environments: Array + items: Array +} + +export interface TaxonomyPublishItem { + uid: string + term_uid: string +} + +export interface TaxonomyPublishResponse extends AnyProperty { + notice?: string + job_id?: string +}