@posthog/core 1.19.0 → 1.20.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.
@@ -10,6 +10,7 @@ export declare abstract class PostHogCore extends PostHogCoreStateless {
10
10
  private _sessionMaxLengthSeconds;
11
11
  protected sessionProps: PostHogEventProperties;
12
12
  protected _personProfiles: 'always' | 'identified_only' | 'never';
13
+ protected _cachedPersonProperties: string | null;
13
14
  constructor(apiKey: string, options?: PostHogCoreOptions);
14
15
  protected setupBootstrap(options?: Partial<PostHogCoreOptions>): void;
15
16
  private clearProps;
@@ -1 +1 @@
1
- {"version":3,"file":"posthog-core.d.ts","sourceRoot":"","sources":["../src/posthog-core.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"posthog-core.d.ts","sourceRoot":"","sources":["../src/posthog-core.ts"],"names":[],"mappings":"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"}
@@ -39,7 +39,7 @@ class PostHogCore extends external_posthog_core_stateless_js_namespaceObject.Pos
39
39
  ...options,
40
40
  disableGeoip: disableGeoipOption,
41
41
  featureFlagsRequestTimeoutMs
42
- }), this.flagCallReported = {}, this._sessionMaxLengthSeconds = 86400, this.sessionProps = {};
42
+ }), this.flagCallReported = {}, this._sessionMaxLengthSeconds = 86400, this.sessionProps = {}, this._cachedPersonProperties = null;
43
43
  this.sendFeatureFlagEvent = options?.sendFeatureFlagEvent ?? true;
44
44
  this._sessionExpirationTimeSeconds = options?.sessionExpirationTimeSeconds ?? 1800;
45
45
  this._personProfiles = options?.personProfiles ?? 'identified_only';
@@ -94,6 +94,7 @@ class PostHogCore extends external_posthog_core_stateless_js_namespaceObject.Pos
94
94
  ...propertiesToKeep || []
95
95
  ];
96
96
  this.clearProps();
97
+ this._cachedPersonProperties = null;
97
98
  for (const key of Object.keys(external_types_js_namespaceObject.PostHogPersistedProperty))if (!allPropertiesToKeep.includes(external_types_js_namespaceObject.PostHogPersistedProperty[key])) this.setPersistedProperty(external_types_js_namespaceObject.PostHogPersistedProperty[key], null);
98
99
  this.reloadFeatureFlags();
99
100
  });
@@ -176,13 +177,16 @@ class PostHogCore extends external_posthog_core_stateless_js_namespaceObject.Pos
176
177
  ...(0, external_posthog_core_stateless_js_namespaceObject.maybeAdd)('$set', userProps),
177
178
  ...(0, external_posthog_core_stateless_js_namespaceObject.maybeAdd)('$set_once', userPropsOnce)
178
179
  });
180
+ const userPropsObj = (0, index_js_namespaceObject.isObject)(userProps) ? userProps : void 0;
181
+ const userPropsOnceObj = (0, index_js_namespaceObject.isObject)(userPropsOnce) ? userPropsOnce : void 0;
179
182
  if (distinctId !== previousDistinctId) {
180
183
  this.setPersistedProperty(external_types_js_namespaceObject.PostHogPersistedProperty.AnonymousId, previousDistinctId);
181
184
  this.setPersistedProperty(external_types_js_namespaceObject.PostHogPersistedProperty.DistinctId, distinctId);
182
185
  this.setPersistedProperty(external_types_js_namespaceObject.PostHogPersistedProperty.PersonMode, 'identified');
183
186
  this.reloadFeatureFlags();
184
- }
185
- super.identifyStateless(distinctId, allProperties, options);
187
+ super.identifyStateless(distinctId, allProperties, options);
188
+ this._cachedPersonProperties = (0, index_js_namespaceObject.getPersonPropertiesHash)(distinctId, userPropsObj, userPropsOnceObj);
189
+ } else if (userPropsObj || userPropsOnceObj) this.setPersonProperties(userPropsObj, userPropsOnceObj);
186
190
  });
