@segment/analytics-browser-actions-koala 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/generated-types.ts +8 -0
- package/src/identifyVisitor/__tests__/index.test.ts +70 -0
- package/src/identifyVisitor/generated-types.ts +10 -0
- package/src/identifyVisitor/index.ts +28 -0
- package/src/index.ts +66 -0
- package/src/init-script.ts +17 -0
- package/src/trackEvent/__tests__/index.test.ts +76 -0
- package/src/trackEvent/generated-types.ts +14 -0
- package/src/trackEvent/index.ts +35 -0
- package/src/types.ts +9 -0
- package/tsconfig.json +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@segment/analytics-browser-actions-koala",
|
|
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,70 @@
|
|
|
1
|
+
import type { Subscription } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
3
|
+
import KoalaDestination, { destination } from '../../index'
|
|
4
|
+
|
|
5
|
+
import { loadScript } from '@segment/browser-destination-runtime/load-script'
|
|
6
|
+
jest.mock('@segment/browser-destination-runtime/load-script')
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
;(loadScript as jest.Mock).mockResolvedValue(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const subscriptions: Subscription[] = [
|
|
12
|
+
{
|
|
13
|
+
partnerAction: 'identifyVisitor',
|
|
14
|
+
name: 'Identify Visitor',
|
|
15
|
+
enabled: true,
|
|
16
|
+
subscribe: 'type = "identify"',
|
|
17
|
+
mapping: {
|
|
18
|
+
traits: {
|
|
19
|
+
'@path': '$.traits'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
describe('Koala.identifyVisitor', () => {
|
|
26
|
+
test('it maps traits and passes them into ko.identify', async () => {
|
|
27
|
+
window.ko = {
|
|
28
|
+
ready: jest.fn(),
|
|
29
|
+
track: jest.fn().mockResolvedValueOnce(undefined),
|
|
30
|
+
identify: jest.fn().mockResolvedValueOnce(undefined)
|
|
31
|
+
}
|
|
32
|
+
window.KoalaSDK = {
|
|
33
|
+
load: jest.fn().mockResolvedValueOnce(window.ko)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const [event] = await KoalaDestination({
|
|
37
|
+
subscriptions,
|
|
38
|
+
project_slug: 'koala-test'
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
const ajs = new Analytics({ writeKey: 'w_123' })
|
|
42
|
+
await event.load(Context.system(), ajs)
|
|
43
|
+
jest.spyOn(destination.actions.identifyVisitor, 'perform')
|
|
44
|
+
|
|
45
|
+
await event.identify?.(
|
|
46
|
+
new Context({
|
|
47
|
+
type: 'identify',
|
|
48
|
+
traits: {
|
|
49
|
+
name: 'Matt'
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
expect(destination.actions.identifyVisitor.perform).toHaveBeenCalledWith(
|
|
55
|
+
expect.anything(),
|
|
56
|
+
expect.objectContaining({
|
|
57
|
+
payload: {
|
|
58
|
+
traits: {
|
|
59
|
+
name: 'Matt'
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
)
|
|
64
|
+
expect(window.ko.identify).toHaveBeenCalledWith(
|
|
65
|
+
expect.objectContaining({
|
|
66
|
+
name: 'Matt'
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
})
|
|
70
|
+
})
|
|
@@ -0,0 +1,28 @@
|
|
|
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 { Koala } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, Koala, Payload> = {
|
|
7
|
+
title: 'Identify Visitor',
|
|
8
|
+
description: 'Update visitor traits in Koala.',
|
|
9
|
+
defaultSubscription: 'type = "identify"',
|
|
10
|
+
platform: 'web',
|
|
11
|
+
fields: {
|
|
12
|
+
traits: {
|
|
13
|
+
type: 'object',
|
|
14
|
+
label: 'Traits',
|
|
15
|
+
description: 'Traits to associate with the visitor in Koala.',
|
|
16
|
+
required: true,
|
|
17
|
+
default: { '@path': '$.traits' },
|
|
18
|
+
defaultObjectUI: 'object'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
perform: (koala, { payload }) => {
|
|
22
|
+
if (payload?.traits) {
|
|
23
|
+
return koala.identify(payload.traits)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default action
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Settings } from './generated-types'
|
|
2
|
+
import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
|
|
3
|
+
import type { KoalaSDK, Koala } from './types'
|
|
4
|
+
import { defaultValues } from '@segment/actions-core'
|
|
5
|
+
import { browserDestination } from '@segment/browser-destination-runtime/shim'
|
|
6
|
+
import { initScript } from './init-script'
|
|
7
|
+
import trackEvent from './trackEvent'
|
|
8
|
+
import identifyVisitor from './identifyVisitor'
|
|
9
|
+
|
|
10
|
+
declare global {
|
|
11
|
+
interface Window {
|
|
12
|
+
ko: Koala
|
|
13
|
+
KoalaSDK: KoalaSDK
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export const destination: BrowserDestinationDefinition<Settings, Koala> = {
|
|
18
|
+
name: 'Koala',
|
|
19
|
+
slug: 'actions-koala',
|
|
20
|
+
description: 'Connect Koala in Segment to send visitor events or traits to Koala.',
|
|
21
|
+
mode: 'device',
|
|
22
|
+
settings: {
|
|
23
|
+
project_slug: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
label: 'Public API Key',
|
|
26
|
+
description: 'Please enter your Public API Key found in your Koala workspace settings.',
|
|
27
|
+
required: true
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
initialize: async ({ settings, analytics }, deps) => {
|
|
32
|
+
initScript()
|
|
33
|
+
await deps.loadScript(`https://cdn.koala.live/v1/${settings.project_slug}/umd.js`)
|
|
34
|
+
|
|
35
|
+
const ko = await window.KoalaSDK.load({
|
|
36
|
+
project: settings.project_slug,
|
|
37
|
+
hookSegment: false
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
void analytics.ready(() => ko.ready(() => ko.identify(analytics.user().traits() as Record<string, unknown>)))
|
|
41
|
+
|
|
42
|
+
return ko
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
actions: {
|
|
46
|
+
trackEvent,
|
|
47
|
+
identifyVisitor
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
presets: [
|
|
51
|
+
{
|
|
52
|
+
name: 'Track Event',
|
|
53
|
+
subscribe: 'type = "track"',
|
|
54
|
+
partnerAction: 'trackEvent',
|
|
55
|
+
mapping: defaultValues(trackEvent.fields)
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: 'Identify Visitor',
|
|
59
|
+
subscribe: 'type = "identify"',
|
|
60
|
+
partnerAction: 'identifyVisitor',
|
|
61
|
+
mapping: defaultValues(identifyVisitor.fields)
|
|
62
|
+
}
|
|
63
|
+
]
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export default browserDestination(destination)
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
// @ts-nocheck
|
|
3
|
+
export function initScript() {
|
|
4
|
+
if (window.ko) {
|
|
5
|
+
return
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
window.ko = []
|
|
9
|
+
;['identify', 'track', 'removeListeners', 'open', 'on', 'off', 'qualify', 'ready'].forEach(function (method) {
|
|
10
|
+
ko[method] = function () {
|
|
11
|
+
let args = Array.from(arguments)
|
|
12
|
+
args.unshift(method)
|
|
13
|
+
ko.push(args)
|
|
14
|
+
return ko
|
|
15
|
+
}
|
|
16
|
+
})
|
|
17
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { Subscription } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
3
|
+
import KoalaDestination, { destination } from '../../index'
|
|
4
|
+
|
|
5
|
+
import { loadScript } from '@segment/browser-destination-runtime/load-script'
|
|
6
|
+
jest.mock('@segment/browser-destination-runtime/load-script')
|
|
7
|
+
beforeEach(async () => {
|
|
8
|
+
;(loadScript as jest.Mock).mockResolvedValue(true)
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
const subscriptions: Subscription[] = [
|
|
12
|
+
{
|
|
13
|
+
partnerAction: 'trackEvent',
|
|
14
|
+
name: 'Track Event',
|
|
15
|
+
enabled: true,
|
|
16
|
+
subscribe: 'type = "track"',
|
|
17
|
+
mapping: {
|
|
18
|
+
event: {
|
|
19
|
+
'@path': '$.event'
|
|
20
|
+
},
|
|
21
|
+
properties: {
|
|
22
|
+
'@path': '$.properties'
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
describe('Koala.trackEvent', () => {
|
|
29
|
+
test('it maps the event name and properties and passes them into ko.track', async () => {
|
|
30
|
+
window.ko = {
|
|
31
|
+
ready: jest.fn(),
|
|
32
|
+
track: jest.fn().mockResolvedValueOnce(undefined),
|
|
33
|
+
identify: jest.fn().mockResolvedValueOnce(undefined)
|
|
34
|
+
}
|
|
35
|
+
window.KoalaSDK = {
|
|
36
|
+
load: jest.fn().mockResolvedValueOnce(window.ko)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const [event] = await KoalaDestination({
|
|
40
|
+
subscriptions,
|
|
41
|
+
project_slug: 'koala-test'
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const ajs = new Analytics({ writeKey: 'w_123' })
|
|
45
|
+
await event.load(Context.system(), ajs)
|
|
46
|
+
jest.spyOn(destination.actions.trackEvent, 'perform')
|
|
47
|
+
|
|
48
|
+
await event.track?.(
|
|
49
|
+
new Context({
|
|
50
|
+
type: 'track',
|
|
51
|
+
event: 'Form Submitted',
|
|
52
|
+
properties: {
|
|
53
|
+
is_new_subscriber: true
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
expect(destination.actions.trackEvent.perform).toHaveBeenCalledWith(
|
|
59
|
+
expect.anything(),
|
|
60
|
+
expect.objectContaining({
|
|
61
|
+
payload: {
|
|
62
|
+
event: 'Form Submitted',
|
|
63
|
+
properties: {
|
|
64
|
+
is_new_subscriber: true
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
expect(window.ko.track).toHaveBeenCalledWith(
|
|
70
|
+
'Form Submitted',
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
is_new_subscriber: true
|
|
73
|
+
})
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
})
|
|
@@ -0,0 +1,35 @@
|
|
|
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 { Koala } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, Koala, Payload> = {
|
|
7
|
+
title: 'Track Event',
|
|
8
|
+
description: 'Send visitor events to Koala.',
|
|
9
|
+
defaultSubscription: 'type = "track"',
|
|
10
|
+
platform: 'web',
|
|
11
|
+
fields: {
|
|
12
|
+
event: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: true,
|
|
15
|
+
description: 'The event name.',
|
|
16
|
+
label: 'Event Name',
|
|
17
|
+
default: { '@path': '$.event' }
|
|
18
|
+
},
|
|
19
|
+
properties: {
|
|
20
|
+
type: 'object',
|
|
21
|
+
required: false,
|
|
22
|
+
description: 'Properties to send with the event.',
|
|
23
|
+
label: 'Event Properties',
|
|
24
|
+
default: { '@path': '$.properties' },
|
|
25
|
+
defaultObjectUI: 'object'
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
perform: (koala, { payload }) => {
|
|
29
|
+
if (payload?.event) {
|
|
30
|
+
return koala.track(payload.event, payload.properties)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default action
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export interface Koala {
|
|
2
|
+
ready: (fn?: () => Promise<unknown> | unknown) => Promise<void>
|
|
3
|
+
track: (event: string, data?: { [key: string]: unknown }) => Promise<void>
|
|
4
|
+
identify: (traits: Record<string, unknown>) => Promise<void>
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export interface KoalaSDK {
|
|
8
|
+
load: (options: { project: string; hookSegment?: boolean }) => Promise<Koala>
|
|
9
|
+
}
|