@segment/analytics-browser-actions-ripe 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 ADDED
@@ -0,0 +1,20 @@
1
+ {
2
+ "name": "@segment/analytics-browser-actions-ripe",
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,16 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Settings {
4
+ /**
5
+ * The version of the Ripe Widget SDK to use
6
+ */
7
+ sdkVersion?: string
8
+ /**
9
+ * The Ripe API key found in the Ripe App
10
+ */
11
+ apiKey: string
12
+ /**
13
+ * The Ripe API endpoint (do not change this unless you know what you're doing)
14
+ */
15
+ endpoint?: string
16
+ }
@@ -0,0 +1,91 @@
1
+ import type { Subscription } from '@segment/browser-destination-runtime/types'
2
+ import { Analytics, Context } from '@segment/analytics-next'
3
+ import RipeDestination, { destination } from '../../index'
4
+
5
+ import { loadScript } from '@segment/browser-destination-runtime/load-script'
6
+ import { RipeSDK } from '../../types'
7
+
8
+ jest.mock('@segment/browser-destination-runtime/load-script')
9
+ beforeEach(async () => {
10
+ ;(loadScript as jest.Mock).mockResolvedValue(true)
11
+ })
12
+
13
+ const subscriptions: Subscription[] = [
14
+ {
15
+ partnerAction: 'group',
16
+ name: 'Group user',
17
+ enabled: true,
18
+ subscribe: 'type = "group"',
19
+ mapping: {
20
+ messageId: {
21
+ '@path': '$.messageId'
22
+ },
23
+ anonymousId: {
24
+ '@path': '$.anonymousId'
25
+ },
26
+ userId: {
27
+ '@path': '$.userId'
28
+ },
29
+ groupId: {
30
+ '@path': '$.groupId'
31
+ },
32
+ traits: {
33
+ '@path': '$.traits'
34
+ }
35
+ }
36
+ }
37
+ ]
38
+
39
+ describe('Ripe.group', () => {
40
+ test('it maps the event name and properties and passes them into RipeSDK.track', async () => {
41
+ window.Ripe = {
42
+ init: jest.fn().mockResolvedValueOnce('123'),
43
+ group: jest.fn().mockResolvedValueOnce(undefined),
44
+ setIds: jest.fn().mockResolvedValueOnce(undefined)
45
+ } as unknown as RipeSDK
46
+
47
+ const [event] = await RipeDestination({
48
+ subscriptions,
49
+ apiKey: '123'
50
+ })
51
+
52
+ const ajs = new Analytics({ writeKey: '123' })
53
+ await event.load(Context.system(), ajs)
54
+ jest.spyOn(destination.actions.group, 'perform')
55
+
56
+ await event.group?.(
57
+ new Context({
58
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
59
+ anonymousId: 'anonId1',
60
+ type: 'group',
61
+ groupId: 'groupId1',
62
+ traits: {
63
+ is_new_group: true
64
+ }
65
+ })
66
+ )
67
+
68
+ expect(destination.actions.group.perform).toHaveBeenCalledWith(
69
+ expect.anything(),
70
+ expect.objectContaining({
71
+ payload: {
72
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
73
+ anonymousId: 'anonId1',
74
+ userId: undefined,
75
+ groupId: 'groupId1',
76
+ traits: {
77
+ is_new_group: true
78
+ }
79
+ }
80
+ })
81
+ )
82
+
83
+ expect(window.Ripe.group).toHaveBeenCalledWith({
84
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
85
+ anonymousId: 'anonId1',
86
+ userId: undefined,
87
+ groupId: 'groupId1',
88
+ traits: expect.objectContaining({ is_new_group: true })
89
+ })
90
+ })
91
+ })
@@ -0,0 +1,26 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Payload {
4
+ /**
5
+ * The anonymous id
6
+ */
7
+ anonymousId: string
8
+ /**
9
+ * The ID associated with the user
10
+ */
11
+ userId?: string | null
12
+ /**
13
+ * The ID associated groupId
14
+ */
15
+ groupId: string | null
16
+ /**
17
+ * Traits to associate with the group
18
+ */
19
+ traits?: {
20
+ [k: string]: unknown
21
+ }
22
+ /**
23
+ * The Segment messageId
24
+ */
25
+ messageId?: string
26
+ }
@@ -0,0 +1,61 @@
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 { RipeSDK } from '../types'
5
+
6
+ const action: BrowserActionDefinition<Settings, RipeSDK, Payload> = {
7
+ title: 'Group',
8
+ description: 'Group user in Ripe',
9
+ defaultSubscription: 'type = "group"',
10
+ platform: 'web',
11
+ fields: {
12
+ anonymousId: {
13
+ type: 'string',
14
+ required: true,
15
+ description: 'The anonymous id',
16
+ label: 'Anonymous ID',
17
+ default: { '@path': '$.anonymousId' }
18
+ },
19
+ userId: {
20
+ type: 'string',
21
+ required: false,
22
+ allowNull: true,
23
+ description: 'The ID associated with the user',
24
+ label: 'User ID',
25
+ default: { '@path': '$.userId' }
26
+ },
27
+ groupId: {
28
+ type: 'string',
29
+ required: true,
30
+ allowNull: true,
31
+ description: 'The ID associated groupId',
32
+ label: 'Group ID',
33
+ default: { '@path': '$.groupId' }
34
+ },
35
+ traits: {
36
+ type: 'object',
37
+ label: 'Traits',
38
+ description: 'Traits to associate with the group',
39
+ required: false,
40
+ default: { '@path': '$.traits' }
41
+ },
42
+ messageId: {
43
+ type: 'string',
44
+ required: false,
45
+ description: 'The Segment messageId',
46
+ label: 'MessageId',
47
+ default: { '@path': '$.messageId' }
48
+ }
49
+ },
50
+ perform: async (ripe, { payload }) => {
51
+ return ripe.group({
52
+ messageId: payload.messageId,
53
+ anonymousId: payload.anonymousId,
54
+ userId: payload.userId,
55
+ groupId: payload.groupId,
56
+ traits: payload.traits
57
+ })
58
+ }
59
+ }
60
+
61
+ export default action
@@ -0,0 +1,91 @@
1
+ import type { Subscription } from '@segment/browser-destination-runtime/types'
2
+ import { Analytics, Context } from '@segment/analytics-next'
3
+ import RipeDestination, { destination } from '../../index'
4
+ import { RipeSDK } from '../../types'
5
+
6
+ import { loadScript } from '@segment/browser-destination-runtime/load-script'
7
+
8
+ jest.mock('@segment/browser-destination-runtime/load-script')
9
+ beforeEach(async () => {
10
+ ;(loadScript as jest.Mock).mockResolvedValue(true)
11
+ })
12
+
13
+ const subscriptions: Subscription[] = [
14
+ {
15
+ partnerAction: 'identify',
16
+ name: 'Identify user',
17
+ enabled: true,
18
+ subscribe: 'type = "identify"',
19
+ mapping: {
20
+ messageId: {
21
+ '@path': '$.messageId'
22
+ },
23
+ anonymousId: {
24
+ '@path': '$.anonymousId'
25
+ },
26
+ userId: {
27
+ '@path': '$.userId'
28
+ },
29
+ groupId: {
30
+ '@path': '$.groupId'
31
+ },
32
+ traits: {
33
+ '@path': '$.traits'
34
+ }
35
+ }
36
+ }
37
+ ]
38
+
39
+ describe('Ripe.identify', () => {
40
+ test('it maps userId and traits and passes them into RipeSDK.identify', async () => {
41
+ window.Ripe = {
42
+ init: jest.fn().mockResolvedValueOnce('123'),
43
+ identify: jest.fn().mockResolvedValueOnce(undefined),
44
+ setIds: jest.fn().mockResolvedValueOnce(undefined)
45
+ } as unknown as RipeSDK
46
+
47
+ const [event] = await RipeDestination({
48
+ subscriptions,
49
+ apiKey: '123'
50
+ })
51
+
52
+ const ajs = new Analytics({ writeKey: '123' })
53
+ await event.load(Context.system(), ajs)
54
+ jest.spyOn(destination.actions.identify, 'perform')
55
+
56
+ await event.identify?.(
57
+ new Context({
58
+ type: 'identify',
59
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
60
+ anonymousId: 'anonymousId',
61
+ userId: 'userId',
62
+ traits: {
63
+ name: 'Simon'
64
+ }
65
+ })
66
+ )
67
+
68
+ expect(destination.actions.identify.perform).toHaveBeenCalledWith(
69
+ expect.anything(),
70
+ expect.objectContaining({
71
+ payload: {
72
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
73
+ anonymousId: 'anonymousId',
74
+ userId: 'userId',
75
+ groupId: undefined,
76
+ traits: {
77
+ name: 'Simon'
78
+ }
79
+ }
80
+ })
81
+ )
82
+
83
+ expect(window.Ripe.identify).toHaveBeenCalledWith({
84
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
85
+ userId: expect.stringMatching('userId'),
86
+ anonymousId: 'anonymousId',
87
+ groupId: undefined,
88
+ traits: expect.objectContaining({ name: 'Simon' })
89
+ })
90
+ })
91
+ })
@@ -0,0 +1,26 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Payload {
4
+ /**
5
+ * The anonymous id
6
+ */
7
+ anonymousId: string
8
+ /**
9
+ * The ID associated with the user
10
+ */
11
+ userId?: string | null
12
+ /**
13
+ * The ID associated groupId
14
+ */
15
+ groupId?: string | null
16
+ /**
17
+ * Traits to associate with the user
18
+ */
19
+ traits?: {
20
+ [k: string]: unknown
21
+ }
22
+ /**
23
+ * The Segment messageId
24
+ */
25
+ messageId?: string
26
+ }
@@ -0,0 +1,61 @@
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 { RipeSDK } from '../types'
5
+
6
+ const action: BrowserActionDefinition<Settings, RipeSDK, Payload> = {
7
+ title: 'Identify',
8
+ description: 'Identify user in Ripe',
9
+ defaultSubscription: 'type = "identify"',
10
+ platform: 'web',
11
+ fields: {
12
+ anonymousId: {
13
+ type: 'string',
14
+ required: true,
15
+ description: 'The anonymous id',
16
+ label: 'Anonymous ID',
17
+ default: { '@path': '$.anonymousId' }
18
+ },
19
+ userId: {
20
+ type: 'string',
21
+ required: false,
22
+ allowNull: true,
23
+ description: 'The ID associated with the user',
24
+ label: 'User ID',
25
+ default: { '@path': '$.userId' }
26
+ },
27
+ groupId: {
28
+ type: 'string',
29
+ required: false,
30
+ allowNull: true,
31
+ description: 'The ID associated groupId',
32
+ label: 'Group ID',
33
+ default: { '@path': '$.context.groupId' }
34
+ },
35
+ traits: {
36
+ type: 'object',
37
+ label: 'Traits',
38
+ description: 'Traits to associate with the user',
39
+ required: false,
40
+ default: { '@path': '$.traits' }
41
+ },
42
+ messageId: {
43
+ type: 'string',
44
+ required: false,
45
+ description: 'The Segment messageId',
46
+ label: 'MessageId',
47
+ default: { '@path': '$.messageId' }
48
+ }
49
+ },
50
+ perform: async (ripe, { payload }) => {
51
+ return ripe.identify({
52
+ messageId: payload.messageId,
53
+ anonymousId: payload.anonymousId,
54
+ userId: payload.userId,
55
+ groupId: payload.groupId,
56
+ traits: payload.traits
57
+ })
58
+ }
59
+ }
60
+
61
+ export default action
package/src/index.ts ADDED
@@ -0,0 +1,109 @@
1
+ import type { Settings } from './generated-types'
2
+ import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
3
+ import { browserDestination } from '@segment/browser-destination-runtime/shim'
4
+ import { RipeSDK } from './types'
5
+
6
+ import group from './group'
7
+ import identify from './identify'
8
+ import track from './track'
9
+
10
+ import { defaultValues } from '@segment/actions-core'
11
+ import { initScript } from './init-script'
12
+
13
+ import page from './page'
14
+
15
+ const defaultVersion = 'latest'
16
+
17
+ declare global {
18
+ interface Window {
19
+ Ripe: RipeSDK
20
+ }
21
+ }
22
+
23
+ export const destination: BrowserDestinationDefinition<Settings, RipeSDK> = {
24
+ name: 'Ripe Device Mode (Actions)',
25
+ slug: 'actions-ripe',
26
+ mode: 'device',
27
+
28
+ settings: {
29
+ sdkVersion: {
30
+ description: 'The version of the Ripe Widget SDK to use',
31
+ label: 'SDK Version',
32
+ type: 'string',
33
+ choices: [
34
+ {
35
+ value: 'latest',
36
+ label: 'latest'
37
+ }
38
+ ],
39
+ default: defaultVersion,
40
+ required: false
41
+ },
42
+ apiKey: {
43
+ description: 'The Ripe API key found in the Ripe App',
44
+ label: 'API Key',
45
+ type: 'string',
46
+ required: true
47
+ },
48
+ endpoint: {
49
+ label: 'API Endpoint',
50
+ description: `The Ripe API endpoint (do not change this unless you know what you're doing)`,
51
+ type: 'string',
52
+ format: 'uri',
53
+ default: 'https://storage.getripe.com'
54
+ }
55
+ },
56
+
57
+ initialize: async ({ settings }, deps) => {
58
+ initScript()
59
+
60
+ const { sdkVersion, apiKey } = settings
61
+ const version = sdkVersion ?? defaultVersion
62
+ const endpoint = settings.endpoint || 'https://storage.getripe.com'
63
+
64
+ await deps
65
+ .loadScript(`${endpoint}/sdk/${version}/sdk.umd.js`)
66
+ .catch((err) => console.error('Unable to load Ripe SDK script', err))
67
+
68
+ await deps.resolveWhen(() => Object.prototype.hasOwnProperty.call(window, 'Ripe'), 100)
69
+ await window.Ripe.init(apiKey)
70
+
71
+ return window.Ripe
72
+ },
73
+
74
+ actions: {
75
+ group,
76
+ identify,
77
+ page,
78
+ track
79
+ },
80
+
81
+ presets: [
82
+ {
83
+ name: 'Group user',
84
+ subscribe: 'type = "group"',
85
+ partnerAction: 'group',
86
+ mapping: defaultValues(group.fields)
87
+ },
88
+ {
89
+ name: 'Identify user',
90
+ subscribe: 'type = "identify"',
91
+ partnerAction: 'identify',
92
+ mapping: defaultValues(identify.fields)
93
+ },
94
+ {
95
+ name: 'Page view',
96
+ subscribe: 'type = "page"',
97
+ partnerAction: 'page',
98
+ mapping: defaultValues(page.fields)
99
+ },
100
+ {
101
+ name: 'Track event',
102
+ subscribe: 'type = "track"',
103
+ partnerAction: 'track',
104
+ mapping: defaultValues(track.fields)
105
+ }
106
+ ]
107
+ }
108
+
109
+ export default browserDestination(destination)
@@ -0,0 +1,17 @@
1
+ /* eslint-disable */
2
+ // @ts-nocheck
3
+ export function initScript() {
4
+ if (window.Ripe) {
5
+ return
6
+ }
7
+
8
+ window.Ripe = []
9
+ ;['group', 'identify', 'init', 'page', 'track'].forEach(function (method) {
10
+ window.Ripe[method] = function () {
11
+ let args = Array.from(arguments)
12
+ args.unshift(method)
13
+ window.Ripe.push(args)
14
+ return window.Ripe
15
+ }
16
+ })
17
+ }
@@ -0,0 +1,102 @@
1
+ import type { Subscription } from '@segment/browser-destination-runtime/types'
2
+ import { Analytics, Context } from '@segment/analytics-next'
3
+ import RipeDestination, { destination } from '../../index'
4
+ import { RipeSDK } from '../../types'
5
+
6
+ import { loadScript } from '@segment/browser-destination-runtime/load-script'
7
+
8
+ jest.mock('@segment/browser-destination-runtime/load-script')
9
+ beforeEach(async () => {
10
+ ;(loadScript as jest.Mock).mockResolvedValue(true)
11
+ })
12
+
13
+ const subscriptions: Subscription[] = [
14
+ {
15
+ partnerAction: 'page',
16
+ name: 'Page view',
17
+ enabled: true,
18
+ subscribe: 'type = "page"',
19
+ mapping: {
20
+ messageId: {
21
+ '@path': '$.messageId'
22
+ },
23
+ anonymousId: {
24
+ '@path': '$.anonymousId'
25
+ },
26
+ userId: {
27
+ '@path': '$.userId'
28
+ },
29
+ groupId: {
30
+ '@path': '$.groupId'
31
+ },
32
+ category: {
33
+ '@path': '$.category'
34
+ },
35
+ name: {
36
+ '@path': '$.name'
37
+ },
38
+ properties: {
39
+ '@path': '$.properties'
40
+ }
41
+ }
42
+ }
43
+ ]
44
+
45
+ describe('Ripe.page', () => {
46
+ test('it maps pageview properties and passes them into RipeSDK.page', async () => {
47
+ window.Ripe = {
48
+ init: jest.fn().mockResolvedValueOnce('123'),
49
+ page: jest.fn().mockResolvedValueOnce(undefined),
50
+ setIds: jest.fn().mockResolvedValueOnce(undefined)
51
+ } as unknown as RipeSDK
52
+
53
+ const [event] = await RipeDestination({
54
+ subscriptions,
55
+ apiKey: '123'
56
+ })
57
+
58
+ const ajs = new Analytics({ writeKey: '123' })
59
+ await event.load(Context.system(), ajs)
60
+ jest.spyOn(destination.actions.page, 'perform')
61
+
62
+ await event.page?.(
63
+ new Context({
64
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
65
+ anonymousId: 'anonymousId',
66
+ type: 'page',
67
+ category: 'main',
68
+ name: 'page2',
69
+ properties: {
70
+ previous: 'page1'
71
+ }
72
+ })
73
+ )
74
+
75
+ expect(destination.actions.page.perform).toHaveBeenCalledWith(
76
+ expect.anything(),
77
+ expect.objectContaining({
78
+ payload: {
79
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
80
+ anonymousId: 'anonymousId',
81
+ userId: undefined,
82
+ groupId: undefined,
83
+ category: 'main',
84
+ name: 'page2',
85
+ properties: {
86
+ previous: 'page1'
87
+ }
88
+ }
89
+ })
90
+ )
91
+
92
+ expect(window.Ripe.page).toHaveBeenCalledWith({
93
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
94
+ userId: undefined,
95
+ groupId: undefined,
96
+ anonymousId: 'anonymousId',
97
+ category: 'main',
98
+ name: 'page2',
99
+ properties: expect.objectContaining({ previous: 'page1' })
100
+ })
101
+ })
102
+ })
@@ -0,0 +1,34 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Payload {
4
+ /**
5
+ * The anonymous id
6
+ */
7
+ anonymousId: string
8
+ /**
9
+ * The ID associated with the user
10
+ */
11
+ userId?: string | null
12
+ /**
13
+ * The ID associated groupId
14
+ */
15
+ groupId?: string | null
16
+ /**
17
+ * The category of the page
18
+ */
19
+ category?: string
20
+ /**
21
+ * The name of the page
22
+ */
23
+ name?: string
24
+ /**
25
+ * Page properties
26
+ */
27
+ properties?: {
28
+ [k: string]: unknown
29
+ }
30
+ /**
31
+ * The Segment messageId
32
+ */
33
+ messageId?: string
34
+ }
@@ -0,0 +1,89 @@
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 { RipeSDK } from '../types'
5
+
6
+ const action: BrowserActionDefinition<Settings, RipeSDK, Payload> = {
7
+ title: 'Page',
8
+ description: 'Register page view in Ripe',
9
+ defaultSubscription: 'type = "page"',
10
+ platform: 'web',
11
+ fields: {
12
+ anonymousId: {
13
+ type: 'string',
14
+ required: true,
15
+ description: 'The anonymous id',
16
+ label: 'Anonymous ID',
17
+ default: { '@path': '$.anonymousId' }
18
+ },
19
+ userId: {
20
+ type: 'string',
21
+ required: false,
22
+ allowNull: true,
23
+ description: 'The ID associated with the user',
24
+ label: 'User ID',
25
+ default: { '@path': '$.userId' }
26
+ },
27
+ groupId: {
28
+ type: 'string',
29
+ required: false,
30
+ allowNull: true,
31
+ description: 'The ID associated groupId',
32
+ label: 'Group ID',
33
+ default: { '@path': '$.context.groupId' }
34
+ },
35
+ category: {
36
+ type: 'string',
37
+ required: false,
38
+ description: 'The category of the page',
39
+ label: 'Category',
40
+ default: {
41
+ '@if': {
42
+ exists: { '@path': '$.category' },
43
+ then: { '@path': '$.category' },
44
+ else: { '@path': '$.context.category' }
45
+ }
46
+ }
47
+ },
48
+ name: {
49
+ type: 'string',
50
+ required: false,
51
+ description: 'The name of the page',
52
+ label: 'Name',
53
+ default: {
54
+ '@if': {
55
+ exists: { '@path': '$.name' },
56
+ then: { '@path': '$.name' },
57
+ else: { '@path': '$.context.name' }
58
+ }
59
+ }
60
+ },
61
+ properties: {
62
+ type: 'object',
63
+ required: false,
64
+ description: 'Page properties',
65
+ label: 'Properties',
66
+ default: { '@path': '$.properties' }
67
+ },
68
+ messageId: {
69
+ type: 'string',
70
+ required: false,
71
+ description: 'The Segment messageId',
72
+ label: 'MessageId',
73
+ default: { '@path': '$.messageId' }
74
+ }
75
+ },
76
+ perform: async (ripe, { payload }) => {
77
+ return ripe.page({
78
+ messageId: payload.messageId,
79
+ anonymousId: payload.anonymousId,
80
+ userId: payload.userId,
81
+ groupId: payload.groupId,
82
+ category: payload.category,
83
+ name: payload.name,
84
+ properties: payload.properties
85
+ })
86
+ }
87
+ }
88
+
89
+ export default action
@@ -0,0 +1,96 @@
1
+ import type { Subscription } from '@segment/browser-destination-runtime/types'
2
+ import { Analytics, Context } from '@segment/analytics-next'
3
+ import RipeDestination, { destination } from '../../index'
4
+ import { RipeSDK } from '../../types'
5
+
6
+ import { loadScript } from '@segment/browser-destination-runtime/load-script'
7
+
8
+ jest.mock('@segment/browser-destination-runtime/load-script')
9
+ beforeEach(async () => {
10
+ ;(loadScript as jest.Mock).mockResolvedValue(true)
11
+ })
12
+
13
+ const subscriptions: Subscription[] = [
14
+ {
15
+ partnerAction: 'track',
16
+ name: 'Track user',
17
+ enabled: true,
18
+ subscribe: 'type = "track"',
19
+ mapping: {
20
+ messageId: {
21
+ '@path': '$.messageId'
22
+ },
23
+ anonymousId: {
24
+ '@path': '$.anonymousId'
25
+ },
26
+ userId: {
27
+ '@path': '$.userId'
28
+ },
29
+ groupId: {
30
+ '@path': '$.groupId'
31
+ },
32
+ event: {
33
+ '@path': '$.event'
34
+ },
35
+ properties: {
36
+ '@path': '$.properties'
37
+ }
38
+ }
39
+ }
40
+ ]
41
+
42
+ describe('Ripe.track', () => {
43
+ test('it maps the event name and properties and passes them into RipeSDK.track', async () => {
44
+ window.Ripe = {
45
+ init: jest.fn().mockResolvedValueOnce('123'),
46
+ setIds: jest.fn().mockResolvedValueOnce(undefined),
47
+ track: jest.fn().mockResolvedValueOnce(undefined)
48
+ } as unknown as RipeSDK
49
+
50
+ const [event] = await RipeDestination({
51
+ subscriptions,
52
+ apiKey: '123'
53
+ })
54
+
55
+ const ajs = new Analytics({ writeKey: '123' })
56
+ await event.load(Context.system(), ajs)
57
+ jest.spyOn(destination.actions.track, 'perform')
58
+
59
+ await event.track?.(
60
+ new Context({
61
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
62
+ type: 'track',
63
+ anonymousId: 'anonymousId',
64
+ event: 'Form Submitted',
65
+ properties: {
66
+ is_new_lead: true
67
+ }
68
+ })
69
+ )
70
+
71
+ expect(destination.actions.track.perform).toHaveBeenCalledWith(
72
+ expect.anything(),
73
+ expect.objectContaining({
74
+ payload: {
75
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
76
+ anonymousId: 'anonymousId',
77
+ userId: undefined,
78
+ groupId: undefined,
79
+ event: 'Form Submitted',
80
+ properties: {
81
+ is_new_lead: true
82
+ }
83
+ }
84
+ })
85
+ )
86
+
87
+ expect(window.Ripe.track).toHaveBeenCalledWith({
88
+ messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
89
+ anonymousId: 'anonymousId',
90
+ userId: undefined,
91
+ groupId: undefined,
92
+ event: 'Form Submitted',
93
+ properties: expect.objectContaining({ is_new_lead: true })
94
+ })
95
+ })
96
+ })
@@ -0,0 +1,30 @@
1
+ // Generated file. DO NOT MODIFY IT BY HAND.
2
+
3
+ export interface Payload {
4
+ /**
5
+ * The anonymous id
6
+ */
7
+ anonymousId: string
8
+ /**
9
+ * The ID associated with the user
10
+ */
11
+ userId?: string | null
12
+ /**
13
+ * The ID associated groupId
14
+ */
15
+ groupId?: string | null
16
+ /**
17
+ * The event name
18
+ */
19
+ event: string
20
+ /**
21
+ * Properties to send with the event
22
+ */
23
+ properties?: {
24
+ [k: string]: unknown
25
+ }
26
+ /**
27
+ * The Segment messageId
28
+ */
29
+ messageId?: string
30
+ }
@@ -0,0 +1,71 @@
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 { RipeSDK } from '../types'
5
+
6
+ const action: BrowserActionDefinition<Settings, RipeSDK, Payload> = {
7
+ title: 'Track',
8
+ description: 'Send user events to Ripe',
9
+ defaultSubscription: 'type = "track"',
10
+ platform: 'web',
11
+ fields: {
12
+ anonymousId: {
13
+ type: 'string',
14
+ required: true,
15
+ description: 'The anonymous id',
16
+ label: 'Anonymous ID',
17
+ default: { '@path': '$.anonymousId' }
18
+ },
19
+ userId: {
20
+ type: 'string',
21
+ required: false,
22
+ allowNull: true,
23
+ description: 'The ID associated with the user',
24
+ label: 'User ID',
25
+ default: { '@path': '$.userId' }
26
+ },
27
+ groupId: {
28
+ type: 'string',
29
+ required: false,
30
+ allowNull: true,
31
+ description: 'The ID associated groupId',
32
+ label: 'Group ID',
33
+ default: { '@path': '$.context.groupId' }
34
+ },
35
+ event: {
36
+ type: 'string',
37
+ required: true,
38
+ description: 'The event name',
39
+ label: 'Event Name',
40
+ default: { '@path': '$.event' }
41
+ },
42
+ properties: {
43
+ type: 'object',
44
+ required: false,
45
+ description: 'Properties to send with the event',
46
+ label: 'Event properties',
47
+ default: { '@path': '$.properties' }
48
+ },
49
+ messageId: {
50
+ type: 'string',
51
+ required: false,
52
+ description: 'The Segment messageId',
53
+ label: 'MessageId',
54
+ default: { '@path': '$.messageId' }
55
+ }
56
+ },
57
+ perform: async (ripe, { payload }) => {
58
+ if (payload?.event) {
59
+ return ripe.track({
60
+ messageId: payload.messageId,
61
+ anonymousId: payload.anonymousId,
62
+ userId: payload.userId,
63
+ groupId: payload.groupId,
64
+ event: payload.event,
65
+ properties: payload.properties
66
+ })
67
+ }
68
+ }
69
+ }
70
+
71
+ export default action
package/src/types.ts ADDED
@@ -0,0 +1,61 @@
1
+ export interface RipeSDK {
2
+ group: ({
3
+ anonymousId,
4
+ userId,
5
+ messageId,
6
+ groupId,
7
+ traits
8
+ }: {
9
+ messageId?: string
10
+ anonymousId: string
11
+ userId?: string | null
12
+ groupId: string | null
13
+ traits?: Record<string, unknown>
14
+ }) => Promise<void>
15
+ identify: ({
16
+ messageId,
17
+ anonymousId,
18
+ userId,
19
+ groupId,
20
+ traits
21
+ }: {
22
+ messageId?: string
23
+ anonymousId: string
24
+ userId?: string | null
25
+ groupId?: string | null
26
+ traits?: Record<string, unknown>
27
+ }) => Promise<void>
28
+ init: (apiKey: string) => Promise<void>
29
+ page: ({
30
+ messageId,
31
+ anonymousId,
32
+ userId,
33
+ groupId,
34
+ category,
35
+ name,
36
+ properties
37
+ }: {
38
+ messageId?: string
39
+ anonymousId: string
40
+ userId?: string | null
41
+ groupId?: string | null
42
+ category?: string
43
+ name?: string
44
+ properties?: Record<string, unknown>
45
+ }) => Promise<void>
46
+ track: ({
47
+ messageId,
48
+ anonymousId,
49
+ userId,
50
+ groupId,
51
+ event,
52
+ properties
53
+ }: {
54
+ messageId?: string
55
+ anonymousId: string
56
+ userId?: string | null
57
+ groupId?: string | null
58
+ event: string
59
+ properties?: Record<string, unknown>
60
+ }) => Promise<void>
61
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.build.json",
3
+ "compilerOptions": {
4
+ "rootDir": "./src",
5
+ "baseUrl": "."
6
+ },
7
+ "include": ["src"],
8
+ "exclude": ["dist", "**/__tests__"]
9
+ }