187
191
  }
188
192
  capture(event, properties, options) {
@@ -635,6 +639,8 @@ class PostHogCore extends external_posthog_core_stateless_js_namespaceObject.Pos
635
639
  const isSetOnceEmpty = (0, index_js_namespaceObject.isNullish)(userPropertiesToSetOnce) || (0, index_js_namespaceObject.isEmptyObject)(userPropertiesToSetOnce);
636
640
  if (isSetEmpty && isSetOnceEmpty) return;
637
641
  if (!this._requirePersonProcessing('posthog.setPersonProperties')) return;
642
+ const hash = (0, index_js_namespaceObject.getPersonPropertiesHash)(this.getDistinctId(), userPropertiesToSet, userPropertiesToSetOnce);
643
+ if (this._cachedPersonProperties === hash) return void this._logger.info('A duplicate setPersonProperties call was made with the same properties. It has been ignored.');
638
644
  const mergedProperties = {
639
645
  ...userPropertiesToSetOnce || {},
640
646
  ...userPropertiesToSet || {}
@@ -644,6 +650,7 @@ class PostHogCore extends external_posthog_core_stateless_js_namespaceObject.Pos
644
650
  $set: userPropertiesToSet || {},
645
651
  $set_once: userPropertiesToSetOnce || {}
646
652
  });
653
+ this._cachedPersonProperties = hash;
647
654
  });
648
655
  }
649
656
  processBeforeEnqueue(message) {
@@ -2,7 +2,7 @@ import { createFlagsResponseFromFlagsAndPayloads, getFeatureFlagValue, getFlagVa
2
2
  import { Compression, FeatureFlagError, PostHogPersistedProperty } from "./types.mjs";
3
3
  import { PostHogCoreStateless, QuotaLimitedFeature, maybeAdd } from "./posthog-core-stateless.mjs";
4
4
  import { uuidv7 } from "./vendor/uuidv7.mjs";
5
- import { isEmptyObject, isNullish, isPlainError } from "./utils/index.mjs";
5
+ import { getPersonPropertiesHash, isEmptyObject, isNullish, isObject, isPlainError } from "./utils/index.mjs";
6
6
  class PostHogCore extends PostHogCoreStateless {
7
7
  constructor(apiKey, options){
8
8
  const disableGeoipOption = options?.disableGeoip ?? false;
@@ -11,7 +11,7 @@ class PostHogCore extends PostHogCoreStateless {
11
11
  ...options,
12
12
  disableGeoip: disableGeoipOption,
13
13
  featureFlagsRequestTimeoutMs
14
- }), this.flagCallReported = {}, this._sessionMaxLengthSeconds = 86400, this.sessionProps = {};
14
+ }), this.flagCallReported = {}, this._sessionMaxLengthSeconds = 86400, this.sessionProps = {}, this._cachedPersonProperties = null;
15
15
  this.sendFeatureFlagEvent = options?.sendFeatureFlagEvent ?? true;
16
16
  this._sessionExpirationTimeSeconds = options?.sessionExpirationTimeSeconds ?? 1800;
17
17
  this._personProfiles = options?.personProfiles ?? 'identified_only';
@@ -66,6 +66,7 @@ class PostHogCore extends PostHogCoreStateless {
66
66
  ...propertiesToKeep || []
67
67
  ];
68
68
  this.clearProps();
69
+ this._cachedPersonProperties = null;
69
70
  for (const key of Object.keys(PostHogPersistedProperty))if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) this.setPersistedProperty(PostHogPersistedProperty[key], null);
70
71
  this.reloadFeatureFlags();
71
72
  });
@@ -148,13 +149,16 @@ class PostHogCore extends PostHogCoreStateless {
148
149
  ...maybeAdd('$set', userProps),
149
150
  ...maybeAdd('$set_once', userPropsOnce)
150
151
  });
