Skip to content

Commit 3000408

Browse files
author
Your Name
committed
Support Backend Headers
1 parent 0b89768 commit 3000408

6 files changed

Lines changed: 222 additions & 3 deletions

File tree

cspell.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
"testdata",
5050
"Bytespider",
5151
"Timespans",
52-
"googlequicksearchbox"
52+
"googlequicksearchbox",
53+
"cnstrc"
5354
]
5455
}

spec/mocha.helpers.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ const extractBodyParamsFromFetch = (fetch) => {
6464
return null;
6565
};
6666

67+
// Extract headers from the last fetch spy call
68+
const extractHeadersFromFetch = (fetch) => {
69+
const lastCallArguments = fetch && fetch.args && fetch.args[fetch.args.length - 1];
70+
const requestData = lastCallArguments && lastCallArguments[1];
71+
return (requestData && requestData.headers) || {};
72+
};
73+
6774
const getUserDefinedWindowProperties = () => {
6875
const iframe = document.createElement('iframe');
6976

@@ -85,5 +92,6 @@ module.exports = {
8592
clearStorage,
8693
extractUrlParamsFromFetch,
8794
extractBodyParamsFromFetch,
95+
extractHeadersFromFetch,
8896
getUserDefinedWindowProperties,
8997
};

spec/src/constructorio.js

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,72 @@ if (!bundled) {
741741
expect(instance).to.have.property('tracker');
742742
});
743743

744+
it('Should store securityToken in options when provided', () => {
745+
const securityToken = 'test-security-token';
746+
const instance = new ConstructorIO({
747+
apiKey: validApiKey,
748+
clientId,
749+
sessionId,
750+
securityToken,
751+
});
752+
753+
expect(instance.options).to.have.property('securityToken').to.equal(securityToken);
754+
});
755+
756+
it('Should store empty string for securityToken when not provided', () => {
757+
const instance = new ConstructorIO({
758+
apiKey: validApiKey,
759+
clientId,
760+
sessionId,
761+
});
762+
763+
expect(instance.options).to.have.property('securityToken').to.equal('');
764+
});
765+
766+
it('Should store userIp in options when provided', () => {
767+
const userIp = '127.0.0.1';
768+
const instance = new ConstructorIO({
769+
apiKey: validApiKey,
770+
clientId,
771+
sessionId,
772+
userIp,
773+
});
774+
775+
expect(instance.options).to.have.property('userIp').to.equal(userIp);
776+
});
777+
778+
it('Should store empty string for userIp when not provided', () => {
779+
const instance = new ConstructorIO({
780+
apiKey: validApiKey,
781+
clientId,
782+
sessionId,
783+
});
784+
785+
expect(instance.options).to.have.property('userIp').to.equal('');
786+
});
787+
788+
it('Should store userAgent in options when provided', () => {
789+
const userAgent = 'custom-agent/1.0';
790+
const instance = new ConstructorIO({
791+
apiKey: validApiKey,
792+
clientId,
793+
sessionId,
794+
userAgent,
795+
});
796+
797+
expect(instance.options).to.have.property('userAgent').to.equal(userAgent);
798+
});
799+
800+
it('Should store empty string for userAgent when not provided', () => {
801+
const instance = new ConstructorIO({
802+
apiKey: validApiKey,
803+
clientId,
804+
sessionId,
805+
});
806+
807+
expect(instance.options).to.have.property('userAgent').to.equal('');
808+
});
809+
744810
it('Should throw an error if client identifier is not provided', () => {
745811
expect(() => new ConstructorIO({
746812
apiKey: validApiKey,

spec/src/utils/request-queue.js

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -849,6 +849,131 @@ describe('ConstructorIO - Utils - Request Queue', function utilsRequestQueue() {
849849
}, waitInterval);
850850
});
851851
});
852+
853+
describe('headers', () => {
854+
describe('securityToken', () => {
855+
it('Should send x-cnstrc-token header on POST requests when securityToken is provided', (done) => {
856+
const requests = new RequestQueue({
857+
...requestQueueOptions,
858+
securityToken: 'test-security-token',
859+
});
860+
861+
store.session.set(humanityStorageKey, true);
862+
863+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
864+
requests.send();
865+
866+
setTimeout(() => {
867+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
868+
expect(requestHeaders).to.have.property('x-cnstrc-token').to.equal('test-security-token');
869+
done();
870+
}, waitInterval);
871+
});
872+
873+
it('Should send x-cnstrc-token header on GET requests when securityToken is provided', (done) => {
874+
const requests = new RequestQueue({
875+
...requestQueueOptions,
876+
securityToken: 'test-security-token',
877+
});
878+
879+
store.session.set(humanityStorageKey, true);
880+
881+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start');
882+
requests.send();
883+
884+
setTimeout(() => {
885+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
886+
expect(requestHeaders).to.have.property('x-cnstrc-token').to.equal('test-security-token');
887+
done();
888+
}, waitInterval);
889+
});
890+
891+
it('Should not send x-cnstrc-token header when securityToken is not provided', (done) => {
892+
const requests = new RequestQueue(requestQueueOptions);
893+
894+
store.session.set(humanityStorageKey, true);
895+
896+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
897+
requests.send();
898+
899+
setTimeout(() => {
900+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
901+
expect(requestHeaders).to.not.have.property('x-cnstrc-token');
902+
done();
903+
}, waitInterval);
904+
});
905+
});
906+
907+
describe('userIp', () => {
908+
it('Should send X-Forwarded-For header when userIp is provided', (done) => {
909+
const requests = new RequestQueue({
910+
...requestQueueOptions,
911+
userIp: '127.0.0.1',
912+
});
913+
914+
store.session.set(humanityStorageKey, true);
915+
916+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
917+
requests.send();
918+
919+
setTimeout(() => {
920+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
921+
expect(requestHeaders).to.have.property('X-Forwarded-For').to.equal('127.0.0.1');
922+
done();
923+
}, waitInterval);
924+
});
925+
926+
it('Should not send X-Forwarded-For header when userIp is not provided', (done) => {
927+
const requests = new RequestQueue(requestQueueOptions);
928+
929+
store.session.set(humanityStorageKey, true);
930+
931+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
932+
requests.send();
933+
934+
setTimeout(() => {
935+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
936+
expect(requestHeaders).to.not.have.property('X-Forwarded-For');
937+
done();
938+
}, waitInterval);
939+
});
940+
});
941+
942+
describe('userAgent', () => {
943+
it('Should send User-Agent header when userAgent is provided', (done) => {
944+
const requests = new RequestQueue({
945+
...requestQueueOptions,
946+
userAgent: 'custom-agent/1.0',
947+
});
948+
949+
store.session.set(humanityStorageKey, true);
950+
951+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
952+
requests.send();
953+
954+
setTimeout(() => {
955+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
956+
expect(requestHeaders).to.have.property('User-Agent').to.equal('custom-agent/1.0');
957+
done();
958+
}, waitInterval);
959+
});
960+
961+
it('Should not send User-Agent header when userAgent is not provided', (done) => {
962+
const requests = new RequestQueue(requestQueueOptions);
963+
964+
store.session.set(humanityStorageKey, true);
965+
966+
requests.queue('https://ac.cnstrc.com/behavior?action=session_start', 'POST', { action: 'session_start' });
967+
requests.send();
968+
969+
setTimeout(() => {
970+
const requestHeaders = helpers.extractHeadersFromFetch(fetchSpy);
971+
expect(requestHeaders).to.not.have.property('User-Agent');
972+
done();
973+
}, waitInterval);
974+
});
975+
});
976+
});
852977
});
853978

