@segment/analytics-browser-actions-iterate 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 +62 -0
- package/src/generated-types.ts +8 -0
- package/src/identifyUser/__tests__/index.test.ts +52 -0
- package/src/identifyUser/generated-types.ts +14 -0
- package/src/identifyUser/index.ts +42 -0
- package/src/index.ts +80 -0
- package/src/trackEvent/__tests__/index.test.ts +43 -0
- package/src/trackEvent/generated-types.ts +8 -0
- package/src/trackEvent/index.ts +27 -0
- package/src/types.ts +23 -0
- package/tsconfig.json +9 -0
package/package.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@segment/analytics-browser-actions-iterate",
|
|
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,62 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import iterateDestination, { destination } from '../index'
|
|
3
|
+
import { Subscription } from '@segment/browser-destination-runtime/types'
|
|
4
|
+
|
|
5
|
+
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
|
+
}
|
|
16
|
+
}
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
describe('Iterate initialization', () => {
|
|
20
|
+
test('can load Iterate', async () => {
|
|
21
|
+
const [event] = await iterateDestination({
|
|
22
|
+
apiKey: 'abc123',
|
|
23
|
+
subscriptions
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
jest.spyOn(destination.actions.trackEvent, 'perform')
|
|
27
|
+
jest.spyOn(destination, 'initialize')
|
|
28
|
+
|
|
29
|
+
await event.load(Context.system(), {} as Analytics)
|
|
30
|
+
expect(destination.initialize).toHaveBeenCalled()
|
|
31
|
+
|
|
32
|
+
const ctx = await event.track?.(
|
|
33
|
+
new Context({
|
|
34
|
+
type: 'track',
|
|
35
|
+
name: 'example-event'
|
|
36
|
+
})
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
expect(destination.actions.trackEvent.perform).toHaveBeenCalled()
|
|
40
|
+
expect(ctx).not.toBeUndefined()
|
|
41
|
+
|
|
42
|
+
const scripts = window.document.querySelectorAll('script')
|
|
43
|
+
scripts[0].src = scripts[0].src.replace(/match-prod-.*.js/, 'match-prod.js')
|
|
44
|
+
expect(scripts).toMatchInlineSnapshot(`
|
|
45
|
+
NodeList [
|
|
46
|
+
<script
|
|
47
|
+
id="iterate-script"
|
|
48
|
+
src="https://platform.iteratehq.com/match-prod.js"
|
|
49
|
+
type="text/javascript"
|
|
50
|
+
/>,
|
|
51
|
+
<script
|
|
52
|
+
src="https://platform.iteratehq.com/loader.js"
|
|
53
|
+
status="loaded"
|
|
54
|
+
type="text/javascript"
|
|
55
|
+
/>,
|
|
56
|
+
<script>
|
|
57
|
+
// the emptiness
|
|
58
|
+
</script>,
|
|
59
|
+
]
|
|
60
|
+
`)
|
|
61
|
+
})
|
|
62
|
+
})
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import iterateDestination, { destination } from '../../index'
|
|
3
|
+
|
|
4
|
+
describe('Iterate.identifyUser', () => {
|
|
5
|
+
it('Should call identify', async () => {
|
|
6
|
+
const [identifyEvent] = await iterateDestination({
|
|
7
|
+
apiKey: '123',
|
|
8
|
+
subscriptions: [
|
|
9
|
+
{
|
|
10
|
+
partnerAction: 'identifyUser',
|
|
11
|
+
name: 'Identify User',
|
|
12
|
+
enabled: true,
|
|
13
|
+
subscribe: 'type = "identify"',
|
|
14
|
+
mapping: {
|
|
15
|
+
userId: {
|
|
16
|
+
'@path': '$.userId'
|
|
17
|
+
},
|
|
18
|
+
traits: {
|
|
19
|
+
'@path': '$.traits'
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
destination.actions.identifyUser.perform = jest.fn()
|
|
27
|
+
const identifySpy = jest.spyOn(destination.actions.identifyUser, 'perform')
|
|
28
|
+
await identifyEvent.load(Context.system(), {} as Analytics)
|
|
29
|
+
|
|
30
|
+
await identifyEvent.identify?.(
|
|
31
|
+
new Context({
|
|
32
|
+
type: 'identify',
|
|
33
|
+
userId: '123abc',
|
|
34
|
+
traits: {
|
|
35
|
+
foo: 'bar'
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
expect(identifySpy).toHaveBeenCalledWith(
|
|
41
|
+
expect.anything(),
|
|
42
|
+
expect.objectContaining({
|
|
43
|
+
payload: {
|
|
44
|
+
userId: '123abc',
|
|
45
|
+
traits: {
|
|
46
|
+
foo: 'bar'
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
})
|
|
52
|
+
})
|
|
@@ -0,0 +1,42 @@
|
|
|
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 { Iterate as IterateClient, Command } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, IterateClient, Payload> = {
|
|
7
|
+
title: 'Identify User',
|
|
8
|
+
description: 'Sets user identity',
|
|
9
|
+
platform: 'web',
|
|
10
|
+
defaultSubscription: 'type = "identify"',
|
|
11
|
+
fields: {
|
|
12
|
+
userId: {
|
|
13
|
+
type: 'string',
|
|
14
|
+
required: false,
|
|
15
|
+
description: "The user's identity.",
|
|
16
|
+
label: 'Identity',
|
|
17
|
+
default: {
|
|
18
|
+
'@path': '$.userId'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
traits: {
|
|
22
|
+
type: 'object',
|
|
23
|
+
required: false,
|
|
24
|
+
description: 'The Segment traits to be forwarded to Iterate.',
|
|
25
|
+
label: 'Traits',
|
|
26
|
+
default: {
|
|
27
|
+
'@path': '$.traits'
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
perform: (Iterate, event) => {
|
|
32
|
+
const traits = event.payload.traits || {}
|
|
33
|
+
|
|
34
|
+
if (event.payload.userId) {
|
|
35
|
+
traits['external_id'] = event.payload.userId
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
Iterate(Command.Identify, traits)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export default action
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
|
|
2
|
+
import { browserDestination } from '@segment/browser-destination-runtime/shim'
|
|
3
|
+
import type { Settings } from './generated-types'
|
|
4
|
+
import { Iterate, IterateApi, IterateSettings } from './types'
|
|
5
|
+
import { defaultValues } from '@segment/actions-core'
|
|
6
|
+
|
|
7
|
+
import trackEvent from './trackEvent'
|
|
8
|
+
import identifyUser from './identifyUser'
|
|
9
|
+
|
|
10
|
+
// Declare global to access your client
|
|
11
|
+
declare global {
|
|
12
|
+
interface Window {
|
|
13
|
+
Iterate: Iterate
|
|
14
|
+
iterateSettings: IterateSettings
|
|
15
|
+
IterateObjectName: string
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Switch from unknown to the partner SDK client types
|
|
20
|
+
export const destination: BrowserDestinationDefinition<Settings, Iterate> = {
|
|
21
|
+
name: 'Iterate Web (Actions)',
|
|
22
|
+
slug: 'actions-iterate',
|
|
23
|
+
mode: 'device',
|
|
24
|
+
presets: [
|
|
25
|
+
{
|
|
26
|
+
name: 'Track Event',
|
|
27
|
+
subscribe: 'type = "track"',
|
|
28
|
+
partnerAction: 'trackEvent',
|
|
29
|
+
mapping: defaultValues(trackEvent.fields)
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: 'Identify User',
|
|
33
|
+
subscribe: 'type = "identify"',
|
|
34
|
+
partnerAction: 'identifyUser',
|
|
35
|
+
mapping: defaultValues(identifyUser.fields)
|
|
36
|
+
}
|
|
37
|
+
],
|
|
38
|
+
|
|
39
|
+
settings: {
|
|
40
|
+
// Add any Segment destination settings required here
|
|
41
|
+
apiKey: {
|
|
42
|
+
label: 'Embed API Key',
|
|
43
|
+
description: 'The Embed API Key for your account. You can find this on your settings pages.',
|
|
44
|
+
type: 'string',
|
|
45
|
+
required: true
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
initialize: async ({ settings }, deps) => {
|
|
50
|
+
// initialize settings
|
|
51
|
+
window.iterateSettings = {
|
|
52
|
+
apiKey: settings.apiKey,
|
|
53
|
+
installOnLoad: false
|
|
54
|
+
}
|
|
55
|
+
window.IterateObjectName = 'Iterate'
|
|
56
|
+
|
|
57
|
+
// Initialize placeholder Iterate command
|
|
58
|
+
const iteratePlaceholder = <IterateApi>function (...args) {
|
|
59
|
+
iteratePlaceholder.command(args)
|
|
60
|
+
}
|
|
61
|
+
iteratePlaceholder.loaded = false
|
|
62
|
+
iteratePlaceholder.q = []
|
|
63
|
+
iteratePlaceholder.command = function (args: unknown[]) {
|
|
64
|
+
iteratePlaceholder.q.push(args)
|
|
65
|
+
}
|
|
66
|
+
window.Iterate = iteratePlaceholder
|
|
67
|
+
|
|
68
|
+
await deps.loadScript('https://platform.iteratehq.com/loader.js')
|
|
69
|
+
await deps.resolveWhen(() => !Object.prototype.hasOwnProperty.call(window.Iterate, 'loaded'), 100)
|
|
70
|
+
|
|
71
|
+
return window.Iterate
|
|
72
|
+
},
|
|
73
|
+
|
|
74
|
+
actions: {
|
|
75
|
+
trackEvent,
|
|
76
|
+
identifyUser
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default browserDestination(destination)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Analytics, Context } from '@segment/analytics-next'
|
|
2
|
+
import iterateDestination, { destination } from '../../index'
|
|
3
|
+
|
|
4
|
+
describe('Iterate.trackEvent', () => {
|
|
5
|
+
it('Sends events to Iterate', async () => {
|
|
6
|
+
const [trackEvent] = await iterateDestination({
|
|
7
|
+
apiKey: 'abc123',
|
|
8
|
+
subscriptions: [
|
|
9
|
+
{
|
|
10
|
+
partnerAction: 'trackEvent',
|
|
11
|
+
name: 'Track Event',
|
|
12
|
+
enabled: true,
|
|
13
|
+
subscribe: 'type = "track"',
|
|
14
|
+
mapping: {
|
|
15
|
+
name: {
|
|
16
|
+
'@path': '$.name'
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
destination.actions.trackEvent.perform = jest.fn()
|
|
24
|
+
const trackSpy = jest.spyOn(destination.actions.trackEvent, 'perform')
|
|
25
|
+
await trackEvent.load(Context.system(), {} as Analytics)
|
|
26
|
+
|
|
27
|
+
await trackEvent.track?.(
|
|
28
|
+
new Context({
|
|
29
|
+
type: 'track',
|
|
30
|
+
name: 'example-event'
|
|
31
|
+
})
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
expect(trackSpy).toHaveBeenCalledWith(
|
|
35
|
+
expect.anything(),
|
|
36
|
+
expect.objectContaining({
|
|
37
|
+
payload: {
|
|
38
|
+
name: 'example-event'
|
|
39
|
+
}
|
|
40
|
+
})
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
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 { Iterate as IterateClient, Command } from '../types'
|
|
5
|
+
|
|
6
|
+
const action: BrowserActionDefinition<Settings, IterateClient, 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: 'Name',
|
|
15
|
+
required: true,
|
|
16
|
+
type: 'string',
|
|
17
|
+
default: {
|
|
18
|
+
'@path': '$.event'
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
perform: (Iterate, event) => {
|
|
23
|
+
Iterate(Command.Event, event.payload.name)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export default action
|
package/src/types.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type Iterate = (command: Command, ...args: unknown[]) => void
|
|
2
|
+
|
|
3
|
+
export enum Command {
|
|
4
|
+
Event = 'event',
|
|
5
|
+
Install = 'install',
|
|
6
|
+
Identify = 'identify',
|
|
7
|
+
OnResponse = 'onResponse',
|
|
8
|
+
OnLoad = 'onLoad',
|
|
9
|
+
onClose = 'onClose',
|
|
10
|
+
Uninstall = 'uninstall'
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type IterateApi = {
|
|
14
|
+
(): void
|
|
15
|
+
q: unknown[]
|
|
16
|
+
command: (args: unknown[]) => void
|
|
17
|
+
loaded: boolean
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type IterateSettings = {
|
|
21
|
+
apiKey: string
|
|
22
|
+
installOnLoad?: boolean
|
|
23
|
+
}
|