152
+ const userPropsObj = isObject(userProps) ? userProps : void 0;
153
+ const userPropsOnceObj = isObject(userPropsOnce) ? userPropsOnce : void 0;
151
154
  if (distinctId !== previousDistinctId) {
152
155
  this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId);
153
156
  this.setPersistedProperty(PostHogPersistedProperty.DistinctId, distinctId);
154
157
  this.setPersistedProperty(PostHogPersistedProperty.PersonMode, 'identified');
155
158
  this.reloadFeatureFlags();
156
- }
157
- super.identifyStateless(distinctId, allProperties, options);
159
+ super.identifyStateless(distinctId, allProperties, options);
160
+ this._cachedPersonProperties = getPersonPropertiesHash(distinctId, userPropsObj, userPropsOnceObj);
161
+ } else if (userPropsObj || userPropsOnceObj) this.setPersonProperties(userPropsObj, userPropsOnceObj);
158
162
  });
159
163
  }
160
164
  capture(event, properties, options) {
@@ -607,6 +611,8 @@ class PostHogCore extends PostHogCoreStateless {
607
611
  const isSetOnceEmpty = isNullish(userPropertiesToSetOnce) || isEmptyObject(userPropertiesToSetOnce);
608
612
  if (isSetEmpty && isSetOnceEmpty) return;
609
613
  if (!this._requirePersonProcessing('posthog.setPersonProperties')) return;
614
+ const hash = getPersonPropertiesHash(this.getDistinctId(), userPropertiesToSet, userPropertiesToSetOnce);
615
+ if (this._cachedPersonProperties === hash) return void this._logger.info('A duplicate setPersonProperties call was made with the same properties. It has been ignored.');
610
616
  const mergedProperties = {
611
617
  ...userPropertiesToSetOnce || {},
612
618
  ...userPropertiesToSet || {}
@@ -616,6 +622,7 @@ class PostHogCore extends PostHogCoreStateless {
616
622
  $set: userPropertiesToSet || {},
617
623
  $set_once: userPropertiesToSetOnce || {}
618
624
  });
625
+ this._cachedPersonProperties = hash;
619
626
  });
620
627
  }
