@segment/analytics-browser-actions-userpilot 1.0.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.
- package/package.json +20 -0
- package/src/__tests__/index.test.ts +132 -0
- package/src/generated-types.ts +16 -0
- package/src/identifyCompany/generated-types.ts +14 -0
- package/src/identifyCompany/index.ts +36 -0
- package/src/identifyUser/generated-types.ts +18 -0
- package/src/identifyUser/index.ts +54 -0
- package/src/index.ts +96 -0
- package/src/pageView/generated-types.ts +14 -0
- package/src/pageView/index.ts +38 -0
- package/src/trackEvent/generated-types.ts +14 -0
- package/src/trackEvent/index.ts +37 -0
- package/src/types.ts +6 -0
- package/tsconfig.json +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@segment/analytics-browser-actions-userpilot",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"main": "./dist/cjs",
|
|
6
|
+
"module": "./dist/esm",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "yarn build:esm && yarn build:cjs",
|
|
9
|
+
"build:cjs": "tsc --module commonjs --outDir ./dist/cjs",
|
|
10
|
+
"build:esm": "tsc --outDir ./dist/esm"
|
|
11
|
+
},
|
|
12
|
+
"typings": "./dist/esm",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@segment/actions-core": "^3.71.0",
|
|
15
|
+
"@segment/browser-destination-runtime": "^1.0.0"
|
|
16
|
+
},
|
|
17
|
+
"peerDependencies": {
|
|
18
|
+
"@segment/analytics-next": "*"
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import { Subscription } from '@segment/browser-destination-runtime/types'
|
|
3
|
+
import userpilot, { destination } from '../index'
|
|
4
|
+
|
|
5
|
+
const example: Subscription[] = [
|
|
6
|
+
{
|
|
7
|
+
partnerAction: 'identifyUser',
|
|
8
|
+
name: 'Identify User',
|
|
9
|
+
enabled: true,
|
|
10
|
+
subscribe: 'type = "identify"',
|
|
11
|
+
mapping: {
|
|
12
|
+
userId: {
|
|
13
|
+
'@path': '$.userId'
|
|
14
|
+
},
|
|
15
|
+
anonymousId: {
|
|
16
|
+
'@path': '$.anonymousId'
|
|
17
|
+
},
|
|
18
|
+
traits: {
|
|
19
|
+
'@path': '$.traits'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
partnerAction: 'trackEvent',
|
|
25
|
+
name: 'Track Event',
|
|
26
|
+
enabled: true,
|
|
27
|
+
subscribe: 'type = "track"',
|
|
28
|
+
mapping: {
|
|
29
|
+
name: {
|
|
30
|
+
'@path': '$.name'
|
|
31
|
+
},
|
|
32
|
+
properties: {
|
|
33
|
+
'@path': '$.properties'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
partnerAction: 'pageView',
|
|
39
|
+
name: 'Page View',
|
|
40
|
+
enabled: true,
|
|
41
|
+
subscribe: 'type = "page"',
|
|
42
|
+
mapping: {
|
|
43
|
+
name: {
|
|
44
|
+
'@path': '$.name'
|
|
45
|
+
},
|
|
46
|
+
properties: {
|
|
47
|
+
'@path': '$.properties'
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
describe('Userpilot', () => {
|
|
54
|
+
it('should load the Userpilot script', async () => {
|
|
55
|
+
const [event] = await userpilot({
|
|
56
|
+
token: 'NX-917089a3',
|
|
57
|
+
subscriptions: example
|
|
58
|
+
})
|
|
59
|
+
jest.spyOn(destination, 'initialize')
|
|
60
|
+
|
|
61
|
+
await event.load(Context.system(), {} as Analytics)
|
|
62
|
+
expect(window.userpilot).toBeDefined()
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
describe('IdentifyUser', () => {
|
|
67
|
+
it('should call identify if user id is provided', async () => {
|
|
68
|
+
const [identifyUser] = await userpilot({
|
|
69
|
+
token: 'NX-917089a3',
|
|
70
|
+
subscriptions: example
|
|
71
|
+
})
|
|
72
|
+
await identifyUser.load(Context.system(), {} as Analytics)
|
|
73
|
+
const up = jest.spyOn(window.userpilot, 'identify')
|
|
74
|
+
|
|
75
|
+
await identifyUser.identify?.(
|
|
76
|
+
new Context({
|
|
77
|
+
type: 'identify',
|
|
78
|
+
userId: 'test',
|
|
79
|
+
traits: {
|
|
80
|
+
example: 'test prop'
|
|
81
|
+
}
|
|
82
|
+
})
|
|
83
|
+
)
|
|
84
|
+
expect(up).toHaveBeenCalledWith('test', { example: 'test prop' })
|
|
85
|
+
})
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
describe('TrackEvent', () => {
|
|
89
|
+
it('should call track if event name is provided', async () => {
|
|
90
|
+
const [_identifyUser, trackEvent] = await userpilot({
|
|
91
|
+
token: 'NX-917089a3',
|
|
92
|
+
subscriptions: example
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
await trackEvent.load(Context.system(), {} as Analytics)
|
|
96
|
+
const up = jest.spyOn(window.userpilot, 'track')
|
|
97
|
+
|
|
98
|
+
await trackEvent.track?.(
|
|
99
|
+
new Context({
|
|
100
|
+
type: 'track',
|
|
101
|
+
name: 'test',
|
|
102
|
+
properties: {
|
|
103
|
+
example: 'test prop'
|
|
104
|
+
}
|
|
105
|
+
})
|
|
106
|
+
)
|
|
107
|
+
expect(up).toHaveBeenCalledWith('test', { example: 'test prop' })
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
describe('PageView', () => {
|
|
112
|
+
it('should call Userpilot reload', async () => {
|
|
113
|
+
const [_identifyUser, _trackEvent, pageView] = await userpilot({
|
|
114
|
+
token: 'NX-917089a3',
|
|
115
|
+
subscriptions: example
|
|
116
|
+
})
|
|
117
|
+
await pageView.load(Context.system(), {} as Analytics)
|
|
118
|
+
|
|
119
|
+
const up = jest.spyOn(window.userpilot, 'reload')
|
|
120
|
+
|
|
121
|
+
await pageView.page?.(
|
|
122
|
+
new Context({
|
|
123
|
+
type: 'page',
|
|
124
|
+
name: 'test',
|
|
125
|
+
properties: {
|
|
126
|
+
example: 'test prop'
|
|
127
|
+
}
|
|
128
|
+
})
|
|
129
|
+
)
|
|
130
|
+
expect(up).toHaveBeenCalledWith('test', { example: 'test prop' })
|
|
131
|
+
})
|
|
132
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Generated file. DO NOT MODIFY IT BY HAND.
|
|
2
|
+
|
|
3
|
+
export interface Settings {
|
|
4
|
+
/**
|
|
5
|
+
* Your Userpilot app token, you can find it in the [Userpilot installation](https://run.userpilot.io/installation) dashboard.
|
|
6
|
+
*/
|
|
7
|
+
token: string
|
|
8
|
+
/**
|
|
9
|
+
* By default, Userpilot would use a service discovery mechanism to determine the API endpoint to connect to. If you are using a proxy or a firewall, you can specify the API endpoint here.
|
|
10
|
+
*/
|
|
11
|
+
endpoint?: string
|
|
12
|
+
/**
|
|
13
|
+
* By default, Segment will load the Userpilot JS snippet onto the page. If you are already loading the Userpilot JS onto the page then disable this setting and Segment will detect the Userpilot JS on the page
|
|
14
|
+
*/
|
|
15
|
+
shouldSegmentLoadSDK: boolean
|
|
16
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import type { Payload } from './generated-types'
|
|
4
|
+
import type { Userpilot } from '../types'
|
|
5
|
+
// Change from unknown to the partner SDK types
|
|
6
|
+
const action: BrowserActionDefinition<Settings, Userpilot, Payload> = {
|
|
7
|
+
title: 'Identify Company',
|
|
8
|
+
description: 'Create or update a company entity in Userpilot',
|
|
9
|
+
platform: 'web',
|
|
10
|
+
defaultSubscription: 'type = "group"',
|
|
11
|
+
fields: {
|
|
12
|
+
groupId: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: true,
|
|
15
|
+
description: 'The ID of the company.',
|
|
16
|
+
label: 'Company ID',
|
|
17
|
+
default: {
|
|
18
|
+
'@path': '$.groupId'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
traits: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
required: false,
|
|
24
|
+
description: 'Company traits',
|
|
25
|
+
label: 'Traits',
|
|
26
|
+
default: {
|
|
27
|
+
'@path': '$.traits'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
perform: (_, events) => {
|
|
32
|
+
window.userpilot.group(events.payload.groupId ?? '', events.payload.traits ?? {})
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default action
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Generated file. DO NOT MODIFY IT BY HAND.
|
|
2
|
+
|
|
3
|
+
export interface Payload {
|
|
4
|
+
/**
|
|
5
|
+
* The ID of the logged-in user.
|
|
6
|
+
*/
|
|
7
|
+
userId: string
|
|
8
|
+
/**
|
|
9
|
+
* The date the user profile was created at
|
|
10
|
+
*/
|
|
11
|
+
createdAt?: string | number
|
|
12
|
+
/**
|
|
13
|
+
* User traits.
|
|
14
|
+
*/
|
|
15
|
+
traits?: {
|
|
16
|
+
[k: string]: unknown
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import type { Payload } from './generated-types'
|
|
4
|
+
import type { Userpilot } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, Userpilot, Payload> = {
|
|
7
|
+
title: 'Identify User',
|
|
8
|
+
description:
|
|
9
|
+
"Create or update a user entity in Userpilot. It's mandatory to identify a user by calling identify() prior to invoking other methods such as track(), page(), or group(). You can learn more by visiting the [Userpilot documentation](https://docs.userpilot.com/article/23-identify-users-track-custom-events).",
|
|
10
|
+
platform: 'web',
|
|
11
|
+
defaultSubscription: 'type = "identify"',
|
|
12
|
+
fields: {
|
|
13
|
+
userId: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
required: true,
|
|
16
|
+
description: 'The ID of the logged-in user.',
|
|
17
|
+
label: 'User ID',
|
|
18
|
+
default: {
|
|
19
|
+
'@if': {
|
|
20
|
+
exists: { '@path': '$.userId' },
|
|
21
|
+
then: { '@path': '$.userId' },
|
|
22
|
+
else: { '@path': '$.anonymousId' }
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
createdAt: {
|
|
27
|
+
type: 'datetime',
|
|
28
|
+
required: false,
|
|
29
|
+
description: 'The date the user profile was created at',
|
|
30
|
+
label: 'User Created At Date',
|
|
31
|
+
default: {
|
|
32
|
+
'@path': '$.traits.createdAt'
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
traits: {
|
|
36
|
+
type: 'object',
|
|
37
|
+
required: false,
|
|
38
|
+
description: 'User traits.',
|
|
39
|
+
label: 'Traits',
|
|
40
|
+
default: {
|
|
41
|
+
'@path': '$.traits'
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
perform: (_, event) => {
|
|
46
|
+
const { userId, traits } = event.payload
|
|
47
|
+
|
|
48
|
+
traits?.createdAt && delete traits.createdAt
|
|
49
|
+
|
|
50
|
+
window.userpilot.identify(userId, { ...traits, created_at: event.payload.createdAt || traits?.created_at })
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default action
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Settings } from './generated-types'
|
|
2
|
+
import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
|
|
3
|
+
import type { Userpilot } from './types'
|
|
4
|
+
|
|
5
|
+
import { browserDestination } from '@segment/browser-destination-runtime/shim'
|
|
6
|
+
import { defaultValues } from '@segment/actions-core'
|
|
7
|
+
|
|
8
|
+
import identifyUser from './identifyUser'
|
|
9
|
+
import trackEvent from './trackEvent'
|
|
10
|
+
import pageView from './pageView'
|
|
11
|
+
|
|
12
|
+
import identifyCompany from './identifyCompany'
|
|
13
|
+
|
|
14
|
+
declare global {
|
|
15
|
+
interface Window {
|
|
16
|
+
userpilot: Userpilot
|
|
17
|
+
userpilotSettings: Settings
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Switch from unknown to the partner SDK client types
|
|
22
|
+
export const destination: BrowserDestinationDefinition<Settings, Userpilot> = {
|
|
23
|
+
name: 'Userpilot Web (Actions)',
|
|
24
|
+
slug: 'actions-userpilot-web',
|
|
25
|
+
mode: 'device',
|
|
26
|
+
presets: [
|
|
27
|
+
{
|
|
28
|
+
name: 'Identify User',
|
|
29
|
+
subscribe: 'type = "identify"',
|
|
30
|
+
partnerAction: 'identifyUser',
|
|
31
|
+
mapping: defaultValues(identifyUser.fields)
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: 'Track Event',
|
|
35
|
+
subscribe: 'type = "track"',
|
|
36
|
+
partnerAction: 'trackEvent',
|
|
37
|
+
mapping: defaultValues(trackEvent.fields)
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Page View',
|
|
41
|
+
subscribe: 'type = "page"',
|
|
42
|
+
partnerAction: 'pageView',
|
|
43
|
+
mapping: defaultValues(pageView.fields)
|
|
44
|
+
}
|
|
45
|
+
],
|
|
46
|
+
settings: {
|
|
47
|
+
token: {
|
|
48
|
+
label: 'App Token',
|
|
49
|
+
description:
|
|
50
|
+
'Your Userpilot app token, you can find it in the [Userpilot installation](https://run.userpilot.io/installation) dashboard.',
|
|
51
|
+
required: true,
|
|
52
|
+
type: 'string'
|
|
53
|
+
},
|
|
54
|
+
endpoint: {
|
|
55
|
+
label: 'The API endpoint the SDK would connect to',
|
|
56
|
+
description:
|
|
57
|
+
'By default, Userpilot would use a service discovery mechanism to determine the API endpoint to connect to. If you are using a proxy or a firewall, you can specify the API endpoint here.',
|
|
58
|
+
required: false,
|
|
59
|
+
type: 'string'
|
|
60
|
+
},
|
|
61
|
+
shouldSegmentLoadSDK: {
|
|
62
|
+
label: 'Segment Loads Userpilot JS',
|
|
63
|
+
description:
|
|
64
|
+
'By default, Segment will load the Userpilot JS snippet onto the page. If you are already loading the Userpilot JS onto the page then disable this setting and Segment will detect the Userpilot JS on the page',
|
|
65
|
+
required: true,
|
|
66
|
+
type: 'boolean',
|
|
67
|
+
default: true
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
initialize: async ({ settings }, deps) => {
|
|
71
|
+
const shouldLoadSDK = settings.shouldSegmentLoadSDK ?? true
|
|
72
|
+
|
|
73
|
+
if (shouldLoadSDK) {
|
|
74
|
+
window.userpilotSettings = {
|
|
75
|
+
token: settings.token,
|
|
76
|
+
endpoint: settings.endpoint,
|
|
77
|
+
shouldSegmentLoadSDK: shouldLoadSDK
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
await deps.loadScript('//js.userpilot.io/sdk/latest.js')
|
|
81
|
+
await deps.resolveWhen(() => Object.prototype.hasOwnProperty.call(window, 'userpilot'), 100)
|
|
82
|
+
} else {
|
|
83
|
+
await deps.resolveWhen(() => window.userpilot !== undefined, 100)
|
|
84
|
+
}
|
|
85
|
+
return window.userpilot
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
actions: {
|
|
89
|
+
identifyUser,
|
|
90
|
+
trackEvent,
|
|
91
|
+
pageView,
|
|
92
|
+
identifyCompany
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default browserDestination(destination)
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Generated file. DO NOT MODIFY IT BY HAND.
|
|
2
|
+
|
|
3
|
+
export interface Payload {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the page that was viewed.
|
|
6
|
+
*/
|
|
7
|
+
name?: string
|
|
8
|
+
/**
|
|
9
|
+
* The properties of the page that was viewed.
|
|
10
|
+
*/
|
|
11
|
+
properties?: {
|
|
12
|
+
[k: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import type { Payload } from './generated-types'
|
|
4
|
+
import type { Userpilot } from '../types'
|
|
5
|
+
|
|
6
|
+
// Change from unknown to the partner SDK types
|
|
7
|
+
const action: BrowserActionDefinition<Settings, Userpilot, Payload> = {
|
|
8
|
+
title: 'Page View',
|
|
9
|
+
description:
|
|
10
|
+
"Update the content queue designed to trigger on a specific page. It's mandatory to identify a user by calling identify() prior to invoking other methods such as page()",
|
|
11
|
+
platform: 'web',
|
|
12
|
+
defaultSubscription: 'type = "page"',
|
|
13
|
+
fields: {
|
|
14
|
+
name: {
|
|
15
|
+
type: 'string',
|
|
16
|
+
required: false,
|
|
17
|
+
description: 'The name of the page that was viewed.',
|
|
18
|
+
label: 'Page Name',
|
|
19
|
+
default: {
|
|
20
|
+
'@path': '$.name'
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
properties: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
required: false,
|
|
26
|
+
description: 'The properties of the page that was viewed.',
|
|
27
|
+
label: 'Properties',
|
|
28
|
+
default: {
|
|
29
|
+
'@path': '$.properties'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
perform: (_, event) => {
|
|
34
|
+
window.userpilot.reload(event.payload.name ?? '', event.payload.properties ?? {})
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default action
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import type { Payload } from './generated-types'
|
|
4
|
+
import type { Userpilot } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, Userpilot, Payload> = {
|
|
7
|
+
title: 'Track Event',
|
|
8
|
+
description:
|
|
9
|
+
"Send an event to Userpilot. It's mandatory to identify a user by calling identify() prior to invoking other methods such as track(). You can learn more by visiting the [Userpilot documentation](https://docs.userpilot.com/article/23-identify-users-track-custom-events).",
|
|
10
|
+
platform: 'web',
|
|
11
|
+
defaultSubscription: 'type = "track"',
|
|
12
|
+
fields: {
|
|
13
|
+
name: {
|
|
14
|
+
type: 'string',
|
|
15
|
+
required: true,
|
|
16
|
+
description: 'Event name',
|
|
17
|
+
label: 'Name',
|
|
18
|
+
default: {
|
|
19
|
+
'@path': '$.event'
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
properties: {
|
|
23
|
+
type: 'object',
|
|
24
|
+
required: false,
|
|
25
|
+
description: 'Event properties',
|
|
26
|
+
label: 'Properties',
|
|
27
|
+
default: {
|
|
28
|
+
'@path': '$.properties'
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
perform: (_, event) => {
|
|
33
|
+
window.userpilot.track(event.payload.name, event.payload.properties ?? {})
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default action
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export type Userpilot = {
|
|
2
|
+
identify: (user_id: String, traits: { [key: string]: unknown }) => void
|
|
3
|
+
track: (eventName: String, eventProperties: { [key: string]: unknown }) => void
|
|
4
|
+
reload: (pageName: String, pageProperties: Object) => void
|
|
5
|
+
group: (groupId: String, groupTraits: Object) => void
|
|
6
|
+
}
|