Skip to content

Commit 1074d19

Browse files
Added header support in all modules
1 parent b3f65af commit 1074d19

File tree

44 files changed

+760
-22
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+760
-22
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
# Changelog
22

3+
## [v1.30.0](https://github.com/contentstack/contentstack-management-javascript/tree/v1.30.0) (2026-04-13)
4+
5+
- Enh
6+
- Per-module CMA headers: `addHeader`, `addHeaderDict`, and `removeHeader` on stack resources and query builders (stack shares one map; other modules copy-on-write). Backward compatible if unused.
7+
- Test
8+
- Unit + sanity coverage for header APIs; minor sanity robustness (taxonomy 412, nested GF plan skip, entry update timeout).
9+
310
## [v1.29.2](https://github.com/contentstack/contentstack-management-javascript/tree/v1.29.2) (2026-04-06)
411

512
- Fix

lib/core/moduleHeaderSupport.js

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import cloneDeep from 'lodash/cloneDeep'
2+
3+
const moduleHeadersOwn = Symbol.for('contentstack.management.moduleHeadersOwn')
4+
5+
/**
6+
* Attaches `addHeader`, `addHeaderDict`, and `removeHeader` to a stack resource instance.
7+
* Per-module headers merge into request stack headers and override parent keys for that
8+
* instance only (copy-on-write). Pass `ownsHeadersInline: true` on Stack so the canonical
9+
* stack header map stays shared across child modules until a child calls addHeader.
10+
*
11+
* @param {Object} instance - Resource instance that uses `stackHeaders` for CMA headers.
12+
* @param {Object} [options]
13+
* @param {boolean} [options.ownsHeadersInline=false] - Mutate `stackHeaders` in place (stack root).
14+
* @returns {Object} The same instance for chaining.
15+
*/
16+
export function bindModuleHeaders (instance, { ownsHeadersInline = false } = {}) {
17+
instance.addHeader = function (key, value) {
18+
if (key === undefined || key === null) {
19+
return this
20+
}
21+
prepareStackHeaders(this, ownsHeadersInline)
22+
this.stackHeaders[key] = value
23+
return this
24+
}
25+
26+
instance.addHeaderDict = function (headerDict) {
27+
if (!headerDict || typeof headerDict !== 'object') {
28+
return this
29+
}
30+
prepareStackHeaders(this, ownsHeadersInline)
31+
Object.assign(this.stackHeaders, headerDict)
32+
return this
33+
}
34+
35+
instance.removeHeader = function (key) {
36+
if (key === undefined || key === null) {
37+
return this
38+
}
39+
if (ownsHeadersInline) {
40+
if (this.stackHeaders && Object.prototype.hasOwnProperty.call(this.stackHeaders, key)) {
41+
delete this.stackHeaders[key]
42+
}
43+
return this
44+
}
45+
if (!this[moduleHeadersOwn]) {
46+
if (!this.stackHeaders || !Object.prototype.hasOwnProperty.call(this.stackHeaders, key)) {
47+
return this
48+
}
49+
prepareStackHeaders(this, ownsHeadersInline)
50+
delete this.stackHeaders[key]
51+
return this
52+
}
53+
if (this.stackHeaders && Object.prototype.hasOwnProperty.call(this.stackHeaders, key)) {
54+
delete this.stackHeaders[key]
55+
}
56+
return this
57+
}
58+
59+
return instance
60+
}
61+
62+
function prepareStackHeaders (instance, ownsHeadersInline) {
63+
if (ownsHeadersInline) {
64+
if (!instance.stackHeaders) {
65+
instance.stackHeaders = {}
66+
}
67+
return
68+
}
69+
if (!instance[moduleHeadersOwn]) {
70+
instance.stackHeaders = cloneDeep(instance.stackHeaders || {})
71+
instance[moduleHeadersOwn] = true
72+
} else if (!instance.stackHeaders) {
73+
instance.stackHeaders = {}
74+
}
75+
}
76+
77+
/**
78+
* Attaches `addHeader`, `addHeaderDict`, and `removeHeader` for a mutable header map (e.g. query builder).
79+
*
80+
* @param {Object} target - Object to receive methods.
81+
* @param {function(): Object} getHeaderMap - Returns the header key/value object used for requests.
82+
* @returns {Object} The same target for chaining.
83+
*/
84+
export function bindHeaderTarget (target, getHeaderMap) {
85+
target.addHeader = function (key, value) {
86+
if (key === undefined || key === null) {
87+
return this
88+
}
89+
const headers = getHeaderMap()
90+
if (!headers) {
91+
return this
92+
}
93+
headers[key] = value
94+
return this
95+
}
96+
97+
target.addHeaderDict = function (headerDict) {
98+
if (!headerDict || typeof headerDict !== 'object') {
99+
return this
100+
}
101+
const headers = getHeaderMap()
102+
if (!headers) {
103+
return this
104+
}
105+
Object.assign(headers, headerDict)
106+
return this
107+
}
108+
109+
target.removeHeader = function (key) {
110+
if (key === undefined || key === null) {
111+
return this
112+
}
113+
const headers = getHeaderMap()
114+
if (!headers) {
115+
return this
116+
}
117+
if (Object.prototype.hasOwnProperty.call(headers, key)) {
118+
delete headers[key]
119+
}
120+
return this
121+
}
122+
123+
return target
124+
}

