flagsmith-nodejs 6.1.0 → 6.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -279,6 +279,7 @@ class Flagsmith {
279
279
  if (this.environmentKey) {
280
280
  headers['X-Environment-Key'] = this.environmentKey;
281
281
  }
282
+ headers['User-Agent'] = (0, utils_js_1.getUserAgent)();
282
283
  if (this.customHeaders) {
283
284
  for (const [k, v] of Object.entries(this.customHeaders)) {
284
285
  headers[k] = v;
@@ -293,7 +294,7 @@ class Flagsmith {
293
294
  if (data.status !== 200) {
294
295
  throw new errors_js_1.FlagsmithAPIError(`Invalid request made to Flagsmith API. Response status code: ${data.status}`);
295
296
  }
296
- return data.json();
297
+ return { response: data, data: await data.json() };
297
298
  }
298
299
  /**
299
300
  * This promise ensures that the environment is retrieved before attempting to locally evaluate.
@@ -320,8 +321,43 @@ class Flagsmith {
320
321
  if (!this.environmentUrl) {
321
322
  throw new Error('`apiUrl` argument is missing or invalid.');
322
323
  }
323
- const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET');
324
- return (0, util_js_1.buildEnvironmentModel)(environment_data);
324
+ const startTime = Date.now();
325
+ const documents = [];
326
+ let url = this.environmentUrl;
327
+ let loggedWarning = false;
328
+ while (true) {
329
+ try {
330
+ if (!loggedWarning) {
331
+ const elapsedMs = Date.now() - startTime;
332
+ if (elapsedMs > this.environmentRefreshIntervalSeconds * 1000) {
333
+ this.logger.warn(`Environment document retrieval exceeded the polling interval of ${this.environmentRefreshIntervalSeconds} seconds.`);
334
+ loggedWarning = true;
335
+ }
336
+ }
337
+ const { response, data } = await this.getJSONResponse(url, 'GET');
338
+ documents.push(data);
339
+ const linkHeader = response.headers.get('link');
340
+ if (linkHeader) {
341
+ const nextMatch = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
342
+ if (nextMatch) {
343
+ const relativeUrl = decodeURIComponent(nextMatch[1]);
344
+ url = new URL(relativeUrl, this.apiUrl).href;
345
+ continue;
346
+ }
347
+ }
348
+ break;
349
+ }
350
+ catch (error) {
351
+ throw error;
352
+ }
353
+ }
354
+ // Compile the document
355
+ const compiledDocument = documents[0];
356
+ for (let i = 1; i < documents.length; i++) {
357
+ compiledDocument.identity_overrides = compiledDocument.identity_overrides || [];
358
+ compiledDocument.identity_overrides.push(...(documents[i].identity_overrides || []));
359
+ }
360
+ return (0, util_js_1.buildEnvironmentModel)(compiledDocument);
325
361
  }
326
362
  async getEnvironmentFlagsFromDocument() {
327
363
  const environment = await this.getEnvironment();
@@ -357,7 +393,7 @@ class Flagsmith {
357
393
  if (!this.environmentFlagsUrl) {
358
394
  throw new Error('`apiUrl` argument is missing or invalid.');
359
395
  }
360
- const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
396
+ const { data: apiFlags } = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
361
397
  const flags = models_js_1.Flags.fromAPIFlags({
362
398
  apiFlags: apiFlags,
363
399
  analyticsProcessor: this.analyticsProcessor,
@@ -373,7 +409,7 @@ class Flagsmith {
373
409
  throw new Error('`apiUrl` argument is missing or invalid.');
374
410
  }
375
411
  const data = (0, utils_js_1.generateIdentitiesData)(identifier, traits, transient);
376
- const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
412
+ const { data: jsonResponse } = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
377
413
  const flags = models_js_1.Flags.fromAPIFlags({
378
414
  apiFlags: jsonResponse['flags'],
379
415
  analyticsProcessor: this.analyticsProcessor,
@@ -56,4 +56,5 @@ export declare class Deferred<T> {
56
56
  resolve(value: T | PromiseLike<T>): void;
57
57
  reject(reason?: unknown): void;
58
58
  }
59
+ export declare function getUserAgent(): string;
59
60
  export {};
@@ -1,6 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Deferred = exports.retryFetch = exports.delay = exports.generateIdentitiesData = exports.isTraitConfig = void 0;
3
+ exports.getUserAgent = exports.Deferred = exports.retryFetch = exports.delay = exports.generateIdentitiesData = exports.isTraitConfig = void 0;
4
+ const FLAGSMITH_USER_AGENT = 'flagsmith-nodejs-sdk';
5
+ const FLAGSMITH_UNKNOWN_VERSION = 'unknown';
4
6
  function isTraitConfig(traitValue) {
5
7
  return !!traitValue && typeof traitValue == 'object' && traitValue.value !== undefined;
6
8
  }
@@ -93,3 +95,14 @@ class Deferred {
93
95
  }
94
96
  }
95
97
  exports.Deferred = Deferred;
98
+ function getUserAgent() {
99
+ try {
100
+ const packageJson = require('../package.json');
101
+ const version = packageJson?.version;
102
+ return version ? `${FLAGSMITH_USER_AGENT}/${version}` : FLAGSMITH_UNKNOWN_VERSION;
103
+ }
104
+ catch {
105
+ return FLAGSMITH_UNKNOWN_VERSION;
106
+ }
107
+ }
108
+ exports.getUserAgent = getUserAgent;
@@ -1,4 +1,5 @@
1
1
  import { pino } from 'pino';
2
+ import { getUserAgent } from './utils.js';
2
3
  export const ANALYTICS_ENDPOINT = './analytics/flags/';
3
4
  /** Duration in seconds to wait before trying to flush collected data after {@link trackFeature} is called. **/
4
5
  const ANALYTICS_TIMER = 10;
@@ -44,7 +45,8 @@ export class AnalyticsProcessor {
44
45
  signal: AbortSignal.timeout(this.requestTimeoutMs),
45
46
  headers: {
46
47
  'Content-Type': 'application/json',
47
- 'X-Environment-Key': this.environmentKey
48
+ 'X-Environment-Key': this.environmentKey,
49
+ 'User-Agent': getUserAgent()
48
50
  }
49
51
  });
50
52
  await this.currentFlush;
@@ -6,7 +6,7 @@ import { ANALYTICS_ENDPOINT, AnalyticsProcessor } from './analytics.js';
6
6
  import { FlagsmithAPIError } from './errors.js';
7
7
  import { Flags } from './models.js';
8
8
  import { EnvironmentDataPollingManager } from './polling_manager.js';
9
- import { Deferred, generateIdentitiesData, retryFetch } from './utils.js';
9
+ import { Deferred, generateIdentitiesData, getUserAgent, retryFetch } from './utils.js';
10
10
  import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators.js';
11
11
  import { pino } from 'pino';
12
12
  export { AnalyticsProcessor } from './analytics.js';
@@ -269,6 +269,7 @@ export class Flagsmith {
269
269
  if (this.environmentKey) {
270
270
  headers['X-Environment-Key'] = this.environmentKey;
271
271
  }
272
+ headers['User-Agent'] = getUserAgent();
272
273
  if (this.customHeaders) {
273
274
  for (const [k, v] of Object.entries(this.customHeaders)) {
274
275
  headers[k] = v;
@@ -283,7 +284,7 @@ export class Flagsmith {
283
284
  if (data.status !== 200) {
284
285
  throw new FlagsmithAPIError(`Invalid request made to Flagsmith API. Response status code: ${data.status}`);
285
286
  }
286
- return data.json();
287
+ return { response: data, data: await data.json() };
287
288
  }
288
289
  /**
289
290
  * This promise ensures that the environment is retrieved before attempting to locally evaluate.
@@ -310,8 +311,43 @@ export class Flagsmith {
310
311
  if (!this.environmentUrl) {
311
312
  throw new Error('`apiUrl` argument is missing or invalid.');
312
313
  }
313
- const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET');
314
- return buildEnvironmentModel(environment_data);
314
+ const startTime = Date.now();
315
+ const documents = [];
316
+ let url = this.environmentUrl;
317
+ let loggedWarning = false;
318
+ while (true) {
319
+ try {
320
+ if (!loggedWarning) {
321
+ const elapsedMs = Date.now() - startTime;
322
+ if (elapsedMs > this.environmentRefreshIntervalSeconds * 1000) {
323
+ this.logger.warn(`Environment document retrieval exceeded the polling interval of ${this.environmentRefreshIntervalSeconds} seconds.`);
324
+ loggedWarning = true;
325
+ }
326
+ }
327
+ const { response, data } = await this.getJSONResponse(url, 'GET');
328
+ documents.push(data);
329
+ const linkHeader = response.headers.get('link');
330
+ if (linkHeader) {
331
+ const nextMatch = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
332
+ if (nextMatch) {
333
+ const relativeUrl = decodeURIComponent(nextMatch[1]);
334
+ url = new URL(relativeUrl, this.apiUrl).href;
335
+ continue;
336
+ }
337
+ }
338
+ break;
339
+ }
340
+ catch (error) {
341
+ throw error;
342
+ }
343
+ }
344
+ // Compile the document
345
+ const compiledDocument = documents[0];
346
+ for (let i = 1; i < documents.length; i++) {
347
+ compiledDocument.identity_overrides = compiledDocument.identity_overrides || [];
348
+ compiledDocument.identity_overrides.push(...(documents[i].identity_overrides || []));
349
+ }
350
+ return buildEnvironmentModel(compiledDocument);
315
351
  }
316
352
  async getEnvironmentFlagsFromDocument() {
317
353
  const environment = await this.getEnvironment();
@@ -347,7 +383,7 @@ export class Flagsmith {
347
383
  if (!this.environmentFlagsUrl) {
348
384
  throw new Error('`apiUrl` argument is missing or invalid.');
349
385
  }
350
- const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
386
+ const { data: apiFlags } = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
351
387
  const flags = Flags.fromAPIFlags({
352
388
  apiFlags: apiFlags,
353
389
  analyticsProcessor: this.analyticsProcessor,
@@ -363,7 +399,7 @@ export class Flagsmith {
363
399
  throw new Error('`apiUrl` argument is missing or invalid.');
364
400
  }
365
401
  const data = generateIdentitiesData(identifier, traits, transient);
366
- const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
402
+ const { data: jsonResponse } = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
367
403
  const flags = Flags.fromAPIFlags({
368
404
  apiFlags: jsonResponse['flags'],
369
405
  analyticsProcessor: this.analyticsProcessor,
@@ -56,4 +56,5 @@ export declare class Deferred<T> {
56
56
  resolve(value: T | PromiseLike<T>): void;
57
57
  reject(reason?: unknown): void;
58
58
  }
59
+ export declare function getUserAgent(): string;
59
60
  export {};
@@ -1,3 +1,5 @@
1
+ const FLAGSMITH_USER_AGENT = 'flagsmith-nodejs-sdk';
2
+ const FLAGSMITH_UNKNOWN_VERSION = 'unknown';
1
3
  export function isTraitConfig(traitValue) {
2
4
  return !!traitValue && typeof traitValue == 'object' && traitValue.value !== undefined;
3
5
  }
@@ -85,3 +87,13 @@ export class Deferred {
85
87
  this.rejectPromise(reason);
86
88
  }
87
89
  }
90
+ export function getUserAgent() {
91
+ try {
92
+ const packageJson = require('../package.json');
93
+ const version = packageJson?.version;
94
+ return version ? `${FLAGSMITH_USER_AGENT}/${version}` : FLAGSMITH_UNKNOWN_VERSION;
95
+ }
96
+ catch {
97
+ return FLAGSMITH_UNKNOWN_VERSION;
98
+ }
99
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flagsmith-nodejs",
3
- "version": "6.1.0",
3
+ "version": "6.2.0",
4
4
  "description": "Flagsmith lets you manage features flags and remote config across web, mobile and server side applications. Deliver true Continuous Integration. Get builds out faster. Control who has access to new features.",
5
5
  "main": "./build/cjs/index.js",
6
6
  "type": "module",
@@ -0,0 +1,62 @@
1
+ {
2
+ "bootstrap-sha": "644c5c883ecbb3786507b50cea01903dc2e533bf",
3
+ "packages": {
4
+ ".": {
5
+ "release-type": "node",
6
+ "changelog-path": "CHANGELOG.md",
7
+ "bump-minor-pre-major": false,
8
+ "bump-patch-for-minor-pre-major": false,
9
+ "draft": false,
10
+ "prerelease": false,
11
+ "include-component-in-tag": false
12
+ }
13
+ },
14
+ "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json",
15
+ "changelog-sections": [
16
+ {
17
+ "type": "feat",
18
+ "hidden": false,
19
+ "section": "Features"
20
+ },
21
+ {
22
+ "type": "fix",
23
+ "hidden": false,
24
+ "section": "Bug Fixes"
25
+ },
26
+ {
27
+ "type": "ci",
28
+ "hidden": false,
29
+ "section": "CI"
30
+ },
31
+ {
32
+ "type": "docs",
33
+ "hidden": false,
34
+ "section": "Docs"
35
+ },
36
+ {
37
+ "type": "deps",
38
+ "hidden": false,
39
+ "section": "Dependency Updates"
40
+ },
41
+ {
42
+ "type": "perf",
43
+ "hidden": false,
44
+ "section": "Performance Improvements"
45
+ },
46
+ {
47
+ "type": "refactor",
48
+ "hidden": false,
49
+ "section": "Refactoring"
50
+ },
51
+ {
52
+ "type": "test",
53
+ "hidden": false,
54
+ "section": "Tests"
55
+ },
56
+ {
57
+ "type": "chore",
58
+ "hidden": false,
59
+ "section": "Other"
60
+ }
61
+ ]
62
+ }
package/sdk/analytics.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { pino, Logger } from 'pino';
2
2
  import { Fetch } from './types.js';
3
3
  import { FlagsmithConfig } from './types.js';
4
+ import { getUserAgent } from './utils.js';
4
5
 
5
6
  export const ANALYTICS_ENDPOINT = './analytics/flags/';
6
7
 
@@ -69,7 +70,8 @@ export class AnalyticsProcessor {
69
70
  signal: AbortSignal.timeout(this.requestTimeoutMs),
70
71
  headers: {
71
72
  'Content-Type': 'application/json',
72
- 'X-Environment-Key': this.environmentKey
73
+ 'X-Environment-Key': this.environmentKey,
74
+ 'User-Agent': getUserAgent()
73
75
  }
74
76
  });
75
77
  await this.currentFlush;
package/sdk/index.ts CHANGED
@@ -14,7 +14,7 @@ import { FlagsmithAPIError } from './errors.js';
14
14
 
15
15
  import { DefaultFlag, Flags } from './models.js';
16
16
  import { EnvironmentDataPollingManager } from './polling_manager.js';
17
- import { Deferred, generateIdentitiesData, retryFetch } from './utils.js';
17
+ import { Deferred, generateIdentitiesData, getUserAgent, retryFetch } from './utils.js';
18
18
  import { SegmentModel } from '../flagsmith-engine/index.js';
19
19
  import { getIdentitySegments } from '../flagsmith-engine/segments/evaluators.js';
20
20
  import {
@@ -329,12 +329,14 @@ export class Flagsmith {
329
329
  url: string,
330
330
  method: string,
331
331
  body?: { [key: string]: any }
332
- ): Promise<any> {
332
+ ): Promise<{ response: Response; data: any }> {
333
333
  const headers: { [key: string]: any } = { 'Content-Type': 'application/json' };
334
334
  if (this.environmentKey) {
335
335
  headers['X-Environment-Key'] = this.environmentKey as string;
336
336
  }
337
337
 
338
+ headers['User-Agent'] = getUserAgent();
339
+
338
340
  if (this.customHeaders) {
339
341
  for (const [k, v] of Object.entries(this.customHeaders)) {
340
342
  headers[k] = v;
@@ -361,7 +363,7 @@ export class Flagsmith {
361
363
  );
362
364
  }
363
365
 
364
- return data.json();
366
+ return { response: data, data: await data.json() };
365
367
  }
366
368
 
367
369
  /**
@@ -391,8 +393,52 @@ export class Flagsmith {
391
393
  if (!this.environmentUrl) {
392
394
  throw new Error('`apiUrl` argument is missing or invalid.');
393
395
  }
394
- const environment_data = await this.getJSONResponse(this.environmentUrl, 'GET');
395
- return buildEnvironmentModel(environment_data);
396
+ const startTime = Date.now();
397
+ const documents: any[] = [];
398
+ let url = this.environmentUrl;
399
+ let loggedWarning = false;
400
+
401
+ while (true) {
402
+ try {
403
+ if (!loggedWarning) {
404
+ const elapsedMs = Date.now() - startTime;
405
+ if (elapsedMs > this.environmentRefreshIntervalSeconds * 1000) {
406
+ this.logger.warn(
407
+ `Environment document retrieval exceeded the polling interval of ${this.environmentRefreshIntervalSeconds} seconds.`
408
+ );
409
+ loggedWarning = true;
410
+ }
411
+ }
412
+
413
+ const { response, data } = await this.getJSONResponse(url, 'GET');
414
+
415
+ documents.push(data);
416
+
417
+ const linkHeader = response.headers.get('link');
418
+ if (linkHeader) {
419
+ const nextMatch = linkHeader.match(/<([^>]+)>;\s*rel="next"/);
420
+
421
+ if (nextMatch) {
422
+ const relativeUrl = decodeURIComponent(nextMatch[1]);
423
+ url = new URL(relativeUrl, this.apiUrl).href;
424
+
425
+ continue;
426
+ }
427
+ }
428
+ break;
429
+ } catch (error) {
430
+ throw error;
431
+ }
432
+ }
433
+
434
+ // Compile the document
435
+ const compiledDocument = documents[0];
436
+ for (let i = 1; i < documents.length; i++) {
437
+ compiledDocument.identity_overrides = compiledDocument.identity_overrides || [];
438
+ compiledDocument.identity_overrides.push(...(documents[i].identity_overrides || []));
439
+ }
440
+
441
+ return buildEnvironmentModel(compiledDocument);
396
442
  }
397
443
 
398
444
  private async getEnvironmentFlagsFromDocument(): Promise<Flags> {
@@ -442,7 +488,7 @@ export class Flagsmith {
442
488
  if (!this.environmentFlagsUrl) {
443
489
  throw new Error('`apiUrl` argument is missing or invalid.');
444
490
  }
445
- const apiFlags = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
491
+ const { data: apiFlags } = await this.getJSONResponse(this.environmentFlagsUrl, 'GET');
446
492
  const flags = Flags.fromAPIFlags({
447
493
  apiFlags: apiFlags,
448
494
  analyticsProcessor: this.analyticsProcessor,
@@ -463,7 +509,7 @@ export class Flagsmith {
463
509
  throw new Error('`apiUrl` argument is missing or invalid.');
464
510
  }
465
511
  const data = generateIdentitiesData(identifier, traits, transient);
466
- const jsonResponse = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
512
+ const { data: jsonResponse } = await this.getJSONResponse(this.identitiesUrl, 'POST', data);
467
513
  const flags = Flags.fromAPIFlags({
468
514
  apiFlags: jsonResponse['flags'],
469
515
  analyticsProcessor: this.analyticsProcessor,
package/sdk/utils.ts CHANGED
@@ -3,6 +3,9 @@ import { Dispatcher } from 'undici-types';
3
3
 
4
4
  type Traits = { [key: string]: TraitConfig | FlagsmithTraitValue };
5
5
 
6
+ const FLAGSMITH_USER_AGENT = 'flagsmith-nodejs-sdk';
7
+ const FLAGSMITH_UNKNOWN_VERSION = 'unknown';
8
+
6
9
  export function isTraitConfig(
7
10
  traitValue: TraitConfig | FlagsmithTraitValue
8
11
  ): traitValue is TraitConfig {
@@ -102,3 +105,13 @@ export class Deferred<T> {
102
105
  this.rejectPromise(reason);
103
106
  }
104
107
  }
108
+
109
+ export function getUserAgent(): string {
110
+ try {
111
+ const packageJson = require('../package.json');
112
+ const version = packageJson?.version;
113
+ return version ? `${FLAGSMITH_USER_AGENT}/${version}` : FLAGSMITH_UNKNOWN_VERSION;
114
+ } catch {
115
+ return FLAGSMITH_UNKNOWN_VERSION;
116
+ }
117
+ }
@@ -12,7 +12,6 @@ import {
12
12
  environmentWithSegmentOverride,
13
13
  feature1,
14
14
  getEnvironmentFeatureStateForFeature,
15
- getEnvironmentFeatureStateForFeatureByName,
16
15
  identity,
17
16
  identityInSegment,
18
17
  segmentConditionProperty,
@@ -1,3 +1,4 @@
1
+ import { getUserAgent } from '../../sdk/utils.js';
1
2
  import { analyticsProcessor, fetch } from './utils.js';
2
3
 
3
4
  test('test_analytics_processor_track_feature_updates_analytics_data', () => {
@@ -26,7 +27,11 @@ test('test_analytics_processor_flush_post_request_data_match_ananlytics_data', a
26
27
  'http://testUrl/analytics/flags/',
27
28
  expect.objectContaining({
28
29
  body: '{"myFeature1":1,"myFeature2":1}',
29
- headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'test-key' },
30
+ headers: {
31
+ 'Content-Type': 'application/json',
32
+ 'X-Environment-Key': 'test-key',
33
+ 'User-Agent': getUserAgent()
34
+ },
30
35
  method: 'POST'
31
36
  })
32
37
  );
@@ -1,6 +1,7 @@
1
1
  import Flagsmith from '../../sdk/index.js';
2
2
  import { environmentJSON, environmentModel, flagsJSON, flagsmith, fetch } from './utils.js';
3
3
  import { DefaultFlag } from '../../sdk/models.js';
4
+ import { getUserAgent } from '../../sdk/utils.js';
4
5
 
5
6
  vi.mock('../../sdk/polling_manager');
6
7
 
@@ -72,6 +73,33 @@ test('test_getFeatureValue', async () => {
72
73
  expect(featureValue).toBe('some-value');
73
74
  });
74
75
 
76
+ test('test_user_agent_is_set_when_fetching_environment_flags', async () => {
77
+ const defaultFlag = new DefaultFlag('some-default-value', true);
78
+
79
+ const defaultFlagHandler = (featureName: string) => defaultFlag;
80
+
81
+ const flg = flagsmith({
82
+ environmentKey: 'key',
83
+ defaultFlagHandler: defaultFlagHandler,
84
+ enableAnalytics: true
85
+ });
86
+ const flags = await flg.getEnvironmentFlags();
87
+ const featureValue = flags.getFeatureValue('some_feature');
88
+
89
+ expect(featureValue).toBe('some-value');
90
+ expect(fetch).toHaveBeenCalledWith(
91
+ `https://edge.api.flagsmith.com/api/v1/flags/`,
92
+ expect.objectContaining({
93
+ method: 'GET',
94
+ headers: {
95
+ 'Content-Type': 'application/json',
96
+ 'X-Environment-Key': 'key',
97
+ 'User-Agent': getUserAgent()
98
+ }
99
+ })
100
+ );
101
+ });
102
+
75
103
  test('test_throws_when_no_default_flag_handler_after_multiple_API_errors', async () => {
76
104
  fetch.mockRejectedValue('Error during fetching the API response');
77
105
 
@@ -9,6 +9,7 @@ import {
9
9
  badFetch
10
10
  } from './utils.js';
11
11
  import { DefaultFlag } from '../../sdk/models.js';
12
+ import { getUserAgent } from '../../sdk/utils.js';
12
13
 
13
14
  vi.mock('../../sdk/polling_manager');
14
15
 
@@ -150,7 +151,11 @@ test('test_transient_identity', async () => {
150
151
  `https://edge.api.flagsmith.com/api/v1/identities/`,
151
152
  expect.objectContaining({
152
153
  method: 'POST',
153
- headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'sometestfakekey' },
154
+ headers: {
155
+ 'Content-Type': 'application/json',
156
+ 'X-Environment-Key': 'sometestfakekey',
157
+ 'User-Agent': getUserAgent()
158
+ },
154
159
  body: JSON.stringify({ identifier, traits: traitsInRequest, transient })
155
160
  })
156
161
  );
@@ -191,7 +196,11 @@ test('test_identity_with_transient_traits', async () => {
191
196
  `https://edge.api.flagsmith.com/api/v1/identities/`,
192
197
  expect.objectContaining({
193
198
  method: 'POST',
194
- headers: { 'Content-Type': 'application/json', 'X-Environment-Key': 'sometestfakekey' },
199
+ headers: {
200
+ 'Content-Type': 'application/json',
201
+ 'X-Environment-Key': 'sometestfakekey',
202
+ 'User-Agent': getUserAgent()
203
+ },
195
204
  body: JSON.stringify({ identifier, traits: traitsInRequest })
196
205
  })
197
206
  );