@segment/analytics-browser-actions-heap 1.70.1 → 1.72.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.
@@ -1,15 +1,9 @@
1
1
  import { Analytics, Context } from '@segment/analytics-next'
2
- import {
3
- createMockedHeapJsSdk,
4
- HEAP_TEST_ENV_ID,
5
- identifyUserSubscription,
6
- mockHeapJsHttpRequest
7
- } from '../../test-utilities'
2
+ import { createMockedHeapJsSdk, HEAP_TEST_ENV_ID, identifyUserSubscription } from '../../test-utilities'
8
3
  import heapDestination from '../../index'
9
4
 
10
5
  describe('#identify', () => {
11
6
  it('should not call identify if user id is not provided and anonymous user id is provided', async () => {
12
- mockHeapJsHttpRequest()
13
7
  window.heap = createMockedHeapJsSdk()
14
8
 
15
9
  const [identifyUser] = await heapDestination({ appId: HEAP_TEST_ENV_ID, subscriptions: [identifyUserSubscription] })
@@ -31,7 +25,6 @@ describe('#identify', () => {
31
25
  })
32
26
 
33
27
  it('should call identify if user id is provided', async () => {
34
- mockHeapJsHttpRequest()
35
28
  window.heap = createMockedHeapJsSdk()
36
29
 
37
30
  const [identifyUser] = await heapDestination({ appId: HEAP_TEST_ENV_ID, subscriptions: [identifyUserSubscription] })
@@ -53,7 +46,6 @@ describe('#identify', () => {
53
46
  })
54
47
 
55
48
  it('should call addUserProprties if traits are provided', async () => {
56
- mockHeapJsHttpRequest()
57
49
  window.heap = createMockedHeapJsSdk()
58
50
 
59
51
  const [identifyUser] = await heapDestination({ appId: HEAP_TEST_ENV_ID, subscriptions: [identifyUserSubscription] })
package/src/index.ts CHANGED
@@ -1,14 +1,16 @@
1
1
  import type { Settings } from './generated-types'
2
2
  import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
3
3
  import { browserDestination } from '@segment/browser-destination-runtime/shim'
4
- import { HeapApi, UserConfig } from './types'
4
+ import type { HeapApi, HeapMethods, UserConfig } from './types'
5
5
  import { defaultValues } from '@segment/actions-core'
6
6
  import trackEvent from './trackEvent'
7
7
  import identifyUser from './identifyUser'
8
+ import { initScript } from './init-script'
8
9
  import { isDefined } from './utils'
9
10
 
10
11
  declare global {
11
12
  interface Window {
13
+ heapReadyCb: Array<{ name: HeapMethods; fn: () => void }>
12
14
  heap: HeapApi
13
15
  }
14
16
  }
@@ -46,28 +48,35 @@ export const destination: BrowserDestinationDefinition<Settings, HeapApi> = {
46
48
  disableTextCapture: {
47
49
  label: 'Global data redaction via Disabling Text Capture',
48
50
  description:
49
- 'Setting to true will redact all target text on your website. For more information visit the heap [docs page](https://developers.heap.io/docs/web#global-data-redaction-via-disabling-text-capture).',
51
+ 'Setting to true will redact all target text on your website. For more information visit the Heap [docs page](https://developers.heap.io/docs/web#global-data-redaction-via-disabling-text-capture).',
50
52
  type: 'boolean',
51
53
  required: false
52
54
  },
53
55
  secureCookie: {
54
56
  label: 'Secure Cookie',
55
57
  description:
56
- 'This option is turned off by default to accommodate websites not served over HTTPS. If your application uses HTTPS, we recommend enabling secure cookies to prevent Heap cookies from being observed by unauthorized parties. For more information visit the heap [docs page](https://developers.heap.io/docs/web#securecookie).',
58
+ 'This option is turned off by default to accommodate websites not served over HTTPS. If your application uses HTTPS, we recommend enabling secure cookies to prevent Heap cookies from being observed by unauthorized parties. For more information visit the Heap [docs page](https://developers.heap.io/docs/web#securecookie).',
57
59
  type: 'boolean',
58
60
  required: false
59
61
  },
60
62
  trackingServer: {
61
- label: 'Tracking Server',
63
+ label: 'Tracking Server (deprecated)',
62
64
  description:
63
- 'This is an optional setting. This is used to set up first-party data collection. For most cased this should not be set. For more information visit the heap [docs page](https://developers.heap.io/docs/set-up-first-party-data-collection-in-heap).',
65
+ 'This is an optional setting. This is used to set up first-party data collection. For most cased this should not be set. For more information visit the Heap [docs page](https://developers.heap.io/docs/set-up-first-party-data-collection-in-heap). This field is deprecated in favor of `ingestServer`. If `trackingServer` is set and `ingestServer` is not set, then the Classic SDK will be loaded. If both are set, `ingestServer` will take precedence, and the latest stable version of the Heap SDK will be loaded.',
66
+ type: 'string',
67
+ required: false
68
+ },
69
+ ingestServer: {
70
+ label: 'Ingest Server',
71
+ description:
72
+ 'This is an optional setting. This is used to set up first-party data collection. For most cased this should not be set. For more information visit the Heap [docs page](https://developers.heap.io/docs/web#ingestserver).',
64
73
  type: 'string',
65
74
  required: false
66
75
  },
67
76
  hostname: {
68
77
  label: 'Hostname',
69
78
  description:
70
- 'This is an optional setting used to set the host that loads heap-js. This setting is used when heapJS is self-hosted. In most cased this should be left unset. The hostname should not contain https or app id it will be populated like so: https://${hostname}/js/heap-${appId}.js. For more information visit the heap [docs page](https://developers.heap.io/docs/self-hosting-heapjs).',
79
+ 'This is an optional setting used to set the host that loads the Heap SDK. This setting is used when the Heap SDK is self-hosted. In most cased this should be left unset. The hostname should not contain https or app id. When _both_ `hostname` and `trackingServer` are set, the Classic SDK will be loaded via: `https://${hostname}/js/heap-${appId}.js`. If `hostname` is set and `trackingServer` is not set, then the latest version of the Heap SDK will be loaded via: `https://${settings.hostname}/config/${settings.appId}/heap_config.js`. For more information visit the Heap [docs page](https://developers.heap.io/docs/self-hosting-heapjs).',
71
80
  type: 'string',
72
81
  required: false
73
82
  },
@@ -87,26 +96,29 @@ export const destination: BrowserDestinationDefinition<Settings, HeapApi> = {
87
96
 
88
97
  const config: UserConfig = {
89
98
  disableTextCapture: settings.disableTextCapture || false,
90
- secureCookie: settings.secureCookie || false
99
+ secureCookie: settings.secureCookie || false,
100
+ ...(settings.ingestServer && { ingestServer: settings.ingestServer }),
101
+ // For backward compatibility. See https://developers.heap.io/docs/web#ingestserver
102
+ ...(settings.trackingServer && { trackingServer: settings.trackingServer })
91
103
  }
92
104
 
93
- if (settings.trackingServer) {
94
- config.trackingServer = settings.trackingServer
95
- }
96
-
97
- // heap.appid and heap.config must be set before loading heap.js.
98
- window.heap = window.heap || []
99
- window.heap.appid = settings.appId
100
- window.heap.config = config
105
+ initScript(settings.appId, config)
101
106
 
102
- if (isDefined(settings.hostname)) {
107
+ // if both hostname and trackingServer are set, load classic SDK from hostname
108
+ if (isDefined(settings.hostname) && isDefined(settings.trackingServer)) {
103
109
  await deps.loadScript(`https://${settings.hostname}/js/heap-${settings.appId}.js`)
104
- } else {
105
- await deps.loadScript(`https://cdn.heapanalytics.com/js/heap-${settings.appId}.js`)
110
+ }
111
+ // if only hostname is set, load latest version of SDK from hostname
112
+ else if (isDefined(settings.hostname) && !isDefined(settings.trackingServer)) {
113
+ await deps.loadScript(`https://${settings.hostname}/config/${settings.appId}/heap_config.js`)
114
+ }
115
+ // default to loading latest version of SDK from heap CDN
116
+ else {
117
+ await deps.loadScript(`https://cdn.us.heap-api.com/config/${settings.appId}/heap_config.js`)
106
118
  }
107
119
 
108
120
  // Explained here: https://stackoverflow.com/questions/14859058/why-does-the-segment-io-loader-script-push-method-names-args-onto-a-queue-which
109
- await deps.resolveWhen(() => Object.prototype.hasOwnProperty.call(window, 'heap'), 100)
121
+ await deps.resolveWhen(() => window.heap.loaded === true, 300)
110
122
 
111
123
  return window.heap
112
124
  },
@@ -0,0 +1,69 @@
1
+ import type { HeapMethods, UserConfig } from './types'
2
+
3
+ /**
4
+ * Initialize the Heap script with the provided environment ID and configuration.
5
+ */
6
+ export const initScript = (envId: string, config: UserConfig) => {
7
+ // Ensure heapReadyCb exists on the window object
8
+ window.heapReadyCb = window.heapReadyCb || []
9
+
10
+ // Ensure heap exists on the window object
11
+ window.heap = window.heap || ({} as any)
12
+
13
+ window.heap.load = function (
14
+ envId: string,
15
+ clientConfig: UserConfig = { disableTextCapture: false, secureCookie: false }
16
+ ): void {
17
+ window.heap.envId = envId
18
+ window.heap.clientConfig = clientConfig
19
+ window.heap.clientConfig.shouldFetchServerConfig = false
20
+
21
+ // Define all Heap API methods and add them to the heap object
22
+ const methods: HeapMethods[] = [
23
+ 'init',
24
+ 'startTracking',
25
+ 'stopTracking',
26
+ 'track',
27
+ 'resetIdentity',
28
+ 'identify',
29
+ 'identifyHashed',
30
+ 'getSessionId',
31
+ 'getUserId',
32
+ 'getIdentity',
33
+ 'addUserProperties',
34
+ 'addEventProperties',
35
+ 'removeEventProperty',
36
+ 'clearEventProperties',
37
+ 'addAccountProperties',
38
+ 'addAdapter',
39
+ 'addTransformer',
40
+ 'addTransformerFn',
41
+ 'onReady',
42
+ 'addPageviewProperties',
43
+ 'removePageviewProperty',
44
+ 'clearPageviewProperties',
45
+ 'trackPageview'
46
+ ]
47
+
48
+ const createMethodProxy = (methodName: HeapMethods) => {
49
+ return function (...args: any[]) {
50
+ // Push method calls to heapReadyCb until the script is fully loaded
51
+ window.heapReadyCb.push({
52
+ name: methodName,
53
+ fn: () => {
54
+ if (window.heap[methodName]) {
55
+ window.heap[methodName](...args)
56
+ }
57
+ }
58
+ })
59
+ }
60
+ }
61
+
62
+ // Proxy all methods to heap
63
+ for (const method of methods) {
64
+ window.heap[method] = createMethodProxy(method)
65
+ }
66
+ }
67
+
68
+ window.heap.load(envId, config)
69
+ }
@@ -1,12 +1,11 @@
1
- import { HeapApi } from './types'
2
- import { Subscription } from '@segment/browser-destination-runtime/types'
3
- import nock from 'nock'
1
+ import type { HeapApi } from './types'
4
2
 
5
3
  export const HEAP_TEST_ENV_ID = '1'
6
4
 
7
5
  export const createMockedHeapJsSdk = (): HeapApi => {
8
6
  return {
9
7
  appid: HEAP_TEST_ENV_ID,
8
+ envId: HEAP_TEST_ENV_ID,
10
9
  config: {
11
10
  disableTextCapture: true,
12
11
  secureCookie: true
@@ -14,10 +13,31 @@ export const createMockedHeapJsSdk = (): HeapApi => {
14
13
  load: jest.fn(),
15
14
  track: jest.fn(),
16
15
  identify: jest.fn(),
17
- addUserProperties: jest.fn()
16
+ addUserProperties: jest.fn(),
17
+ init: jest.fn(),
18
+ startTracking: jest.fn(),
19
+ stopTracking: jest.fn(),
20
+ resetIdentity: jest.fn(),
21
+ identifyHashed: jest.fn(),
22
+ getSessionId: jest.fn(),
23
+ getUserId: jest.fn(),
24
+ getIdentity: jest.fn(),
25
+ addEventProperties: jest.fn(),
26
+ removeEventProperty: jest.fn(),
27
+ clearEventProperties: jest.fn(),
28
+ addAccountProperties: jest.fn(),
29
+ addAdapter: jest.fn(),
30
+ addTransformer: jest.fn(),
31
+ addTransformerFn: jest.fn(),
32
+ onReady: jest.fn(),
33
+ addPageviewProperties: jest.fn(),
34
+ removePageviewProperty: jest.fn(),
35
+ clearPageviewProperties: jest.fn(),
36
+ trackPageview: jest.fn()
18
37
  }
19
38
  }
20
- export const trackEventSubscription: Subscription = {
39
+
40
+ export const trackEventSubscription = {
21
41
  partnerAction: 'trackEvent',
22
42
  name: 'Track Event',
23
43
  enabled: true,
@@ -41,7 +61,7 @@ export const trackEventSubscription: Subscription = {
41
61
  }
42
62
  }
43
63
 
44
- export const identifyUserSubscription: Subscription = {
64
+ export const identifyUserSubscription = {
45
65
  partnerAction: 'identifyUser',
46
66
  name: 'Identify User',
47
67
  enabled: true,
@@ -58,7 +78,3 @@ export const identifyUserSubscription: Subscription = {
58
78
  }
59
79
  }
60
80
  }
61
-
62
- export const mockHeapJsHttpRequest = (): void => {
63
- nock('https://cdn.heapanalytics.com').get(`/js/heap-${HEAP_TEST_ENV_ID}.js`).reply(200, {})
64
- }
@@ -1,11 +1,6 @@
1
1
  import { Analytics, Context, Plugin } from '@segment/analytics-next'
2
2
  import heapDestination from '../../index'
3
- import {
4
- createMockedHeapJsSdk,
5
- HEAP_TEST_ENV_ID,
6
- mockHeapJsHttpRequest,
7
- trackEventSubscription
8
- } from '../../test-utilities'
3
+ import { createMockedHeapJsSdk, HEAP_TEST_ENV_ID, trackEventSubscription } from '../../test-utilities'
9
4
  import { HEAP_SEGMENT_BROWSER_LIBRARY_NAME } from '../../constants'
10
5
 
11
6
  describe('#trackEvent', () => {
@@ -16,7 +11,6 @@ describe('#trackEvent', () => {
16
11
  let identifySpy: jest.SpyInstance
17
12
 
18
13
  beforeAll(async () => {
19
- mockHeapJsHttpRequest()
20
14
  window.heap = createMockedHeapJsSdk()
21
15
 
22
16
  eventWithUnrolling = (
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export type UserConfig = {
2
2
  trackingServer?: string
3
+ ingestServer?: string
3
4
  disableTextCapture: boolean
4
5
  secureCookie: boolean
5
6
  }
@@ -12,11 +13,40 @@ type EventProperties = {
12
13
  [key: string]: unknown
13
14
  }
14
15
 
15
- export type HeapApi = {
16
+ export type HeapApi = Record<HeapMethods, (...args: any[]) => void> & {
16
17
  appid: string
18
+ envId: string
17
19
  track: (eventName: string, eventProperties: EventProperties, library?: string) => void
18
- load: () => void
20
+ load: (envId: string, clientConfig?: UserConfig) => void
21
+ loaded?: boolean
19
22
  config: UserConfig
23
+ clientConfig?: Partial<UserConfig> & { shouldFetchServerConfig?: boolean }
20
24
  identify: (identity: string) => void
21
25
  addUserProperties: (properties: UserProperties) => void
22
26
  }
27
+
28
+ // Define types for Heap methods
29
+ export type HeapMethods =
30
+ | 'init'
31
+ | 'startTracking'
32
+ | 'stopTracking'
33
+ | 'track'
34
+ | 'resetIdentity'
35
+ | 'identify'
36
+ | 'identifyHashed'
37
+ | 'getSessionId'
38
+ | 'getUserId'
39
+ | 'getIdentity'
40
+ | 'addUserProperties'
41
+ | 'addEventProperties'
42
+ | 'removeEventProperty'
43
+ | 'clearEventProperties'
44
+ | 'addAccountProperties'
45
+ | 'addAdapter'
46
+ | 'addTransformer'
47
+ | 'addTransformerFn'
48
+ | 'onReady'
49
+ | 'addPageviewProperties'
50
+ | 'removePageviewProperty'
51
+ | 'clearPageviewProperties'
52
+ | 'trackPageview'