@segment/analytics-browser-actions-playerzero 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 +18 -0
- package/src/generated-types.ts +8 -0
- package/src/identifyUser/__tests__/index.test.ts +78 -0
- package/src/identifyUser/generated-types.ts +26 -0
- package/src/identifyUser/index.ts +96 -0
- package/src/index.ts +62 -0
- package/src/test-utils.ts +43 -0
- package/src/trackEvent/__tests__/index.test.ts +33 -0
- package/src/trackEvent/generated-types.ts +14 -0
- package/src/trackEvent/index.ts +36 -0
- package/src/types.ts +5 -0
- package/tsconfig.json +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@segment/analytics-browser-actions-playerzero",
|
|
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,18 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import playerzero, { destination } from '../index'
|
|
3
|
+
import { subscriptions, TEST_PROJECT_ID } from '../test-utils'
|
|
4
|
+
|
|
5
|
+
test.skip('load PlayerZero', async () => {
|
|
6
|
+
const [event] = await playerzero({
|
|
7
|
+
projectId: TEST_PROJECT_ID,
|
|
8
|
+
subscriptions
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
jest.spyOn(destination, 'initialize')
|
|
12
|
+
|
|
13
|
+
await event.load(Context.system(), {} as Analytics)
|
|
14
|
+
expect(destination.initialize).toHaveBeenCalled()
|
|
15
|
+
expect(window.playerzero).toHaveProperty('track')
|
|
16
|
+
expect(window.playerzero).toHaveProperty('identify')
|
|
17
|
+
expect(window.playerzero).toHaveProperty('setUserVars')
|
|
18
|
+
})
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import playerzero from '../../index'
|
|
3
|
+
import { subscriptions, TEST_PROJECT_ID } from '../../test-utils'
|
|
4
|
+
|
|
5
|
+
describe.skip('PlayerzeroWeb.identifyUser', () => {
|
|
6
|
+
it('should keep anonymous users', async () => {
|
|
7
|
+
const [_, identifyUser] = await playerzero({
|
|
8
|
+
projectId: TEST_PROJECT_ID,
|
|
9
|
+
subscriptions
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
await identifyUser.load(Context.system(), {} as Analytics)
|
|
13
|
+
const pzUserVars = jest.spyOn(window.playerzero, 'setUserVars')
|
|
14
|
+
const pzIdentify = jest.spyOn(window.playerzero, 'identify')
|
|
15
|
+
|
|
16
|
+
await identifyUser.identify?.(
|
|
17
|
+
new Context({
|
|
18
|
+
type: 'identify',
|
|
19
|
+
anonymousId: 'ghost',
|
|
20
|
+
traits: {
|
|
21
|
+
hello: 'world'
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
expect(pzUserVars).toHaveBeenCalled()
|
|
27
|
+
expect(pzIdentify).not.toHaveBeenCalled()
|
|
28
|
+
expect(pzUserVars).toHaveBeenCalledWith({
|
|
29
|
+
segmentAnonymousId: 'ghost',
|
|
30
|
+
hello: 'world'
|
|
31
|
+
})
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('should identify a user with id', async () => {
|
|
35
|
+
const [_, identifyUser] = await playerzero({
|
|
36
|
+
projectId: TEST_PROJECT_ID,
|
|
37
|
+
subscriptions
|
|
38
|
+
})
|
|
39
|
+
await identifyUser.load(Context.system(), {} as Analytics)
|
|
40
|
+
const pzIdentify = jest.spyOn(window.playerzero, 'identify')
|
|
41
|
+
|
|
42
|
+
await identifyUser.identify?.(
|
|
43
|
+
new Context({
|
|
44
|
+
type: 'identify',
|
|
45
|
+
userId: 'id'
|
|
46
|
+
})
|
|
47
|
+
)
|
|
48
|
+
expect(pzIdentify).toHaveBeenCalledWith('id', {})
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
it.skip('sets identity and traits', async () => {
|
|
52
|
+
const [_, identifyUser] = await playerzero({
|
|
53
|
+
projectId: TEST_PROJECT_ID,
|
|
54
|
+
subscriptions
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
await identifyUser.load(Context.system(), {} as Analytics)
|
|
58
|
+
const pzIdentify = jest.spyOn(window.playerzero, 'identify')
|
|
59
|
+
|
|
60
|
+
await identifyUser.identify?.(
|
|
61
|
+
new Context({
|
|
62
|
+
type: 'identify',
|
|
63
|
+
userId: 'id',
|
|
64
|
+
anonymousId: 'ghost',
|
|
65
|
+
traits: {
|
|
66
|
+
name: 'Joe',
|
|
67
|
+
email: 'billy@bob.com'
|
|
68
|
+
}
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
expect(pzIdentify).toHaveBeenCalledWith('id', {
|
|
73
|
+
name: 'Joe',
|
|
74
|
+
email: 'billy@bob.com',
|
|
75
|
+
segmentAnonymousId: 'ghost'
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
})
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
// Generated file. DO NOT MODIFY IT BY HAND.
|
|
2
|
+
|
|
3
|
+
export interface Payload {
|
|
4
|
+
/**
|
|
5
|
+
* The user's id
|
|
6
|
+
*/
|
|
7
|
+
userId?: string
|
|
8
|
+
/**
|
|
9
|
+
* The user's anonymous id
|
|
10
|
+
*/
|
|
11
|
+
anonymousId?: string
|
|
12
|
+
/**
|
|
13
|
+
* The user's name
|
|
14
|
+
*/
|
|
15
|
+
name?: string
|
|
16
|
+
/**
|
|
17
|
+
* The user's email
|
|
18
|
+
*/
|
|
19
|
+
email?: string
|
|
20
|
+
/**
|
|
21
|
+
* The Segment traits to be included as metadata in PlayerZero
|
|
22
|
+
*/
|
|
23
|
+
traits?: {
|
|
24
|
+
[k: string]: unknown
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import { PlayerZero } from '../types'
|
|
4
|
+
import type { Payload } from './generated-types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, PlayerZero, Payload> = {
|
|
7
|
+
title: 'Identify User',
|
|
8
|
+
description: 'Sets the user identity',
|
|
9
|
+
platform: 'web',
|
|
10
|
+
defaultSubscription: 'type = "identify"',
|
|
11
|
+
fields: {
|
|
12
|
+
userId: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: false,
|
|
15
|
+
description: "The user's id",
|
|
16
|
+
label: 'User ID',
|
|
17
|
+
default: {
|
|
18
|
+
'@path': '$.userId'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
anonymousId: {
|
|
22
|
+
type: 'string',
|
|
23
|
+
required: false,
|
|
24
|
+
description: "The user's anonymous id",
|
|
25
|
+
label: 'Anonymous ID',
|
|
26
|
+
default: {
|
|
27
|
+
'@path': '$.anonymousId'
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
name: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
required: false,
|
|
33
|
+
description: "The user's name",
|
|
34
|
+
label: 'Display Name',
|
|
35
|
+
default: {
|
|
36
|
+
'@path': '$.traits.name'
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
email: {
|
|
40
|
+
type: 'string',
|
|
41
|
+
required: false,
|
|
42
|
+
description: "The user's email",
|
|
43
|
+
label: 'Email',
|
|
44
|
+
default: {
|
|
45
|
+
'@path': '$.traits.email'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
traits: {
|
|
49
|
+
type: 'object',
|
|
50
|
+
required: false,
|
|
51
|
+
description: 'The Segment traits to be included as metadata in PlayerZero',
|
|
52
|
+
label: 'Traits',
|
|
53
|
+
default: {
|
|
54
|
+
'@path': '$.traits'
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
perform: (playerzero, event) => {
|
|
59
|
+
let newTraits: Record<string, unknown> = {}
|
|
60
|
+
|
|
61
|
+
if (event.payload.traits) {
|
|
62
|
+
newTraits = Object.entries(event.payload.traits).reduce(
|
|
63
|
+
(acc, [key, value]) => ({
|
|
64
|
+
...acc,
|
|
65
|
+
[cleanKey(key)]: value
|
|
66
|
+
}),
|
|
67
|
+
{}
|
|
68
|
+
)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (event.payload.anonymousId) {
|
|
72
|
+
newTraits.segmentAnonymousId = event.payload.anonymousId
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
if (event.payload.userId) {
|
|
76
|
+
playerzero.identify(event.payload.userId, newTraits)
|
|
77
|
+
} else {
|
|
78
|
+
playerzero.setUserVars({
|
|
79
|
+
...newTraits,
|
|
80
|
+
...(event.payload.email !== undefined && { email: event.payload.email }),
|
|
81
|
+
...(event.payload.name !== undefined && { name: event.payload.name })
|
|
82
|
+
})
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Clean up variable name to be compatible with
|
|
89
|
+
*
|
|
90
|
+
* @param {string} key
|
|
91
|
+
*/
|
|
92
|
+
function cleanKey(key: string) {
|
|
93
|
+
return key.trim().toLowerCase().replace(' ', '_')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export default action
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { defaultValues } from '@segment/actions-core'
|
|
2
|
+
import type { Settings } from './generated-types'
|
|
3
|
+
import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
|
|
4
|
+
import { browserDestination } from '@segment/browser-destination-runtime/shim'
|
|
5
|
+
import { PlayerZero } from './types'
|
|
6
|
+
|
|
7
|
+
import identifyUser from './identifyUser'
|
|
8
|
+
|
|
9
|
+
import trackEvent from './trackEvent'
|
|
10
|
+
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
playerzero: PlayerZero
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Switch from unknown to the partner SDK client types
|
|
18
|
+
export const destination: BrowserDestinationDefinition<Settings, PlayerZero> = {
|
|
19
|
+
name: 'PlayerZero Web',
|
|
20
|
+
slug: 'actions-playerzero-web',
|
|
21
|
+
mode: 'device',
|
|
22
|
+
|
|
23
|
+
settings: {
|
|
24
|
+
// Add any Segment destination settings required here
|
|
25
|
+
projectId: {
|
|
26
|
+
label: 'PlayerZero Project ID',
|
|
27
|
+
description:
|
|
28
|
+
'The Project ID where you want to send data. You can find this ID on the [Project Data Collection](https://go.playerzero.app/setting/data) page.',
|
|
29
|
+
type: 'string',
|
|
30
|
+
required: true
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
|
|
34
|
+
presets: [
|
|
35
|
+
{
|
|
36
|
+
name: 'Track Event',
|
|
37
|
+
subscribe: 'type = "track"',
|
|
38
|
+
partnerAction: 'trackEvent',
|
|
39
|
+
mapping: defaultValues(trackEvent.fields)
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
name: 'Identify User',
|
|
43
|
+
subscribe: 'type = "identify"',
|
|
44
|
+
partnerAction: 'identifyUser',
|
|
45
|
+
mapping: defaultValues(identifyUser.fields)
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
|
|
49
|
+
initialize: async ({ settings }, deps) => {
|
|
50
|
+
await deps.loadScript(`https://go.playerzero.app/record/${settings.projectId}`)
|
|
51
|
+
// initialize client code here
|
|
52
|
+
await deps.resolveWhen(() => Object.prototype.hasOwnProperty.call(window, 'playerzero'), 250)
|
|
53
|
+
return window.playerzero
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
actions: {
|
|
57
|
+
trackEvent,
|
|
58
|
+
identifyUser
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export default browserDestination(destination)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Subscription } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
|
|
3
|
+
export const TEST_PROJECT_ID = '634947ab6e8b1d18374ed00c'
|
|
4
|
+
|
|
5
|
+
export const subscriptions: Subscription[] = [
|
|
6
|
+
{
|
|
7
|
+
partnerAction: 'trackEvent',
|
|
8
|
+
name: 'Track Event',
|
|
9
|
+
enabled: true,
|
|
10
|
+
subscribe: 'type = "track"',
|
|
11
|
+
mapping: {
|
|
12
|
+
name: {
|
|
13
|
+
'@path': '$.name'
|
|
14
|
+
},
|
|
15
|
+
properties: {
|
|
16
|
+
'@path': '$.properties'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
partnerAction: 'identifyUser',
|
|
22
|
+
name: 'Identify User',
|
|
23
|
+
enabled: true,
|
|
24
|
+
subscribe: 'type = "identify"',
|
|
25
|
+
mapping: {
|
|
26
|
+
anonymousId: {
|
|
27
|
+
'@path': '$.anonymousId'
|
|
28
|
+
},
|
|
29
|
+
userId: {
|
|
30
|
+
'@path': '$.userId'
|
|
31
|
+
},
|
|
32
|
+
name: {
|
|
33
|
+
'@path': '$.traits.name'
|
|
34
|
+
},
|
|
35
|
+
email: {
|
|
36
|
+
'@path': '$.traits.email'
|
|
37
|
+
},
|
|
38
|
+
traits: {
|
|
39
|
+
'@path': '$.traits'
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
]
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import playerzero, { destination } from '../../index'
|
|
3
|
+
import { subscriptions, TEST_PROJECT_ID } from '../../test-utils'
|
|
4
|
+
|
|
5
|
+
describe('PlayerzeroWeb.trackEvent', () => {
|
|
6
|
+
it.skip('emits a PlayerZero track event', async () => {
|
|
7
|
+
const [event] = await playerzero({
|
|
8
|
+
projectId: TEST_PROJECT_ID,
|
|
9
|
+
subscriptions
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
await event.load(Context.system(), {} as Analytics)
|
|
13
|
+
jest.spyOn(destination.actions.trackEvent, 'perform')
|
|
14
|
+
const pz = jest.spyOn(window.playerzero, 'track')
|
|
15
|
+
|
|
16
|
+
const ctx = await event.track?.(
|
|
17
|
+
new Context({
|
|
18
|
+
type: 'track',
|
|
19
|
+
name: 'test event',
|
|
20
|
+
properties: {
|
|
21
|
+
hello: 'world'
|
|
22
|
+
}
|
|
23
|
+
})
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
expect(ctx).not.toBeUndefined()
|
|
27
|
+
expect(pz).toHaveBeenCalledWith('test event', {
|
|
28
|
+
hello: 'world'
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
expect(destination.actions.trackEvent.perform).toHaveBeenCalled()
|
|
32
|
+
})
|
|
33
|
+
})
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Generated file. DO NOT MODIFY IT BY HAND.
|
|
2
|
+
|
|
3
|
+
export interface Payload {
|
|
4
|
+
/**
|
|
5
|
+
* The name of the event.
|
|
6
|
+
*/
|
|
7
|
+
name: string
|
|
8
|
+
/**
|
|
9
|
+
* A JSON object containing more information about the event.
|
|
10
|
+
*/
|
|
11
|
+
properties?: {
|
|
12
|
+
[k: string]: unknown
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import type { Settings } from '../generated-types'
|
|
3
|
+
import { PlayerZero } from '../types'
|
|
4
|
+
import type { Payload } from './generated-types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, PlayerZero, Payload> = {
|
|
7
|
+
title: 'Track Event',
|
|
8
|
+
description: 'Track events',
|
|
9
|
+
platform: 'web',
|
|
10
|
+
defaultSubscription: 'type = "track"',
|
|
11
|
+
fields: {
|
|
12
|
+
name: {
|
|
13
|
+
description: 'The name of the event.',
|
|
14
|
+
label: 'Event name',
|
|
15
|
+
required: true,
|
|
16
|
+
type: 'string',
|
|
17
|
+
default: {
|
|
18
|
+
'@path': '$.event'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
properties: {
|
|
22
|
+
description: 'A JSON object containing more information about the event.',
|
|
23
|
+
label: 'Properties',
|
|
24
|
+
required: false,
|
|
25
|
+
type: 'object',
|
|
26
|
+
default: {
|
|
27
|
+
'@path': '$.properties'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
perform: (playerzero, event) => {
|
|
32
|
+
playerzero.track(event.payload.name, event.payload.properties)
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export default action
|
package/src/types.ts
ADDED