lib/query/index.js

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import error from '../core/contentstackError'
22
import cloneDeep from 'lodash/cloneDeep'
33
import ContentstackCollection from '../contentstackCollection'
4+
import { bindHeaderTarget } from '../core/moduleHeaderSupport.js'
45

56
export default function Query (http, urlPath, param, stackHeaders = null, wrapperCollection) {
67
const headers = {}
7-
if (stackHeaders) {
8-
headers.headers = stackHeaders
9-
}
8+
const headerMap = stackHeaders && typeof stackHeaders === 'object' ? stackHeaders : {}
9+
headers.headers = headerMap
1010
var contentTypeUid = null
1111
if (param) {
1212
if (param.content_type_uid) {
@@ -43,7 +43,7 @@ export default function Query (http, urlPath, param, stackHeaders = null, wrappe
4343
if (contentTypeUid) {
4444
response.data.content_type_uid = contentTypeUid
4545
}
46-
return new ContentstackCollection(response, http, stackHeaders, wrapperCollection)
46+
return new ContentstackCollection(response, http, headerMap, wrapperCollection)
4747
} else {
4848
throw error(response)
4949
}
@@ -114,7 +114,7 @@ export default function Query (http, urlPath, param, stackHeaders = null, wrappe
114114
if (contentTypeUid) {
115115
response.data.content_type_uid = contentTypeUid
116116
}
117-
return new ContentstackCollection(response, http, stackHeaders, wrapperCollection)
117+
return new ContentstackCollection(response, http, headerMap, wrapperCollection)
118118
} else {
119119
throw error(response)
120120
}
@@ -123,9 +123,11 @@ export default function Query (http, urlPath, param, stackHeaders = null, wrappe
123123
}
124124
}
125125

126-
return {
126+
const api = {
127127
count: count,
128128
find: find,
129129
findOne: findOne
130130
}
131+
bindHeaderTarget(api, () => headers.headers)
132+
return api
131133
}

lib/stack/asset/folders/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
fetch,
66
create
77
} from '../../../entity'
8+
import { bindModuleHeaders } from '../../../core/moduleHeaderSupport.js'
89

910
/**
1011
* Folders refer to Asset Folders.
@@ -84,6 +85,7 @@ export function Folder (http, data = {}) {
8485
*/
8586
this.create = create({ http: http })
8687
}
88+
bindModuleHeaders(this)
8789
}
8890

8991
export function FolderCollection (http, data) {

lib/stack/asset/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
unpublish } from '../../entity'
1111
import { Folder } from './folders'
1212
import error from '../../core/contentstackError'
13+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
1314
import { ERROR_MESSAGES } from '../../core/errorMessages'
1415
import FormData from 'form-data'
1516
import { createReadStream } from 'fs'
@@ -297,6 +298,7 @@ export function Asset (http, data = {}) {
297298
throw error(err)
298299
}
299300
}
301+
bindModuleHeaders(this)
300302
return this
301303
}
302304

lib/stack/auditlog/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import cloneDeep from 'lodash/cloneDeep'
22
import error from '../../core/contentstackError'
33
import { fetchAll } from '../../entity'
4+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
45

56
/**
67
*
@@ -63,6 +64,7 @@ export function AuditLog (http, data = {}) {
6364
*/
6465
this.fetchAll = fetchAll(http, LogCollection)
6566
}
67+
bindModuleHeaders(this)
6668
return this
6769
}
6870

lib/stack/branch/compare.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { get } from '../../entity'
2+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
23

34
/**
45
*
@@ -74,5 +75,6 @@ export function Compare (http, data = {}) {
7475
return get(http, url, params, data)
7576
}
7677

78+
bindModuleHeaders(this)
7779
return this
7880
}

lib/stack/branch/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { create, query, fetch, deleteEntity } from '../../entity'
33
import { Compare } from './compare'
44
import { MergeQueue } from './mergeQueue'
55
import error from '../../core/contentstackError'
6+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
67

78
/**
89
*
@@ -205,6 +206,7 @@ export function Branch (http, data = {}) {
205206
return new MergeQueue(http, mergeData)
206207
}
207208
}
209+
bindModuleHeaders(this)
208210
return this
209211
}
210212

lib/stack/branch/mergeQueue.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { get } from '../../entity'
2+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
23

34
export function MergeQueue (http, data = {}) {
45
this.stackHeaders = data.stackHeaders
@@ -43,5 +44,6 @@ export function MergeQueue (http, data = {}) {
4344
}
4445
}
4546

47+
bindModuleHeaders(this)
4648
return this
4749
}

lib/stack/branchAlias/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import cloneDeep from 'lodash/cloneDeep'
22
import error from '../../core/contentstackError'
33
import { deleteEntity, fetchAll, parseData } from '../../entity'
44
import { Branch, BranchCollection } from '../branch'
5+
import { bindModuleHeaders } from '../../core/moduleHeaderSupport.js'
56

67
/**
78
*
@@ -110,5 +111,6 @@ export function BranchAlias (http, data = {}) {
110111
*/
111112
this.fetchAll = fetchAll(http, BranchCollection)
112113
}
114+
bindModuleHeaders(this)
113115
return this
114116
}

0 commit comments

Comments
 (0)