854979
describe('domless', () => {

src/constructorio.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ class ConstructorIO {
9191
beaconMode,
9292
networkParameters,
9393
humanityCheckLocation,
94+
securityToken,
95+
userIp,
96+
userAgent,
9497
} = options;
9598

9699
if (!apiKey || typeof apiKey !== 'string') {
@@ -139,6 +142,9 @@ class ConstructorIO {
139142
beaconMode: (beaconMode === false) ? false : true, // Defaults to 'true',
140143
networkParameters: networkParameters || {},
141144
humanityCheckLocation: humanityCheckLocation || 'session',
145+
securityToken: securityToken || '',
146+
userIp: userIp || '',
147+
userAgent: userAgent || '',
142148
};
143149

144150
// Expose global modules

src/utils/request-queue.js

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,16 +112,29 @@ class RequestQueue {
112112
}
113113
}
114114

115+
// Build security token header (mirrors Node SDK pattern)
116+
const headers = {};
117+
if (this.options.securityToken && typeof this.options.securityToken === 'string') {
118+
headers['x-cnstrc-token'] = this.options.securityToken;
119+
}
120+
if (this.options.userIp && typeof this.options.userIp === 'string') {
121+
headers['X-Forwarded-For'] = this.options.userIp;
122+
}
123+
if (this.options.userAgent && typeof this.options.userAgent === 'string') {
124+
headers['User-Agent'] = this.options.userAgent;
125+
}
126+
115127
if (nextInQueue.method === 'GET') {
116-
request = fetch(nextInQueue.url, { signal });
128+
request = fetch(nextInQueue.url, { headers, signal });
117129
}
118130

119131
if (nextInQueue.method === 'POST') {
132+
headers['Content-Type'] = 'text/plain';
120133
request = fetch(nextInQueue.url, {
121134
method: nextInQueue.method,
122135
body: JSON.stringify(nextInQueue.body),
123136
mode: 'cors',
124-
headers: { 'Content-Type': 'text/plain' },
137+
headers,
125138
signal,
126139
});
127140
}

0 commit comments

Comments
 (0)