621
628
  processBeforeEnqueue(message) {
@@ -1,6 +1,17 @@
1
+ import type { JsonType } from '../types';
1
2
  export declare function includes(str: string, needle: string): boolean;
2
3
  export declare function includes<T>(arr: T[], needle: T): boolean;
3
4
  export declare const trim: (str: string) => string;
4
5
  export declare const stripLeadingDollar: (s: string) => string;
5
6
  export declare function isDistinctIdStringLike(value: string): boolean;
7
+ /**
8
+ * Creates a hash string from distinct_id and person properties.
9
+ * Used to detect if person properties have changed to avoid duplicate $set events.
10
+ * Uses sorted keys to ensure consistent ordering regardless of object construction order.
11
+ */
12
+ export declare function getPersonPropertiesHash(distinct_id: string, userPropertiesToSet?: {
13
+ [key: string]: JsonType;
14
+ }, userPropertiesToSetOnce?: {
15
+ [key: string]: JsonType;
16
+ }): string;
6
17
  //# sourceMappingURL=string-utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAA;AAKzD,eAAO,MAAM,IAAI,GAAa,KAAK,MAAM,KAAG,MAM3C,CAAA;AAID,eAAO,MAAM,kBAAkB,GAAa,GAAG,MAAM,KAAG,MAEvD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7D"}
1
+ {"version":3,"file":"string-utils.d.ts","sourceRoot":"","sources":["../../src/utils/string-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AAExC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAA;AAC9D,wBAAgB,QAAQ,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,GAAG,OAAO,CAAA;AAKzD,eAAO,MAAM,IAAI,GAAa,KAAK,MAAM,KAAG,MAM3C,CAAA;AAID,eAAO,MAAM,kBAAkB,GAAa,GAAG,MAAM,KAAG,MAEvD,CAAA;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE7D;AAuBD;;;;GAIG;AACH,wBAAgB,uBAAuB,CACrC,WAAW,EAAE,MAAM,EACnB,mBAAmB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,EACjD,uBAAuB,CAAC,EAAE;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAA;CAAE,GACpD,MAAM,CAMR"}
@@ -24,6 +24,7 @@ var __webpack_require__ = {};
24
24
  var __webpack_exports__ = {};
25
25
  __webpack_require__.r(__webpack_exports__);
26
26
  __webpack_require__.d(__webpack_exports__, {
27
+ getPersonPropertiesHash: ()=>getPersonPropertiesHash,
27
28
  includes: ()=>includes,
28
29
  isDistinctIdStringLike: ()=>isDistinctIdStringLike,
29
30
  stripLeadingDollar: ()=>stripLeadingDollar,
@@ -44,11 +45,28 @@ function isDistinctIdStringLike(value) {
44
45
  'distinctid'
45
46
  ].includes(value.toLowerCase());
46
47
  }
48
+ function deepSortKeys(value) {
49
+ if (null === value || 'object' != typeof value) return value;
50
+ if (Array.isArray(value)) return value.map(deepSortKeys);
51
+ return Object.keys(value).sort().reduce((acc, key)=>{
52
+ acc[key] = deepSortKeys(value[key]);
53
+ return acc;
54
+ }, {});
55
+ }
56
+ function getPersonPropertiesHash(distinct_id, userPropertiesToSet, userPropertiesToSetOnce) {
57
+ return JSON.stringify({
58
+ distinct_id,
59
+ userPropertiesToSet: userPropertiesToSet ? deepSortKeys(userPropertiesToSet) : void 0,
60
+ userPropertiesToSetOnce: userPropertiesToSetOnce ? deepSortKeys(userPropertiesToSetOnce) : void 0
61
+ });
62
+ }
63
+ exports.getPersonPropertiesHash = __webpack_exports__.getPersonPropertiesHash;
47
64
  exports.includes = __webpack_exports__.includes;
48
65
  exports.isDistinctIdStringLike = __webpack_exports__.isDistinctIdStringLike;
49
66
  exports.stripLeadingDollar = __webpack_exports__.stripLeadingDollar;
50
67
  exports.trim = __webpack_exports__.trim;
51
68
  for(var __webpack_i__ in __webpack_exports__)if (-1 === [
69
+ "getPersonPropertiesHash",
52
70
  "includes",
53
71
  "isDistinctIdStringLike",
54
72
  "stripLeadingDollar",
@@ -13,4 +13,19 @@ function isDistinctIdStringLike(value) {
13
13
  'distinctid'
14
14
  ].includes(value.toLowerCase());
15
15
  }
16
- export { includes, isDistinctIdStringLike, stripLeadingDollar, trim };
16
+ function deepSortKeys(value) {
17
+ if (null === value || 'object' != typeof value) return value;
18
+ if (Array.isArray(value)) return value.map(deepSortKeys);
19
+ return Object.keys(value).sort().reduce((acc, key)=>{
20
+ acc[key] = deepSortKeys(value[key]);
21
+ return acc;
22
+ }, {});
23
+ }
24
+ function getPersonPropertiesHash(distinct_id, userPropertiesToSet, userPropertiesToSetOnce) {
25
+ return JSON.stringify({
26
+ distinct_id,
27
+ userPropertiesToSet: userPropertiesToSet ? deepSortKeys(userPropertiesToSet) : void 0,
28
+ userPropertiesToSetOnce: userPropertiesToSetOnce ? deepSortKeys(userPropertiesToSetOnce) : void 0
29
+ });
30
+ }
31
+ export { getPersonPropertiesHash, includes, isDistinctIdStringLike, stripLeadingDollar, trim };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@posthog/core",
3
- "version": "1.19.0",
3
+ "version": "1.20.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -30,7 +30,7 @@ import {
30
30
  import { Compression, FeatureFlagError, PostHogPersistedProperty } from './types'
31
31
  import { maybeAdd, PostHogCoreStateless, QuotaLimitedFeature } from './posthog-core-stateless'
32
32
  import { uuidv7 } from './vendor/uuidv7'
33
- import { isEmptyObject, isNullish, isPlainError } from './utils'
33
+ import { isEmptyObject, isNullish, isPlainError, getPersonPropertiesHash, isObject } from './utils'
34
34
 
35
35
  export abstract class PostHogCore extends PostHogCoreStateless {
36
36
  // options
@@ -47,6 +47,9 @@ export abstract class PostHogCore extends PostHogCoreStateless {
47
47
  // person profiles
48
48
  protected _personProfiles: 'always' | 'identified_only' | 'never'
49
49
 
50
+ // cache for person properties to avoid duplicate $set events
51
+ protected _cachedPersonProperties: string | null = null
52
+
50
53
  constructor(apiKey: string, options?: PostHogCoreOptions) {
51
54
  // Default for stateful mode is to not disable geoip. Only override if explicitly set
52
55
  const disableGeoipOption = options?.disableGeoip ?? false
@@ -130,6 +133,9 @@ export abstract class PostHogCore extends PostHogCoreStateless {
130
133
  // clean up props
131
134
  this.clearProps()
132
135
 
136
+ // clear cached person properties
137
+ this._cachedPersonProperties = null
138
+
133
139
  for (const key of <(keyof typeof PostHogPersistedProperty)[]>Object.keys(PostHogPersistedProperty)) {
134
140
  if (!allPropertiesToKeep.includes(PostHogPersistedProperty[key])) {
135
141
  this.setPersistedProperty((PostHogPersistedProperty as any)[key], null)
@@ -294,6 +300,10 @@ export abstract class PostHogCore extends PostHogCoreStateless {
294
300
  ...maybeAdd('$set_once', userPropsOnce),
295
301
  })
296
302
 
303
+ // Safely cast userProps and userPropsOnce to object types for hash and setPersonProperties
304
+ const userPropsObj = isObject(userProps) ? (userProps as { [key: string]: JsonType }) : undefined
305
+ const userPropsOnceObj = isObject(userPropsOnce) ? (userPropsOnce as { [key: string]: JsonType }) : undefined
306
+
297
307
  if (distinctId !== previousDistinctId) {
298
308
  // We keep the AnonymousId to be used by flags calls and identify to link the previousId
299
309
  this.setPersistedProperty(PostHogPersistedProperty.AnonymousId, previousDistinctId)
@@ -301,9 +311,16 @@ export abstract class PostHogCore extends PostHogCoreStateless {
301
311
  // Mark the user as identified
302
312
  this.setPersistedProperty(PostHogPersistedProperty.PersonMode, 'identified')
303
313
  this.reloadFeatureFlags()
304
- }
305
314
 
306
- super.identifyStateless(distinctId, allProperties, options)
315
+ super.identifyStateless(distinctId, allProperties, options)
316
+
317
+ // Update the cached person properties hash
318
+ this._cachedPersonProperties = getPersonPropertiesHash(distinctId, userPropsObj, userPropsOnceObj)
319
+ } else if (userPropsObj || userPropsOnceObj) {
320
+ // If the distinct_id is not changing, but we have user properties to set, we can check if they have changed
321
+ // and if so, send a $set event
322
+ this.setPersonProperties(userPropsObj, userPropsOnceObj)
323
+ }
307
324
  })
308
325
  }
309
326
 
@@ -1218,12 +1235,24 @@ export abstract class PostHogCore extends PostHogCoreStateless {
1218
1235
  return
1219
1236
  }
1220
1237
 
1238
+ const hash = getPersonPropertiesHash(this.getDistinctId(), userPropertiesToSet, userPropertiesToSetOnce)
1239
+
1240
+ // If exactly this $set call has been sent before, don't send it again - determine based on hash of properties
1241
+ if (this._cachedPersonProperties === hash) {
1242
+ this._logger.info(
1243
+ 'A duplicate setPersonProperties call was made with the same properties. It has been ignored.'
1244
+ )
1245
+ return
1246
+ }
1247
+
1221
1248
  // Update person properties for feature flags evaluation
1222
1249
  // Merge setOnce first, then set to allow overwriting
1223
1250
  const mergedProperties = { ...(userPropertiesToSetOnce || {}), ...(userPropertiesToSet || {}) }
1224
1251
  this.setPersonPropertiesForFlags(mergedProperties, reloadFeatureFlags)
1225
1252
 
1226
1253
  this.capture('$set', { $set: userPropertiesToSet || {}, $set_once: userPropertiesToSetOnce || {} })
1254
+
1255
+ this._cachedPersonProperties = hash
1227
1256
  })
1228
1257
  }
1229
1258
 
@@ -0,0 +1,121 @@
1
+ import { getPersonPropertiesHash } from './string-utils'
2
+
3
+ describe('string-utils', () => {
4
+ describe('getPersonPropertiesHash', () => {
5
+ it('should return consistent hash regardless of top-level key order', () => {
6
+ const hash1 = getPersonPropertiesHash('user-1', { b: 'value-b', a: 'value-a' })
7
+ const hash2 = getPersonPropertiesHash('user-1', { a: 'value-a', b: 'value-b' })
8
+ expect(hash1).toBe(hash2)
9
+ })
10
+
11
+ it('should return consistent hash regardless of nested object key order', () => {
12
+ const hash1 = getPersonPropertiesHash('user-1', {
13
+ nested: { z: 1, a: 2 },
14
+ })
15
+ const hash2 = getPersonPropertiesHash('user-1', {
16
+ nested: { a: 2, z: 1 },
17
+ })
18
+ expect(hash1).toBe(hash2)
19
+ })
20
+
21
+ it('should return consistent hash for deeply nested objects', () => {
22
+ const hash1 = getPersonPropertiesHash('user-1', {
23
+ level1: {
24
+ level2: {
25
+ level3: { c: 3, a: 1, b: 2 },
26
+ },
27
+ },
28
+ })
29
+ const hash2 = getPersonPropertiesHash('user-1', {
30
+ level1: {
31
+ level2: {
32
+ level3: { a: 1, b: 2, c: 3 },
33
+ },
34
+ },
35
+ })
36
+ expect(hash1).toBe(hash2)
37
+ })
38
+
39
+ it('should handle arrays with nested objects', () => {
40
+ const hash1 = getPersonPropertiesHash('user-1', {
41
+ items: [
42
+ { z: 1, a: 2 },
43
+ { y: 3, b: 4 },
44
+ ],
45
+ })
46
+ const hash2 = getPersonPropertiesHash('user-1', {
47
+ items: [
48
+ { a: 2, z: 1 },
49
+ { b: 4, y: 3 },
50
+ ],
51
+ })
52
+ expect(hash1).toBe(hash2)
53
+ })
54
+
55
+ it('should preserve array order (not sort array elements)', () => {
56
+ const hash1 = getPersonPropertiesHash('user-1', {
57
+ items: [1, 2, 3],
58
+ })
59
+ const hash2 = getPersonPropertiesHash('user-1', {
60
+ items: [3, 2, 1],
61
+ })
62
+ expect(hash1).not.toBe(hash2)
63
+ })
64
+
65
+ it('should handle null values', () => {
66
+ const hash1 = getPersonPropertiesHash('user-1', { a: null, b: 'value' })
67
+ const hash2 = getPersonPropertiesHash('user-1', { b: 'value', a: null })
68
+ expect(hash1).toBe(hash2)
69
+ })
70
+
71
+ it('should handle primitive values', () => {
72
+ const hash1 = getPersonPropertiesHash('user-1', {
73
+ str: 'string',
74
+ num: 42,
75
+ bool: true,
76
+ nil: null,
77
+ })
78
+ const hash2 = getPersonPropertiesHash('user-1', {
79
+ nil: null,
80
+ bool: true,
81
+ num: 42,
82
+ str: 'string',
83
+ })
84
+ expect(hash1).toBe(hash2)
85
+ })
86
+
87
+ it('should handle userPropertiesToSetOnce with nested objects', () => {
88
+ const hash1 = getPersonPropertiesHash('user-1', undefined, {
89
+ nested: { z: 1, a: 2 },
90
+ })
91
+ const hash2 = getPersonPropertiesHash('user-1', undefined, {
92
+ nested: { a: 2, z: 1 },
93
+ })
94
+ expect(hash1).toBe(hash2)
95
+ })
96
+
97
+ it('should handle both userPropertiesToSet and userPropertiesToSetOnce', () => {
98
+ const hash1 = getPersonPropertiesHash('user-1', { nested: { z: 1, a: 2 } }, { other: { y: 3, b: 4 } })
99
+ const hash2 = getPersonPropertiesHash('user-1', { nested: { a: 2, z: 1 } }, { other: { b: 4, y: 3 } })
100
+ expect(hash1).toBe(hash2)
101
+ })
102
+
103
+ it('should return different hash for different distinct_id', () => {
104
+ const hash1 = getPersonPropertiesHash('user-1', { a: 1 })
105
+ const hash2 = getPersonPropertiesHash('user-2', { a: 1 })
106
+ expect(hash1).not.toBe(hash2)
107
+ })
108
+
109
+ it('should return different hash for different property values', () => {
110
+ const hash1 = getPersonPropertiesHash('user-1', { a: 1 })
111
+ const hash2 = getPersonPropertiesHash('user-1', { a: 2 })
112
+ expect(hash1).not.toBe(hash2)
113
+ })
114
+
115
+ it('should handle undefined properties', () => {
116
+ const hash1 = getPersonPropertiesHash('user-1')
117
+ const hash2 = getPersonPropertiesHash('user-1', undefined, undefined)
118
+ expect(hash1).toBe(hash2)
119
+ })
120
+ })
121
+ })
@@ -1,3 +1,5 @@
1
+ import type { JsonType } from '../types'
2
+
1
3
  export function includes(str: string, needle: string): boolean
2
4
  export function includes<T>(arr: T[], needle: T): boolean
3
5
  export function includes(str: unknown[] | string, needle: unknown): boolean {
@@ -21,3 +23,41 @@ export const stripLeadingDollar = function (s: string): string {
21
23
  export function isDistinctIdStringLike(value: string): boolean {
22
24
  return ['distinct_id', 'distinctid'].includes(value.toLowerCase())
23
25
  }
26
+
27
+ /**
28
+ * Recursively sorts all keys in an object and its nested objects/arrays.
29
+ * Used to ensure deterministic JSON serialization regardless of object construction order.
30
+ */
31
+ function deepSortKeys(value: JsonType): JsonType {
32
+ if (value === null || typeof value !== 'object') {
33
+ return value
34
+ }
35
+
36
+ if (Array.isArray(value)) {
37
+ return value.map(deepSortKeys)
38
+ }
39
+
40
+ return Object.keys(value)
41
+ .sort()
42
+ .reduce((acc: { [key: string]: JsonType }, key) => {
43
+ acc[key] = deepSortKeys(value[key])
44
+ return acc
45
+ }, {})
46
+ }
47
+
48
+ /**
49
+ * Creates a hash string from distinct_id and person properties.
50
+ * Used to detect if person properties have changed to avoid duplicate $set events.
51
+ * Uses sorted keys to ensure consistent ordering regardless of object construction order.
52
+ */
53
+ export function getPersonPropertiesHash(
54
+ distinct_id: string,
55
+ userPropertiesToSet?: { [key: string]: JsonType },
56
+ userPropertiesToSetOnce?: { [key: string]: JsonType }
57
+ ): string {
58
+ return JSON.stringify({
59
+ distinct_id,
60
+ userPropertiesToSet: userPropertiesToSet ? deepSortKeys(userPropertiesToSet) : undefined,
61
+ userPropertiesToSetOnce: userPropertiesToSetOnce ? deepSortKeys(userPropertiesToSetOnce) : undefined,
62
+ })
63
+ }