From b60859d3bee3781284a48e8975d21143b1d03f8e Mon Sep 17 00:00:00 2001
From: "M.Byun" <48914716+bombamong@users.noreply.github.com>
Date: Mon, 2 Oct 2023 20:16:10 +0900
Subject: [PATCH 001/389] feat: hubble-web browser-destination (#1566)
* feat: hubble-web browser-destination
* refactor: change settings appId to id
* refactor: setSource to be global and add identifiers to track
* fix(hubble-web): set optional chaining when setting source on initialize
* refactor: make identify and track take objects as arguments
* fix: change to production URL for script
* fix: failing test for hubble-web browser destination
- change test to correct URL
- add optional chaining to setSource on initialize
---
.../destinations/hubble-web/README.md | 31 ++++++
.../destinations/hubble-web/package.json | 24 +++++
.../__snapshots__/index.test.ts.snap | 16 +++
.../hubble-web/src/__tests__/index.test.ts | 101 ++++++++++++++++++
.../hubble-web/src/generated-types.ts | 8 ++
.../src/identify/__tests__/index.test.ts | 92 ++++++++++++++++
.../src/identify/generated-types.ts | 18 ++++
.../hubble-web/src/identify/index.ts | 49 +++++++++
.../destinations/hubble-web/src/index.ts | 64 +++++++++++
.../src/track/__tests__/index.test.ts | 84 +++++++++++++++
.../hubble-web/src/track/generated-types.ts | 22 ++++
.../hubble-web/src/track/index.ts | 63 +++++++++++
.../destinations/hubble-web/src/types.ts | 10 ++
.../destinations/hubble-web/tsconfig.json | 9 ++
14 files changed, 591 insertions(+)
create mode 100644 packages/browser-destinations/destinations/hubble-web/README.md
create mode 100644 packages/browser-destinations/destinations/hubble-web/package.json
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/__tests__/__snapshots__/index.test.ts.snap
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/__tests__/index.test.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/identify/__tests__/index.test.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/identify/index.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/index.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/track/__tests__/index.test.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/track/generated-types.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/track/index.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/src/types.ts
create mode 100644 packages/browser-destinations/destinations/hubble-web/tsconfig.json
diff --git a/packages/browser-destinations/destinations/hubble-web/README.md b/packages/browser-destinations/destinations/hubble-web/README.md
new file mode 100644
index 0000000000..fad1cb7abb
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/README.md
@@ -0,0 +1,31 @@
+# @segment/analytics-browser-hubble-web
+
+The Hubble (actions) browser action destination for use with @segment/analytics-next.
+
+## License
+
+MIT License
+
+Copyright (c) 2023 Segment
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+## Contributing
+
+All third party contributors acknowledge that any contributions they provide will be made under the same open source license that the open source project is provided under.
diff --git a/packages/browser-destinations/destinations/hubble-web/package.json b/packages/browser-destinations/destinations/hubble-web/package.json
new file mode 100644
index 0000000000..57d02d1556
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@segment/analytics-browser-hubble-web",
+ "version": "1.0.0",
+ "license": "MIT",
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org"
+ },
+ "main": "./dist/cjs",
+ "module": "./dist/esm",
+ "scripts": {
+ "build": "yarn build:esm && yarn build:cjs",
+ "build:cjs": "tsc --module commonjs --outDir ./dist/cjs",
+ "build:esm": "tsc --outDir ./dist/esm"
+ },
+ "typings": "./dist/esm",
+ "dependencies": {
+ "@segment/actions-core": "^3.83.0",
+ "@segment/browser-destination-runtime": "^1.4.0"
+ },
+ "peerDependencies": {
+ "@segment/analytics-next": ">=1.55.0"
+ }
+}
diff --git a/packages/browser-destinations/destinations/hubble-web/src/__tests__/__snapshots__/index.test.ts.snap b/packages/browser-destinations/destinations/hubble-web/src/__tests__/__snapshots__/index.test.ts.snap
new file mode 100644
index 0000000000..ec0642738e
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/__tests__/__snapshots__/index.test.ts.snap
@@ -0,0 +1,16 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Hubble load Hubble SDK:
+
+ 1`] = `
+NodeList [
+ ,
+]
+`;
diff --git a/packages/browser-destinations/destinations/hubble-web/src/__tests__/index.test.ts b/packages/browser-destinations/destinations/hubble-web/src/__tests__/index.test.ts
new file mode 100644
index 0000000000..ebd9421846
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/__tests__/index.test.ts
@@ -0,0 +1,101 @@
+import { Subscription } from '@segment/browser-destination-runtime/types'
+import { Analytics, Context } from '@segment/analytics-next'
+import hubbleDestination, { destination } from '../index'
+
+const subscriptions: Subscription[] = [
+ {
+ name: 'Identify user',
+ subscribe: 'type = "identify"',
+ partnerAction: 'identify',
+ enabled: true,
+ mapping: {
+ userId: {
+ type: 'string',
+ required: true,
+ label: 'User ID',
+ description: 'Unique user ID',
+ default: {
+ '@path': '$.userId'
+ }
+ },
+ anonymousId: {
+ type: 'string',
+ required: false,
+ description: 'Anonymous id of the user',
+ label: 'Anonymous ID',
+ default: {
+ '@path': '$.anonymousId'
+ }
+ },
+ attributes: {
+ type: 'object',
+ required: false,
+ description: 'User traits used to enrich user identification',
+ label: 'Traits',
+ default: {
+ '@path': '$.traits'
+ }
+ }
+ }
+ },
+ {
+ name: 'Track event',
+ subscribe: 'type = "track"',
+ partnerAction: 'track',
+ enabled: true,
+ mapping: {
+ event: {
+ description: 'Event to be tracked',
+ label: 'Event',
+ required: true,
+ type: 'string',
+ default: {
+ '@path': '$.event'
+ }
+ },
+ attributes: {
+ description: 'Object containing the attributes (properties) of the event',
+ type: 'object',
+ required: false,
+ label: 'Event Attributes',
+ default: {
+ '@path': '$.properties'
+ }
+ }
+ }
+ }
+]
+
+describe('Hubble', () => {
+ beforeAll(() => {
+ jest.mock('@segment/browser-destination-runtime/load-script', () => ({
+ loadScript: (_src: any, _attributes: any) => {}
+ }))
+ jest.mock('@segment/browser-destination-runtime/resolve-when', () => ({
+ resolveWhen: (_fn: any, _timeout: any) => {}
+ }))
+ })
+
+ const testID = 'testId'
+
+ test('load Hubble SDK', async () => {
+ const [event] = await hubbleDestination({
+ id: testID,
+ subscriptions
+ })
+
+ jest.spyOn(destination, 'initialize')
+ await event.load(Context.system(), {} as Analytics)
+ expect(destination.initialize).toHaveBeenCalled()
+
+ const scripts = window.document.querySelectorAll('script')
+ expect(scripts).toMatchSnapshot(`
+
+ `)
+ })
+})
diff --git a/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts b/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
new file mode 100644
index 0000000000..d7c0c3af40
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
@@ -0,0 +1,8 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * id
+ */
+ id: string
+}
diff --git a/packages/browser-destinations/destinations/hubble-web/src/identify/__tests__/index.test.ts b/packages/browser-destinations/destinations/hubble-web/src/identify/__tests__/index.test.ts
new file mode 100644
index 0000000000..f7cfa89e93
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/identify/__tests__/index.test.ts
@@ -0,0 +1,92 @@
+import { Analytics, Context } from '@segment/analytics-next'
+import hubbleDestination, { destination } from '../../index'
+import { Subscription } from '@segment/browser-destination-runtime/types'
+
+const subscriptions: Subscription[] = [
+ {
+ partnerAction: 'identify',
+ name: 'Identify User',
+ enabled: true,
+ subscribe: 'type = "identify"',
+ mapping: {
+ anonymousId: {
+ '@path': '$.anonymousId'
+ },
+ userId: {
+ '@path': '$.userId'
+ },
+ attributes: {
+ '@path': '$.traits'
+ }
+ }
+ }
+]
+
+describe('identify', () => {
+ beforeAll(() => {
+ jest.mock('@segment/browser-destination-runtime/load-script', () => ({
+ loadScript: (_src: any, _attributes: any) => {}
+ }))
+ jest.mock('@segment/browser-destination-runtime/resolve-when', () => ({
+ resolveWhen: (_fn: any, _timeout: any) => {}
+ }))
+ })
+
+ let identify: any
+ const mockIdentify: jest.Mock = jest.fn()
+
+ beforeEach(async () => {
+ const [hubbleIdentify] = await hubbleDestination({
+ id: 'testID',
+ subscriptions
+ })
+
+ identify = hubbleIdentify
+
+ jest.spyOn(destination, 'initialize').mockImplementation(() => {
+ const mockedWithTrack = {
+ id: 'testID',
+ initialized: true,
+ emitter: { setSource: jest.fn() },
+ track: mockIdentify,
+ identify: jest.fn(),
+ setSource: jest.fn()
+ }
+ return Promise.resolve(mockedWithTrack)
+ })
+ await identify.load(Context.system(), {} as Analytics)
+ })
+
+ test('it maps event parameters correctly to identify function ', async () => {
+ jest.spyOn(destination.actions.identify, 'perform')
+ await identify.load(Context.system(), {} as Analytics)
+
+ await identify.identify?.(
+ new Context({
+ type: 'identify',
+ anonymousId: 'anon-123',
+ userId: 'some-user-123',
+ traits: {
+ someNumber: 123,
+ hello: 'world',
+ email: 'this_email@hubble.team'
+ }
+ })
+ )
+
+ expect(destination.actions.identify.perform).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({
+ payload: {
+ anonymousId: 'anon-123',
+ userId: 'some-user-123',
+ attributes: {
+ someNumber: 123,
+ hello: 'world',
+ email: 'this_email@hubble.team'
+ }
+ }
+ })
+ )
+ })
+})
diff --git a/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts b/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
new file mode 100644
index 0000000000..75c2e07c00
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
@@ -0,0 +1,18 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Unique identifer of the user
+ */
+ userId: string
+ /**
+ * Anonymous identifier of the user
+ */
+ anonymousId?: string
+ /**
+ * User traits used to enrich user identification
+ */
+ attributes?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/browser-destinations/destinations/hubble-web/src/identify/index.ts b/packages/browser-destinations/destinations/hubble-web/src/identify/index.ts
new file mode 100644
index 0000000000..8122a46a17
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/identify/index.ts
@@ -0,0 +1,49 @@
+import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
+import { Hubble } from '../types'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+// Change from unknown to the partner SDK types
+const action: BrowserActionDefinition = {
+ title: 'Identify',
+ description: 'Set identifiers and attributes for a user',
+ platform: 'web',
+ defaultSubscription: 'type = "identify"',
+ fields: {
+ userId: {
+ description: 'Unique identifer of the user',
+ type: 'string',
+ required: false,
+ label: 'User ID',
+ default: {
+ '@path': '$.userId'
+ }
+ },
+ anonymousId: {
+ description: 'Anonymous identifier of the user',
+ type: 'string',
+ required: false,
+ label: 'Anonymous ID',
+ default: {
+ '@path': '$.anonymousId'
+ }
+ },
+ attributes: {
+ description: 'User traits used to enrich user identification',
+ type: 'object',
+ required: false,
+ label: 'User Attributes (Traits)',
+ default: {
+ '@path': '$.traits'
+ }
+ }
+ },
+ perform: (hubble, event) => {
+ const payload = event.payload
+
+ hubble.identify &&
+ hubble.identify({ userId: payload.userId, anonymousId: payload.anonymousId, attributes: payload.attributes })
+ }
+}
+
+export default action
diff --git a/packages/browser-destinations/destinations/hubble-web/src/index.ts b/packages/browser-destinations/destinations/hubble-web/src/index.ts
new file mode 100644
index 0000000000..adef7740f4
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/index.ts
@@ -0,0 +1,64 @@
+import type { Settings } from './generated-types'
+import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
+import { browserDestination } from '@segment/browser-destination-runtime/shim'
+
+import { Hubble } from './types'
+import { defaultValues } from '@segment/actions-core'
+
+import track from './track'
+import identify from './identify'
+
+declare global {
+ interface Window {
+ Hubble: Hubble
+ }
+}
+
+export const destination: BrowserDestinationDefinition = {
+ name: 'Hubble (actions)',
+ slug: 'hubble-web',
+ mode: 'device',
+ description:
+ 'From design to production, monitor, measure and enhance your user experience with seamless integration with Segment',
+ presets: [
+ {
+ name: 'Identify user',
+ subscribe: 'type = "identify"',
+ partnerAction: 'identify',
+ mapping: defaultValues(identify.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Track event',
+ subscribe: 'type = "track"',
+ partnerAction: 'track',
+ mapping: defaultValues(track.fields),
+ type: 'automatic'
+ }
+ ],
+
+ settings: {
+ id: {
+ description: 'Unique identifier for your team (given in Hubble app)',
+ label: 'id',
+ type: 'string',
+ required: true
+ }
+ },
+
+ initialize: async ({ settings }, deps) => {
+ await deps.loadScript(`https://sdk.hubble.team/api/sdk/${settings.id}`)
+ await deps.resolveWhen(() => window?.Hubble?.initialized, 250)
+
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ window?.Hubble?.setSource('__segment__')
+ return window.Hubble
+ },
+
+ actions: {
+ track,
+ identify
+ }
+}
+
+export default browserDestination(destination)
diff --git a/packages/browser-destinations/destinations/hubble-web/src/track/__tests__/index.test.ts b/packages/browser-destinations/destinations/hubble-web/src/track/__tests__/index.test.ts
new file mode 100644
index 0000000000..b6f29b62ec
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/track/__tests__/index.test.ts
@@ -0,0 +1,84 @@
+import { Analytics, Context } from '@segment/analytics-next'
+import hubbleDestination, { destination } from '../../index'
+import { Subscription } from '@segment/browser-destination-runtime/types'
+
+const subscriptions: Subscription[] = [
+ {
+ partnerAction: 'track',
+ name: 'Track event',
+ enabled: true,
+ subscribe: 'type = "track"',
+ mapping: {
+ event: {
+ '@path': '$.event'
+ },
+ attributes: {
+ '@path': '$.properties'
+ }
+ }
+ }
+]
+
+describe('track', () => {
+ beforeAll(() => {
+ jest.mock('@segment/browser-destination-runtime/load-script', () => ({
+ loadScript: (_src: any, _attributes: any) => {}
+ }))
+ jest.mock('@segment/browser-destination-runtime/resolve-when', () => ({
+ resolveWhen: (_fn: any, _timeout: any) => {}
+ }))
+ })
+
+ let track: any
+ const mockTrack: jest.Mock = jest.fn()
+
+ beforeEach(async () => {
+ const [hubbleTrack] = await hubbleDestination({
+ id: 'testID',
+ subscriptions
+ })
+
+ track = hubbleTrack
+
+ jest.spyOn(destination, 'initialize').mockImplementation(() => {
+ const mockedWithTrack = {
+ id: 'testID',
+ initialized: true,
+ emitter: { setSource: jest.fn() },
+ track: mockTrack,
+ identify: jest.fn(),
+ setSource: jest.fn()
+ }
+ return Promise.resolve(mockedWithTrack)
+ })
+ await track.load(Context.system(), {} as Analytics)
+ })
+
+ test('it maps event parameters correctly to track function', async () => {
+ jest.spyOn(destination.actions.track, 'perform')
+
+ await track.track?.(
+ new Context({
+ type: 'track',
+ event: 'event-test',
+ properties: {
+ prop1: 'something',
+ prop2: 'another-thing'
+ }
+ })
+ )
+
+ expect(destination.actions.track.perform).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({
+ payload: {
+ event: 'event-test',
+ attributes: {
+ prop1: 'something',
+ prop2: 'another-thing'
+ }
+ }
+ })
+ )
+ })
+})
diff --git a/packages/browser-destinations/destinations/hubble-web/src/track/generated-types.ts b/packages/browser-destinations/destinations/hubble-web/src/track/generated-types.ts
new file mode 100644
index 0000000000..95b0d403de
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/track/generated-types.ts
@@ -0,0 +1,22 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Event to be tracked
+ */
+ event: string
+ /**
+ * Object containing the attributes (properties) of the event
+ */
+ attributes?: {
+ [k: string]: unknown
+ }
+ /**
+ * Unique identifer of the user
+ */
+ userId?: string
+ /**
+ * Anonymous identifier of the user
+ */
+ anonymousId?: string
+}
diff --git a/packages/browser-destinations/destinations/hubble-web/src/track/index.ts b/packages/browser-destinations/destinations/hubble-web/src/track/index.ts
new file mode 100644
index 0000000000..ffbf3fad2b
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/track/index.ts
@@ -0,0 +1,63 @@
+import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
+import { Hubble } from '../types'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+// Change from unknown to the partner SDK types
+const action: BrowserActionDefinition = {
+ title: 'Track',
+ description: 'Track events to trigger Hubble surveys',
+ platform: 'web',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ event: {
+ description: 'Event to be tracked',
+ label: 'Event',
+ required: true,
+ type: 'string',
+ default: {
+ '@path': '$.event'
+ }
+ },
+ attributes: {
+ description: 'Object containing the attributes (properties) of the event',
+ type: 'object',
+ required: false,
+ label: 'Event Attributes',
+ default: {
+ '@path': '$.properties'
+ }
+ },
+ userId: {
+ description: 'Unique identifer of the user',
+ type: 'string',
+ required: false,
+ label: 'User ID',
+ default: {
+ '@path': '$.userId'
+ }
+ },
+ anonymousId: {
+ description: 'Anonymous identifier of the user',
+ type: 'string',
+ required: false,
+ label: 'Anonymous ID',
+ default: {
+ '@path': '$.anonymousId'
+ }
+ }
+ },
+ perform: (hubble, event) => {
+ const payload = event.payload
+
+ hubble.track &&
+ hubble.track({
+ event: payload.event,
+ attributes: payload.attributes,
+ userId: payload.userId,
+ anonymousId: payload.anonymousId
+ })
+ }
+}
+
+export default action
diff --git a/packages/browser-destinations/destinations/hubble-web/src/types.ts b/packages/browser-destinations/destinations/hubble-web/src/types.ts
new file mode 100644
index 0000000000..5e172e079b
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/src/types.ts
@@ -0,0 +1,10 @@
+export type Methods = {
+ track?: (...args: unknown[]) => unknown
+ identify?: (...args: unknown[]) => unknown
+}
+
+export type Hubble = {
+ id: string
+ initialized: boolean
+ setSource: (source: string) => void
+} & Methods
diff --git a/packages/browser-destinations/destinations/hubble-web/tsconfig.json b/packages/browser-destinations/destinations/hubble-web/tsconfig.json
new file mode 100644
index 0000000000..c2a7897afd
--- /dev/null
+++ b/packages/browser-destinations/destinations/hubble-web/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.build.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "baseUrl": "."
+ },
+ "include": ["src"],
+ "exclude": ["dist", "**/__tests__"]
+}
From 478b9699a2c8e1d464e2dd8b85bc8922db9cfd3f Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 2 Oct 2023 12:46:46 +0100
Subject: [PATCH 002/389] registering hubble
---
packages/destinations-manifest/package.json | 1 +
packages/destinations-manifest/src/index.ts | 1 +
2 files changed, 2 insertions(+)
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index f4333c3d36..0287d14b7a 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -42,6 +42,7 @@
"@segment/analytics-browser-actions-utils": "^1.15.0",
"@segment/analytics-browser-actions-vwo": "^1.16.0",
"@segment/analytics-browser-actions-wiseops": "^1.15.0",
+ "@segment/analytics-browser-hubble-web": "^1.0.0",
"@segment/browser-destination-runtime": "^1.14.0"
}
}
diff --git a/packages/destinations-manifest/src/index.ts b/packages/destinations-manifest/src/index.ts
index c240cde985..648166a148 100644
--- a/packages/destinations-manifest/src/index.ts
+++ b/packages/destinations-manifest/src/index.ts
@@ -59,3 +59,4 @@ register('6501a4325a8a629197cdd691', '@segment/analytics-browser-actions-pendo-w
register('6501a5225aa338d11164cc0f', '@segment/analytics-browser-actions-rupt')
register('650c69e7f47d84b86c120b4c', '@segment/analytics-browser-actions-cdpresolution')
register('649adeaa719bd3f55fe81bef', '@segment/analytics-browser-actions-devrev')
+register('651aac880f2c3b5a8736e0cc', '@segment/analytics-browser-hubble-web')
From a24111e3daef7ac6009b79cfe42357cd389c6325 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 2 Oct 2023 13:33:45 +0100
Subject: [PATCH 003/389] comitting generated typees for hubble
---
.../destinations/hubble-web/src/generated-types.ts | 2 +-
.../destinations/hubble-web/src/identify/generated-types.ts | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts b/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
index d7c0c3af40..eef1f71582 100644
--- a/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
+++ b/packages/browser-destinations/destinations/hubble-web/src/generated-types.ts
@@ -2,7 +2,7 @@
export interface Settings {
/**
- * id
+ * Unique identifier for your team (given in Hubble app)
*/
id: string
}
diff --git a/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts b/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
index 75c2e07c00..a3a0d93825 100644
--- a/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
+++ b/packages/browser-destinations/destinations/hubble-web/src/identify/generated-types.ts
@@ -4,7 +4,7 @@ export interface Payload {
/**
* Unique identifer of the user
*/
- userId: string
+ userId?: string
/**
* Anonymous identifier of the user
*/
From 53f6f8620c3ec4c6943a45e812d081b0bc697032 Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Mon, 2 Oct 2023 10:06:32 -0700
Subject: [PATCH 004/389] [The Trade Desk CRM] Remove old create audience flow
(#1618)
* Remove flagon for createAudience
* Remove unnecesssary fields
* Fix tests
---
.../the-trade-desk-crm/awsClient.ts | 3 -
.../the-trade-desk-crm/functions.ts | 72 +------
.../the-trade-desk-crm/generated-types.ts | 4 +-
.../destinations/the-trade-desk-crm/index.ts | 4 +-
.../the-trade-desk-crm/properties.ts | 20 --
.../syncAudience/__tests__/index.test.ts | 186 +-----------------
.../syncAudience/generated-types.ts | 8 -
.../the-trade-desk-crm/syncAudience/index.ts | 4 +-
8 files changed, 15 insertions(+), 286 deletions(-)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/awsClient.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/awsClient.ts
index d384b633ae..327ab21065 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/awsClient.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/awsClient.ts
@@ -8,7 +8,6 @@ interface SendToAWSRequest {
TDDAuthToken: string
AdvertiserId: string
CrmDataId: string
- SegmentName: string
UsersFormatted: string
DropOptions: {
PiiType: string
@@ -21,7 +20,6 @@ interface SendToAWSRequest {
interface TTDEventPayload {
TDDAuthToken: string
AdvertiserId: string
- SegmentName: string
CrmDataId: string
RequeueCount: number
DropReferenceId?: string
@@ -59,7 +57,6 @@ export const sendEventToAWS = async (request: RequestClient, input: SendToAWSReq
const metadata = JSON.stringify({
TDDAuthToken: input.TDDAuthToken,
AdvertiserId: input.AdvertiserId,
- SegmentName: input.SegmentName,
CrmDataId: input.CrmDataId,
DropOptions: input.DropOptions,
RequeueCount: 0
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
index 9920882637..3877ff1d0c 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
@@ -1,4 +1,4 @@
-import { IntegrationError, RequestClient, ModifiedResponse, PayloadValidationError } from '@segment/actions-core'
+import { RequestClient, ModifiedResponse, PayloadValidationError } from '@segment/actions-core'
import { Settings } from './generated-types'
import { Payload } from './syncAudience/generated-types'
import { createHash } from 'crypto'
@@ -49,12 +49,7 @@ export const TTD_LEGACY_FLOW_FLAG_NAME = 'actions-the-trade-desk-crm-legacy-flow
export const TTD_LIST_ACTION_FLOW_FLAG_NAME = 'ttd-list-action-destination'
export async function processPayload(input: ProcessPayloadInput) {
- let crmID
- if (input?.features?.[TTD_LIST_ACTION_FLOW_FLAG_NAME]) {
- crmID = input?.payloads?.[0]?.external_id || ''
- } else {
- crmID = await getCRMInfo(input.request, input.settings, input.payloads[0])
- }
+ const crmID = input?.payloads?.[0]?.external_id || ''
// Get user emails from the payloads
const usersFormatted = extractUsers(input.payloads)
@@ -86,70 +81,14 @@ export async function processPayload(input: ProcessPayloadInput) {
TDDAuthToken: input.settings.auth_token,
AdvertiserId: input.settings.advertiser_id,
CrmDataId: crmID,
- SegmentName: input.payloads[0].name,
UsersFormatted: usersFormatted,
DropOptions: {
PiiType: input.payloads[0].pii_type,
- MergeMode: 'Replace'
- }
- })
- }
-}
-
-async function getAllDataSegments(request: RequestClient, settings: Settings) {
- const allDataSegments: Segments[] = []
- // initial call to get first page
- let response: ModifiedResponse = await request(
- `${BASE_URL}/crmdata/segment/${settings.advertiser_id}`,
- {
- method: 'GET'
- }
- )
- let segments = response.data.Segments
- // pagingToken leads you to the next page
- let pagingToken = response.data.PagingToken
- // keep iterating through pages until the last empty page
- while (segments.length > 0) {
- allDataSegments.push(...segments)
- response = await request(`${BASE_URL}/crmdata/segment/${settings.advertiser_id}?pagingToken=${pagingToken}`, {
- method: 'GET'
- })
-
- segments = response.data.Segments
- pagingToken = response.data.PagingToken
- }
- return allDataSegments
-}
-
-async function getCRMInfo(request: RequestClient, settings: Settings, payload: Payload): Promise {
- let segmentId: string
- const segments = await getAllDataSegments(request, settings)
- const segmentExists = segments.filter(function (segment) {
- if (segment.SegmentName == payload.name) {
- return segment
- }
- })
-
- // More than 1 audience returned matches name
- if (segmentExists.length > 1) {
- throw new IntegrationError('Multiple audiences found with the same name', 'INVALID_SETTINGS', 400)
- } else if (segmentExists.length == 1) {
- segmentId = segmentExists[0].CrmDataId
- } else {
- // If an audience does not exist, we will create it. In V1, we will send a single batch
- // of full audience syncs every 24 hours to eliminate the risk of a race condition.
- const response: ModifiedResponse = await request(`${BASE_URL}/crmdata/segment`, {
- method: 'POST',
- json: {
- AdvertiserId: settings.advertiser_id,
- SegmentName: payload.name,
- Region: payload.region
+ MergeMode: 'Replace',
+ RetentionEnabled: true
}
})
- segmentId = response.data.CrmDataId
}
-
- return segmentId
}
function extractUsers(payloads: Payload[]): string {
@@ -207,7 +146,8 @@ async function getCRMDataDropEndpoint(request: RequestClient, settings: Settings
method: 'POST',
json: {
PiiType: payload.pii_type,
- MergeMode: 'Replace'
+ MergeMode: 'Replace',
+ RetentionEnabled: true
}
}
)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/generated-types.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/generated-types.ts
index 1154986b2d..f54093708f 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/generated-types.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/generated-types.ts
@@ -22,7 +22,7 @@ export interface Settings {
export interface AudienceSettings {
/**
- * Region of your audience.
+ * The geographical region of the CRM data segment based on the origin of PII. Can be US (United States and Canada), EU (European Union and the UK), or APAC (Asia-Pacific)
*/
- region?: string
+ region: string
}
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
index de6fa665c0..ffaeef132a 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
@@ -74,7 +74,9 @@ const destination: AudienceDestinationDefinition = {
region: {
type: 'string',
label: 'Region',
- description: 'Region of your audience.'
+ description:
+ 'The geographical region of the CRM data segment based on the origin of PII. Can be US (United States and Canada), EU (European Union and the UK), or APAC (Asia-Pacific)',
+ required: true
}
},
audienceConfig: {
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/properties.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/properties.ts
index e802953e5b..0c95332f15 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/properties.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/properties.ts
@@ -10,26 +10,6 @@ export const external_id: InputField = {
unsafe_hidden: true
}
-export const name: InputField = {
- label: 'Segment Name',
- description:
- 'The name of The Trade Desk CRM Data Segment you want to sync. If the audience name does not exist Segment will create one.',
- type: 'string',
- required: true
-}
-
-export const region: InputField = {
- label: 'Region',
- description: 'The geographical region of the CRM data segment based on the origin of PII.',
- type: 'string',
- default: 'US',
- choices: [
- { label: 'US', value: 'US' },
- { label: 'EU', value: 'EU' },
- { label: 'APAC', value: 'APAC' }
- ]
-}
-
export const pii_type: InputField = {
label: 'PII Type',
description: 'The type of personally identifiable data (PII) sent by the advertiser.',
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
index 4095f6fdc0..022d0c7003 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
@@ -86,164 +86,6 @@ const event = createTestEvent({
})
describe('TheTradeDeskCrm.syncAudience', () => {
- it('should succeed and create a Segment if an existing CRM Segment is not found', async () => {
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [{ SegmentName: 'not_test_audience', CrmDataId: 'crm_data_id' }],
- PagingToken: 'paging_token'
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment`)
- .post(/.*/)
- .reply(200, {
- data: {
- CrmDataId: 'test_audience'
- }
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- const responses = await testDestination.testBatchAction('syncAudience', {
- events,
- settings: {
- advertiser_id: 'advertiser_id',
- auth_token: 'test_token',
- __segment_internal_engage_force_full_sync: true,
- __segment_internal_engage_batch_sync: true
- },
- useDefaultMappings: true,
- mapping: {
- name: 'test_audience',
- region: 'US',
- pii_type: 'Email'
- }
- })
-
- expect(responses.length).toBe(5)
- })
-
- it('should succeed and update a Segment with Email if an existing CRM Segment is not found', async () => {
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [{ SegmentName: 'test_audience', CrmDataId: 'crm_data_id' }],
- PagingToken: 'paging_token'
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- const responses = await testDestination.testBatchAction('syncAudience', {
- events,
- settings: {
- advertiser_id: 'advertiser_id',
- auth_token: 'test_token',
- __segment_internal_engage_force_full_sync: true,
- __segment_internal_engage_batch_sync: true
- },
- useDefaultMappings: true,
- mapping: {
- name: 'test_audience',
- region: 'US',
- pii_type: 'Email'
- }
- })
-
- expect(responses.length).toBe(4)
- })
-
- it('should succeed and update a Segment with EmailHashedUnifiedId2 if an existing CRM Segment is not found', async () => {
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [{ SegmentName: 'test_audience', CrmDataId: 'crm_data_id' }],
- PagingToken: 'paging_token'
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- nock(/https?:\/\/([a-z0-9-]+)\.s3\.([a-z0-9-]+)\.amazonaws\.com:.*/)
- .put(/.*/)
- .reply(200)
-
- const responses = await testDestination.testBatchAction('syncAudience', {
- events,
- settings: {
- advertiser_id: 'advertiser_id',
- auth_token: 'test_token',
- __segment_internal_engage_force_full_sync: true,
- __segment_internal_engage_batch_sync: true
- },
- useDefaultMappings: true,
- mapping: {
- name: 'test_audience',
- region: 'US',
- pii_type: 'EmailHashedUnifiedId2'
- }
- })
-
- expect(responses.length).toBe(4)
- })
-
- it('should fail if multiple CRM Segments found with same name', async () => {
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [
- { SegmentName: 'test_audience', CrmDataId: 'crm_data_id' },
- { SegmentName: 'test_audience', CrmDataId: 'crm_data_id' }
- ],
- PagingToken: 'paging_token'
- })
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
- await expect(
- testDestination.testBatchAction('syncAudience', {
- events,
- settings: {
- advertiser_id: 'advertiser_id',
- auth_token: 'test_token',
- __segment_internal_engage_force_full_sync: true,
- __segment_internal_engage_batch_sync: true
- },
- useDefaultMappings: true,
- mapping: {
- name: 'test_audience',
- region: 'US',
- pii_type: 'Email'
- }
- })
- ).rejects.toThrow('Multiple audiences found with the same name')
- })
-
it('should fail if batch has less than 1500 and using legacy flow', async () => {
nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
.get(/.*/)
@@ -279,19 +121,8 @@ describe('TheTradeDeskCrm.syncAudience', () => {
const dropReferenceId = 'aabbcc5b01-c9c7-4000-9191-000000000000'
const dropEndpoint = `https://thetradedesk-crm-data.s3.us-east-1.amazonaws.com/data/advertiser/advertiser-id/drop/${dropReferenceId}/pii?X-Amz-Security-Token=token&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=date&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=credentials&X-Amz-Signature=signature&`
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [{ SegmentName: 'test_audience', CrmDataId: 'crm_data_id' }],
- PagingToken: 'paging_token'
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id/crm_data_id`)
- .post(/.*/, { PiiType: 'Email', MergeMode: 'Replace' })
+ .post(/.*/, { PiiType: 'Email', MergeMode: 'Replace', RetentionEnabled: true })
.reply(200, { ReferenceId: dropReferenceId, Url: dropEndpoint })
nock(dropEndpoint).put(/.*/).reply(200)
@@ -315,26 +146,15 @@ describe('TheTradeDeskCrm.syncAudience', () => {
}
})
- expect(responses.length).toBe(4)
+ expect(responses.length).toBe(2)
})
it('should use external_id from payload', async () => {
const dropReferenceId = 'aabbcc5b01-c9c7-4000-9191-000000000000'
const dropEndpoint = `https://thetradedesk-crm-data.s3.us-east-1.amazonaws.com/data/advertiser/advertiser-id/drop/${dropReferenceId}/pii?X-Amz-Security-Token=token&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=date&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=credentials&X-Amz-Signature=signature&`
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id`)
- .get(/.*/)
- .reply(200, {
- Segments: [{ SegmentName: 'test_audience', CrmDataId: 'crm_data_id' }],
- PagingToken: 'paging_token'
- })
-
- nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id?pagingToken=paging_token`)
- .get(/.*/)
- .reply(200, { Segments: [], PagingToken: null })
-
nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id/personas_test_audience`)
- .post(/.*/, { PiiType: 'Email', MergeMode: 'Replace' })
+ .post(/.*/, { PiiType: 'Email', MergeMode: 'Replace', RetentionEnabled: true })
.reply(200, { ReferenceId: dropReferenceId, Url: dropEndpoint })
nock(dropEndpoint).put(/.*/).reply(200)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/generated-types.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/generated-types.ts
index 616a3b8307..aeaabca519 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/generated-types.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/generated-types.ts
@@ -1,14 +1,6 @@
// Generated file. DO NOT MODIFY IT BY HAND.
export interface Payload {
- /**
- * The name of The Trade Desk CRM Data Segment you want to sync. If the audience name does not exist Segment will create one.
- */
- name: string
- /**
- * The geographical region of the CRM data segment based on the origin of PII.
- */
- region?: string
/**
* The CRM Data ID for The Trade Desk Segment.
*/
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/index.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/index.ts
index 043cb79743..8a76a19a02 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/index.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/index.ts
@@ -1,7 +1,7 @@
import type { ActionDefinition } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
-import { name, region, external_id, pii_type, email, enable_batching, event_name, batch_size } from '../properties'
+import { external_id, pii_type, email, enable_batching, event_name, batch_size } from '../properties'
import { processPayload } from '../functions'
const action: ActionDefinition = {
@@ -9,8 +9,6 @@ const action: ActionDefinition = {
description: 'Drop users into the given CRM Data Segment',
defaultSubscription: 'event = "Audience Entered"',
fields: {
- name: { ...name },
- region: { ...region },
external_id: { ...external_id },
pii_type: { ...pii_type },
email: { ...email },
From af521a0c757325dfce74b32ba7186531756c0e01 Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Mon, 2 Oct 2023 10:54:39 -0700
Subject: [PATCH 005/389] [TikTok Audiences] Remove feature flag (#1624)
* Use different feature flag
* Fix test
* Remove feature flag
---
.../addToAudience/__tests__/index.test.ts | 5 -----
.../tiktok-audiences/addToAudience/index.ts | 11 ++---------
.../destinations/tiktok-audiences/addUser/index.ts | 11 ++---------
.../src/destinations/tiktok-audiences/constants.ts | 2 +-
.../removeFromAudience/__tests__/index.test.ts | 3 ---
.../tiktok-audiences/removeFromAudience/index.ts | 13 ++-----------
.../tiktok-audiences/removeUser/index.ts | 11 ++---------
7 files changed, 9 insertions(+), 47 deletions(-)
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/__tests__/index.test.ts
index faa956c429..503a7e35c0 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/__tests__/index.test.ts
@@ -66,7 +66,6 @@ describe('TiktokAudiences.addToAudience', () => {
const r = await testDestination.testAction('addToAudience', {
auth,
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {},
useDefaultMappings: true,
mapping: {
@@ -96,7 +95,6 @@ describe('TiktokAudiences.addToAudience', () => {
const responses = await testDestination.testAction('addToAudience', {
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
@@ -158,7 +156,6 @@ describe('TiktokAudiences.addToAudience', () => {
const r = await testDestination.testAction('addToAudience', {
event: anotherEvent,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
@@ -176,7 +173,6 @@ describe('TiktokAudiences.addToAudience', () => {
await expect(
testDestination.testAction('addToAudience', {
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
@@ -200,7 +196,6 @@ describe('TiktokAudiences.addToAudience', () => {
await expect(
testDestination.testAction('addToAudience', {
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/index.ts
index 5d21103a25..c387e45d8c 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/addToAudience/index.ts
@@ -12,7 +12,6 @@ import {
external_audience_id
} from '../properties'
import { IntegrationError } from '@segment/actions-core'
-import { MIGRATION_FLAG_NAME } from '../constants'
const action: ActionDefinition = {
title: 'Add to Audience',
@@ -27,10 +26,7 @@ const action: ActionDefinition = {
enable_batching: { ...enable_batching },
external_audience_id: { ...external_audience_id }
},
- perform: async (request, { audienceSettings, payload, statsContext, features }) => {
- if (features && !features[MIGRATION_FLAG_NAME]) {
- return
- }
+ perform: async (request, { audienceSettings, payload, statsContext }) => {
const statsClient = statsContext?.statsClient
const statsTag = statsContext?.tags
@@ -44,10 +40,7 @@ const action: ActionDefinition = {
return processPayload(request, audienceSettings, [payload], 'add')
},
- performBatch: async (request, { payload, audienceSettings, statsContext, features }) => {
- if (features && !features[MIGRATION_FLAG_NAME]) {
- return
- }
+ performBatch: async (request, { payload, audienceSettings, statsContext }) => {
const statsClient = statsContext?.statsClient
const statsTag = statsContext?.tags
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
index e70679454f..195191192a 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
@@ -13,7 +13,6 @@ import {
enable_batching
} from '../properties'
import { TikTokAudiences } from '../api'
-import { MIGRATION_FLAG_NAME } from '../constants'
// NOTE
// This action is not used by the native Segment Audiences feature.
@@ -75,17 +74,11 @@ const action: ActionDefinition = {
}
}
},
- perform: async (request, { settings, payload, statsContext, features }) => {
- if (features && features[MIGRATION_FLAG_NAME]) {
- return
- }
+ perform: async (request, { settings, payload, statsContext }) => {
statsContext?.statsClient?.incr('addUser', 1, statsContext?.tags)
return processPayload(request, settings, [payload], 'add')
},
- performBatch: async (request, { settings, payload, statsContext, features }) => {
- if (features && features[MIGRATION_FLAG_NAME]) {
- return
- }
+ performBatch: async (request, { settings, payload, statsContext }) => {
statsContext?.statsClient?.incr('addUser', 1, statsContext?.tags)
return processPayload(request, settings, payload, 'add')
}
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/constants.ts b/packages/destination-actions/src/destinations/tiktok-audiences/constants.ts
index 856113a564..b510c4855e 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/constants.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/constants.ts
@@ -2,4 +2,4 @@ export const TIKTOK_API_VERSION = 'v1.3'
export const BASE_URL = 'https://business-api.tiktok.com/open_api/'
export const CREATE_AUDIENCE_URL = `${BASE_URL}${TIKTOK_API_VERSION}/segment/audience/`
export const GET_AUDIENCE_URL = `${BASE_URL}${TIKTOK_API_VERSION}/dmp/custom_audience/get`
-export const MIGRATION_FLAG_NAME = 'tiktok-hide-create-audience-action'
+export const MIGRATION_FLAG_NAME = 'actions-migrated-tiktok'
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/__tests__/index.test.ts
index b994b66cb4..d797860d9f 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/__tests__/index.test.ts
@@ -66,7 +66,6 @@ describe('TiktokAudiences.removeFromAudience', () => {
await expect(
testDestination.testAction('removeFromAudience', {
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
@@ -127,7 +126,6 @@ describe('TiktokAudiences.removeFromAudience', () => {
await expect(
testDestination.testAction('removeFromAudience', {
event: anotherEvent,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
@@ -147,7 +145,6 @@ describe('TiktokAudiences.removeFromAudience', () => {
await expect(
testDestination.testAction('removeFromAudience', {
event,
- features: { 'tiktok-hide-create-audience-action': true },
settings: {
advertiser_ids: ['123']
},
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/index.ts
index 54ecd7e9a2..09f6f9ac73 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/removeFromAudience/index.ts
@@ -12,7 +12,6 @@ import {
external_audience_id
} from '../properties'
import { IntegrationError } from '@segment/actions-core'
-import { MIGRATION_FLAG_NAME } from '../constants'
const action: ActionDefinition = {
title: 'Remove from Audience',
@@ -27,11 +26,7 @@ const action: ActionDefinition = {
enable_batching: { ...enable_batching },
external_audience_id: { ...external_audience_id }
},
- perform: async (request, { audienceSettings, payload, statsContext, features }) => {
- if (features && !features[MIGRATION_FLAG_NAME]) {
- return
- }
-
+ perform: async (request, { audienceSettings, payload, statsContext }) => {
const statsClient = statsContext?.statsClient
const statsTag = statsContext?.tags
@@ -42,11 +37,7 @@ const action: ActionDefinition = {
statsClient?.incr('removeFromAudience', 1, statsTag)
return processPayload(request, audienceSettings, [payload], 'delete')
},
- performBatch: async (request, { audienceSettings, payload, statsContext, features }) => {
- if (features && !features[MIGRATION_FLAG_NAME]) {
- return
- }
-
+ performBatch: async (request, { audienceSettings, payload, statsContext }) => {
const statsClient = statsContext?.statsClient
const statsTag = statsContext?.tags
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
index 39e76e9597..2138a8c5d4 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
@@ -13,7 +13,6 @@ import {
enable_batching
} from '../properties'
import { TikTokAudiences } from '../api'
-import { MIGRATION_FLAG_NAME } from '../constants'
// NOTE
// This action is not used by the native Segment Audiences feature.
@@ -74,17 +73,11 @@ const action: ActionDefinition = {
}
}
},
- perform: async (request, { settings, payload, statsContext, features }) => {
- if (features && features[MIGRATION_FLAG_NAME]) {
- return
- }
+ perform: async (request, { settings, payload, statsContext }) => {
statsContext?.statsClient?.incr('removeUser', 1, statsContext?.tags)
return processPayload(request, settings, [payload], 'delete')
},
- performBatch: async (request, { settings, payload, statsContext, features }) => {
- if (features && features[MIGRATION_FLAG_NAME]) {
- return
- }
+ performBatch: async (request, { settings, payload, statsContext }) => {
statsContext?.statsClient?.incr('removeUser', 1, statsContext?.tags)
return processPayload(request, settings, payload, 'delete')
}
From 3c89f00fbb0984a85d60963c572d3d8a16a2863d Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Mon, 2 Oct 2023 11:22:21 -0700
Subject: [PATCH 006/389] [The Trade Desk] Add error message (#1627)
* Add error if external_id not found in payload
* Add test case
* Add preset
* Remove preset:
---
.../the-trade-desk-crm/functions.ts | 7 ++-
.../syncAudience/__tests__/index.test.ts | 52 +++++++++++++++++++
2 files changed, 58 insertions(+), 1 deletion(-)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
index 3877ff1d0c..2be8e4f460 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
@@ -49,7 +49,12 @@ export const TTD_LEGACY_FLOW_FLAG_NAME = 'actions-the-trade-desk-crm-legacy-flow
export const TTD_LIST_ACTION_FLOW_FLAG_NAME = 'ttd-list-action-destination'
export async function processPayload(input: ProcessPayloadInput) {
- const crmID = input?.payloads?.[0]?.external_id || ''
+ let crmID
+ if (!input.payloads[0].external_id) {
+ throw new PayloadValidationError(`No external_id found in payload.`)
+ } else {
+ crmID = input.payloads[0].external_id
+ }
// Get user emails from the payloads
const usersFormatted = extractUsers(input.payloads)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
index 022d0c7003..9763c0c1e2 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
@@ -41,6 +41,9 @@ for (let index = 1; index <= 1500; index++) {
},
traits: {
email: `testing${index}@testing.com`
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
}
}
})
@@ -81,6 +84,9 @@ const event = createTestEvent({
},
traits: {
email: 'testing@testing.com'
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
}
}
})
@@ -178,4 +184,50 @@ describe('TheTradeDeskCrm.syncAudience', () => {
expect(responses.length).toBe(2)
})
+
+ it('should fail if no external_id in payload', async () => {
+ const dropReferenceId = 'aabbcc5b01-c9c7-4000-9191-000000000000'
+ const dropEndpoint = `https://thetradedesk-crm-data.s3.us-east-1.amazonaws.com/data/advertiser/advertiser-id/drop/${dropReferenceId}/pii?X-Amz-Security-Token=token&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=date&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=credentials&X-Amz-Signature=signature&`
+
+ nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id/personas_test_audience`)
+ .post(/.*/, { PiiType: 'Email', MergeMode: 'Replace', RetentionEnabled: true })
+ .reply(200, { ReferenceId: dropReferenceId, Url: dropEndpoint })
+
+ nock(dropEndpoint).put(/.*/).reply(200)
+
+ const newEvent = createTestEvent({
+ event: 'Audience Entered',
+ type: 'track',
+ properties: {
+ audience_key: 'personas_test_audience'
+ },
+ context: {
+ device: {
+ advertisingId: '123'
+ },
+ traits: {
+ email: 'testing@testing.com'
+ }
+ }
+ })
+
+ await expect(
+ testDestination.testAction('syncAudience', {
+ event: newEvent,
+ settings: {
+ advertiser_id: 'advertiser_id',
+ auth_token: 'test_token',
+ __segment_internal_engage_force_full_sync: true,
+ __segment_internal_engage_batch_sync: true
+ },
+ features: { 'actions-the-trade-desk-crm-legacy-flow': true, 'ttd-list-action-destination': true },
+ useDefaultMappings: true,
+ mapping: {
+ name: 'test_audience',
+ region: 'US',
+ pii_type: 'Email'
+ }
+ })
+ ).rejects.toThrow(`No external_id found in payload.`)
+ })
})
From a008da0d280fff0d7de6cb27ff5c2789ad5f816f Mon Sep 17 00:00:00 2001
From: Maryam Sharif
Date: Mon, 2 Oct 2023 11:29:44 -0700
Subject: [PATCH 007/389] Publish
- @segment/action-destinations@3.219.0
- @segment/destinations-manifest@1.22.0
- @segment/analytics-browser-actions-braze-cloud-plugins@1.17.0
- @segment/analytics-browser-actions-braze@1.17.0
- @segment/analytics-browser-hubble-web@1.1.0
---
.../destinations/braze-cloud-plugins/package.json | 4 ++--
.../browser-destinations/destinations/braze/package.json | 2 +-
.../destinations/hubble-web/package.json | 2 +-
packages/destination-actions/package.json | 2 +-
packages/destinations-manifest/package.json | 8 ++++----
5 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
index 84fd76e262..c7360e0af6 100644
--- a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
+++ b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze-cloud-plugins",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/analytics-browser-actions-braze": "^1.16.0",
+ "@segment/analytics-browser-actions-braze": "^1.17.0",
"@segment/browser-destination-runtime": "^1.14.0"
},
"peerDependencies": {
diff --git a/packages/browser-destinations/destinations/braze/package.json b/packages/browser-destinations/destinations/braze/package.json
index 57584cc39a..00a28a8439 100644
--- a/packages/browser-destinations/destinations/braze/package.json
+++ b/packages/browser-destinations/destinations/braze/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/browser-destinations/destinations/hubble-web/package.json b/packages/browser-destinations/destinations/hubble-web/package.json
index 57d02d1556..73641f6d06 100644
--- a/packages/browser-destinations/destinations/hubble-web/package.json
+++ b/packages/browser-destinations/destinations/hubble-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-hubble-web",
- "version": "1.0.0",
+ "version": "1.1.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 39d2b461ec..89d5329e41 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.218.0",
+ "version": "3.219.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index 0287d14b7a..dd22ed0c13 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destinations-manifest",
- "version": "1.21.0",
+ "version": "1.22.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
@@ -14,8 +14,8 @@
"dependencies": {
"@segment/analytics-browser-actions-adobe-target": "^1.15.0",
"@segment/analytics-browser-actions-amplitude-plugins": "^1.15.0",
- "@segment/analytics-browser-actions-braze": "^1.16.0",
- "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.16.0",
+ "@segment/analytics-browser-actions-braze": "^1.17.0",
+ "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.17.0",
"@segment/analytics-browser-actions-cdpresolution": "^1.2.0",
"@segment/analytics-browser-actions-commandbar": "^1.15.0",
"@segment/analytics-browser-actions-devrev": "^1.2.0",
@@ -42,7 +42,7 @@
"@segment/analytics-browser-actions-utils": "^1.15.0",
"@segment/analytics-browser-actions-vwo": "^1.16.0",
"@segment/analytics-browser-actions-wiseops": "^1.15.0",
- "@segment/analytics-browser-hubble-web": "^1.0.0",
+ "@segment/analytics-browser-hubble-web": "^1.1.0",
"@segment/browser-destination-runtime": "^1.14.0"
}
}
From ec2edbdd523a4a27a562692a83f84b2110ff10c1 Mon Sep 17 00:00:00 2001
From: Innovative-GauravKochar
<117165746+Innovative-GauravKochar@users.noreply.github.com>
Date: Tue, 3 Oct 2023 16:14:22 +0530
Subject: [PATCH 008/389] [Strat-3157] | Updated type of num_items from string
to integer (#1620)
* worked on fixing 3157 | Pinterest Conversions API sending integers as strings.
* Handle NAN while parsing
* updated datatype of num_items from string to integer
---------
Co-authored-by: Gaurav Kochar
---
.../pinterest-conversions/pinterest-capi-custom-data.ts | 2 +-
.../__tests__/__snapshots__/index.test.ts.snap | 4 ++--
.../reportConversionEvent/__tests__/index.test.ts | 4 ++++
.../reportConversionEvent/generated-types.ts | 2 +-
4 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/packages/destination-actions/src/destinations/pinterest-conversions/pinterest-capi-custom-data.ts b/packages/destination-actions/src/destinations/pinterest-conversions/pinterest-capi-custom-data.ts
index 260980e804..59ded2fde9 100644
--- a/packages/destination-actions/src/destinations/pinterest-conversions/pinterest-capi-custom-data.ts
+++ b/packages/destination-actions/src/destinations/pinterest-conversions/pinterest-capi-custom-data.ts
@@ -48,7 +48,7 @@ export const custom_data_field: InputField = {
num_items: {
label: 'Number of Items',
description: 'Total number of products in the event. ',
- type: 'string'
+ type: 'integer'
},
order_id: {
label: 'Order ID',
diff --git a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/__snapshots__/index.test.ts.snap b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/__snapshots__/index.test.ts.snap
index 78707fd8a5..fa3dca3bef 100644
--- a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/__snapshots__/index.test.ts.snap
+++ b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/__snapshots__/index.test.ts.snap
@@ -12,11 +12,11 @@ Object {
"content_ids": undefined,
"contents": undefined,
"currency": undefined,
- "num_items": undefined,
+ "num_items": 2,
"opt_out_type": undefined,
"order_id": undefined,
"search_string": undefined,
- "value": "undefined",
+ "value": "2000",
},
"device_brand": undefined,
"device_carrier": undefined,
diff --git a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/index.test.ts
index 0796e29183..7487051e98 100644
--- a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/__tests__/index.test.ts
@@ -111,6 +111,10 @@ describe('PinterestConversionApi', () => {
client_user_agent: '5.5.5.5',
client_ip_address:
'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
+ },
+ custom_data: {
+ num_items: '2',
+ value: 2000
}
}
})
diff --git a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/generated-types.ts b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/generated-types.ts
index bfc6dc06a6..605e89d920 100644
--- a/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/generated-types.ts
+++ b/packages/destination-actions/src/destinations/pinterest-conversions/reportConversionEvent/generated-types.ts
@@ -122,7 +122,7 @@ export interface Payload {
/**
* Total number of products in the event.
*/
- num_items?: string
+ num_items?: number
/**
* Order ID
*/
From 08e75eff0e68f652b39f50da180b100d14472f2d Mon Sep 17 00:00:00 2001
From: Matt Grosvenor <101577834+mattgrosvenor-fs@users.noreply.github.com>
Date: Tue, 3 Oct 2023 06:47:18 -0400
Subject: [PATCH 009/389] Segment Actions Improvements (#23) (#1550)
* Make userId and uid not required
* Change path from v2beta to v2
* Remove integrationSrc query param for v2 routes
* change testAuthentication to use /me endpoint
---
.../fullstory/__tests__/fullstory.test.ts | 10 ++++-----
.../__tests__/request-params.test.ts | 22 +++++++++----------
.../identifyUserV2/generated-types.ts | 2 +-
.../fullstory/identifyUserV2/index.ts | 2 +-
.../src/destinations/fullstory/index.ts | 4 ++--
.../destinations/fullstory/request-params.ts | 13 +++++------
.../fullstory/trackEventV2/generated-types.ts | 2 +-
.../fullstory/trackEventV2/index.ts | 2 +-
8 files changed, 28 insertions(+), 29 deletions(-)
diff --git a/packages/destination-actions/src/destinations/fullstory/__tests__/fullstory.test.ts b/packages/destination-actions/src/destinations/fullstory/__tests__/fullstory.test.ts
index db7b0e8ba7..c8973200fb 100644
--- a/packages/destination-actions/src/destinations/fullstory/__tests__/fullstory.test.ts
+++ b/packages/destination-actions/src/destinations/fullstory/__tests__/fullstory.test.ts
@@ -18,7 +18,7 @@ const testDestination = createTestIntegration(Definition)
describe('FullStory', () => {
describe('testAuthentication', () => {
it('makes expected request', async () => {
- nock(baseUrl).get('/operations/v1?limit=1').reply(200)
+ nock(baseUrl).get('/me').reply(200)
await expect(testDestination.testAuthentication(settings)).resolves.not.toThrowError()
})
})
@@ -156,7 +156,7 @@ describe('FullStory', () => {
describe('onDelete', () => {
const falsyUserIds = ['', undefined, null]
it('makes expected request given a valid user id', async () => {
- nock(baseUrl).delete(`/v2beta/users?uid=${urlEncodedUserId}`).reply(200)
+ nock(baseUrl).delete(`/v2/users?uid=${urlEncodedUserId}`).reply(200)
await expect(testDestination.onDelete!({ type: 'delete', userId }, settings)).resolves.not.toThrowError()
})
@@ -171,7 +171,7 @@ describe('FullStory', () => {
describe('identifyUserV2', () => {
it('makes expected request with default mappings', async () => {
- nock(baseUrl).post(`/v2beta/users?${integrationSourceQueryParam}`).reply(200)
+ nock(baseUrl).post(`/v2/users`).reply(200)
const event = createTestEvent({
type: 'identify',
userId,
@@ -212,7 +212,7 @@ describe('FullStory', () => {
describe('trackEventV2', () => {
it('makes expected request with default mappings', async () => {
- nock(baseUrl).post(`/v2beta/events?${integrationSourceQueryParam}`).reply(200)
+ nock(baseUrl).post(`/v2/events`).reply(200)
const eventName = 'test-event'
const sessionId = '12345:678'
@@ -272,7 +272,7 @@ describe('FullStory', () => {
})
it('handles undefined event values', async () => {
- nock(baseUrl).post(`/v2beta/events?${integrationSourceQueryParam}`).reply(200)
+ nock(baseUrl).post(`/v2/events`).reply(200)
const eventName = 'test-event'
const event = createTestEvent({
diff --git a/packages/destination-actions/src/destinations/fullstory/__tests__/request-params.test.ts b/packages/destination-actions/src/destinations/fullstory/__tests__/request-params.test.ts
index c31b764324..7934d3a0a1 100644
--- a/packages/destination-actions/src/destinations/fullstory/__tests__/request-params.test.ts
+++ b/packages/destination-actions/src/destinations/fullstory/__tests__/request-params.test.ts
@@ -1,10 +1,10 @@
import {
- listOperationsRequestParams,
customEventRequestParams,
setUserPropertiesRequestParams,
deleteUserRequestParams,
createUserRequestParams,
- createEventRequestParams
+ createEventRequestParams,
+ meRequestParams
} from '../request-params'
import {
anonymousId,
@@ -19,14 +19,14 @@ import {
} from './fullstory.test'
describe('requestParams', () => {
- describe('listOperations', () => {
- it(`returns expected request params`, () => {
- const { url, options } = listOperationsRequestParams(settings)
+ describe('me', () => {
+ it('returns expected request params', () => {
+ const { url, options } = meRequestParams(settings)
expect(options.method).toBe('get')
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/operations/v1?limit=1`)
+ expect(url).toBe(`${baseUrl}/me`)
})
})
@@ -129,7 +129,7 @@ describe('requestParams', () => {
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/v2beta/users?uid=${urlEncodedUserId}`)
+ expect(url).toBe(`${baseUrl}/v2/users?uid=${urlEncodedUserId}`)
})
})
@@ -148,7 +148,7 @@ describe('requestParams', () => {
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/v2beta/users?${integrationSourceQueryParam}`)
+ expect(url).toBe(`${baseUrl}/v2/users`)
expect(options.json).toEqual(requestBody)
})
})
@@ -173,7 +173,7 @@ describe('requestParams', () => {
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/v2beta/events?${integrationSourceQueryParam}`)
+ expect(url).toBe(`${baseUrl}/v2/events`)
expect(options.json).toEqual({
name: requestValues.eventName,
properties: requestValues.properties,
@@ -199,7 +199,7 @@ describe('requestParams', () => {
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/v2beta/events?${integrationSourceQueryParam}`)
+ expect(url).toBe(`${baseUrl}/v2/events`)
expect(options.json).toEqual({
name: requestValues.eventName,
properties: requestValues.properties,
@@ -221,7 +221,7 @@ describe('requestParams', () => {
expect(options.headers!['Content-Type']).toBe('application/json')
expect(options.headers!['Authorization']).toBe(`Basic ${settings.apiKey}`)
expect(options.headers!['Integration-Source']).toBe(integrationSource)
- expect(url).toBe(`${baseUrl}/v2beta/events?${integrationSourceQueryParam}`)
+ expect(url).toBe(`${baseUrl}/v2/events`)
expect(options.json).toEqual({
name: requestValues.eventName,
properties: requestValues.properties,
diff --git a/packages/destination-actions/src/destinations/fullstory/identifyUserV2/generated-types.ts b/packages/destination-actions/src/destinations/fullstory/identifyUserV2/generated-types.ts
index 252edef00e..91e54b9a67 100644
--- a/packages/destination-actions/src/destinations/fullstory/identifyUserV2/generated-types.ts
+++ b/packages/destination-actions/src/destinations/fullstory/identifyUserV2/generated-types.ts
@@ -4,7 +4,7 @@ export interface Payload {
/**
* The user's id
*/
- uid: string
+ uid?: string
/**
* The user's anonymous id
*/
diff --git a/packages/destination-actions/src/destinations/fullstory/identifyUserV2/index.ts b/packages/destination-actions/src/destinations/fullstory/identifyUserV2/index.ts
index 6835d869ce..4cc2c29fd6 100644
--- a/packages/destination-actions/src/destinations/fullstory/identifyUserV2/index.ts
+++ b/packages/destination-actions/src/destinations/fullstory/identifyUserV2/index.ts
@@ -11,7 +11,7 @@ const action: ActionDefinition = {
fields: {
uid: {
type: 'string',
- required: true,
+ required: false,
description: "The user's id",
label: 'User ID',
default: {
diff --git a/packages/destination-actions/src/destinations/fullstory/index.ts b/packages/destination-actions/src/destinations/fullstory/index.ts
index 292c90a0f4..be63e50ef6 100644
--- a/packages/destination-actions/src/destinations/fullstory/index.ts
+++ b/packages/destination-actions/src/destinations/fullstory/index.ts
@@ -5,7 +5,7 @@ import identifyUser from './identifyUser'
import trackEvent from './trackEvent'
import identifyUserV2 from './identifyUserV2'
import trackEventV2 from './trackEventV2'
-import { listOperationsRequestParams, deleteUserRequestParams } from './request-params'
+import { deleteUserRequestParams, meRequestParams } from './request-params'
const destination: DestinationDefinition = {
name: 'Fullstory Cloud Mode (Actions)',
@@ -39,7 +39,7 @@ const destination: DestinationDefinition = {
},
testAuthentication: (request, { settings }) => {
- const { url, options } = listOperationsRequestParams(settings)
+ const { url, options } = meRequestParams(settings)
return request(url, options)
}
},
diff --git a/packages/destination-actions/src/destinations/fullstory/request-params.ts b/packages/destination-actions/src/destinations/fullstory/request-params.ts
index 77068bb06f..16ace53c6f 100644
--- a/packages/destination-actions/src/destinations/fullstory/request-params.ts
+++ b/packages/destination-actions/src/destinations/fullstory/request-params.ts
@@ -34,12 +34,11 @@ const defaultRequestParams = (settings: Settings, relativeUrl: string): RequestP
}
/**
- * Returns {@link RequestParams} for the list operations HTTP API endpoint.
+ * Returns {@link RequestParams} for the me HTTP API endpoint.
*
* @param settings Settings configured for the cloud mode destination.
*/
-export const listOperationsRequestParams = (settings: Settings): RequestParams =>
- defaultRequestParams(settings, `operations/v1?limit=1`)
+export const meRequestParams = (settings: Settings): RequestParams => defaultRequestParams(settings, 'me')
/**
* Returns {@link RequestParams} for the V1 custom events HTTP API endpoint.
@@ -130,7 +129,7 @@ export const setUserPropertiesRequestParams = (
* @param userId The id of the user to delete.
*/
export const deleteUserRequestParams = (settings: Settings, userId: string): RequestParams => {
- const defaultParams = defaultRequestParams(settings, `v2beta/users?uid=${encodeURIComponent(userId)}`)
+ const defaultParams = defaultRequestParams(settings, `v2/users?uid=${encodeURIComponent(userId)}`)
return {
...defaultParams,
@@ -148,7 +147,7 @@ export const deleteUserRequestParams = (settings: Settings, userId: string): Req
* @param requestBody The request body containing user properties to set.
*/
export const createUserRequestParams = (settings: Settings, requestBody: Object): RequestParams => {
- const defaultParams = defaultRequestParams(settings, `v2beta/users?${integrationSourceQueryParam}`)
+ const defaultParams = defaultRequestParams(settings, `v2/users`)
return {
...defaultParams,
@@ -169,7 +168,7 @@ export const createUserRequestParams = (settings: Settings, requestBody: Object)
export const createEventRequestParams = (
settings: Settings,
requestValues: {
- userId: string
+ userId?: string
eventName: string
properties: {}
timestamp?: string
@@ -178,7 +177,7 @@ export const createEventRequestParams = (
}
): RequestParams => {
const { userId, eventName, properties: eventData, timestamp, useRecentSession, sessionUrl } = requestValues
- const defaultParams = defaultRequestParams(settings, `v2beta/events?${integrationSourceQueryParam}`)
+ const defaultParams = defaultRequestParams(settings, `v2/events`)
const requestBody: Record = {
name: eventName,
diff --git a/packages/destination-actions/src/destinations/fullstory/trackEventV2/generated-types.ts b/packages/destination-actions/src/destinations/fullstory/trackEventV2/generated-types.ts
index 672565984c..ae950d0713 100644
--- a/packages/destination-actions/src/destinations/fullstory/trackEventV2/generated-types.ts
+++ b/packages/destination-actions/src/destinations/fullstory/trackEventV2/generated-types.ts
@@ -4,7 +4,7 @@ export interface Payload {
/**
* The user's id
*/
- userId: string
+ userId?: string
/**
* The name of the event.
*/
diff --git a/packages/destination-actions/src/destinations/fullstory/trackEventV2/index.ts b/packages/destination-actions/src/destinations/fullstory/trackEventV2/index.ts
index 2ae7b95c77..dbfc02bb12 100644
--- a/packages/destination-actions/src/destinations/fullstory/trackEventV2/index.ts
+++ b/packages/destination-actions/src/destinations/fullstory/trackEventV2/index.ts
@@ -13,7 +13,7 @@ const action: ActionDefinition = {
fields: {
userId: {
type: 'string',
- required: true,
+ required: false,
description: "The user's id",
label: 'User ID',
default: {
From dc0f000daf1de80f302a0912b0bc7bacbcdc36fa Mon Sep 17 00:00:00 2001
From: zhadier39 <113626827+zhadier39@users.noreply.github.com>
Date: Tue, 3 Oct 2023 17:48:57 +0500
Subject: [PATCH 010/389] [Hyperengage] Destination (#1621)
* Add unit and integration tests
* Updated field descriptions for group, identify and track
* Updated common fields
* Fix identify function error
* Added authentication endpoint
* Revise tests to enable auth
* Update default paths for groupId.
* Implement recommended changes from PR #1621
* Add url field
* Resolve pathing issues and add tests/checks for first and last name fields
* Resolve test issues, payload validation error, and correct context default
---------
Co-authored-by: saadhypng
Co-authored-by: Saad Ali <88059697+saadhypng@users.noreply.github.com>
---
.../hyperengage/__tests__/hyperengage.test.ts | 30 +++
.../__tests__/validateInput.test.ts | 93 ++++++++
.../destinations/hyperengage/commonFields.ts | 164 ++++++++++++++
.../hyperengage/generated-types.ts | 12 +
.../hyperengage/group/__tests__/index.test.ts | 106 +++++++++
.../hyperengage/group/generated-types.ts | 124 ++++++++++
.../destinations/hyperengage/group/index.ts | 84 +++++++
.../identify/__tests__/index.test.ts | 211 ++++++++++++++++++
.../hyperengage/identify/generated-types.ts | 128 +++++++++++
.../hyperengage/identify/index.ts | 113 ++++++++++
.../src/destinations/hyperengage/index.ts | 72 ++++++
.../hyperengage/track/__tests__/index.test.ts | 93 ++++++++
.../hyperengage/track/generated-types.ts | 112 ++++++++++
.../destinations/hyperengage/track/index.ts | 56 +++++
.../destinations/hyperengage/validateInput.ts | 105 +++++++++
.../audienceEnteredSFTP.types.ts | 48 ++++
16 files changed, 1551 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/commonFields.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/group/index.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/identify/index.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/index.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/track/index.ts
create mode 100644 packages/destination-actions/src/destinations/hyperengage/validateInput.ts
create mode 100644 packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts
new file mode 100644
index 0000000000..582fc8e332
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/hyperengage.test.ts
@@ -0,0 +1,30 @@
+import { createTestIntegration } from '@segment/actions-core'
+import Definition from '../index'
+import nock from 'nock'
+
+export const apiKey = 'testApiKey'
+export const workspaceIdentifier = 'testApiIdentifier'
+
+const testDestination = createTestIntegration(Definition)
+beforeAll(() => {
+ nock.disableNetConnect()
+})
+
+afterAll(() => {
+ nock.enableNetConnect()
+ nock.cleanAll()
+})
+
+describe('Hyperengage', () => {
+ describe('testAuthentication', () => {
+ test('should validate workspaceIdentifier and apiKey', async () => {
+ nock('https://api.hyperengage.io/api/v1/verify_api_key')
+ .post(/.*/, {
+ api_key: apiKey,
+ workspace_identifier: workspaceIdentifier
+ })
+ .reply(200, { message: 'Mocked response' })
+ await expect(testDestination.testAuthentication({ apiKey, workspaceIdentifier })).resolves.not.toThrowError()
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts
new file mode 100644
index 0000000000..1298d085b1
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/__tests__/validateInput.test.ts
@@ -0,0 +1,93 @@
+import { validateInput } from '../validateInput'
+
+const fakeTrackData = {
+ event_id: 'test-message-cz380xxe9kn',
+ page_title: 'Title',
+ event_name: 'test',
+ event_type: 'track',
+ properties: {
+ required: 'false'
+ },
+ timestamp: '2023-09-11T08:06:11.192Z',
+ user_id: 'test',
+ account_id: 'testAccount'
+}
+
+const fakeIdentifyData = {
+ event_id: 'test-message-cz380xxe9kn',
+ page_title: 'Title',
+ event_name: 'test',
+ event_type: 'identify',
+ name: 'testUser',
+ email: 'testEmail',
+ traits: {
+ required: 'false'
+ },
+ timestamp: '2023-09-11T08:06:11.192Z',
+ user_id: 'test',
+ account_id: 'testAccount'
+}
+
+const fakeGroupData = {
+ event_id: 'test-message-cz380xxe9kn',
+ page_title: 'Title',
+ event_name: 'test',
+ event_type: 'group',
+ name: 'Test account',
+ plan: 'temporary',
+ industry: 'test industry',
+ website: 'test website',
+ traits: {
+ required: 'false'
+ },
+ timestamp: '2023-09-11T08:06:11.192Z',
+ user_id: 'test',
+ account_id: 'testAccount'
+}
+
+const settings = {
+ workspaceIdentifier: 'testWorkspaceId',
+ apiKey: 'testApiKey'
+}
+
+describe('validateInput', () => {
+ describe('test common payload', () => {
+ it('should return converted payload', () => {
+ const payload = validateInput(settings, fakeIdentifyData, 'user_identify')
+ expect(payload.api_key).toBe(settings.apiKey)
+ expect(payload.workspace_key).toBe(settings.workspaceIdentifier)
+ expect(payload.doc_encoding).toBe('UTF-8')
+ expect(payload.src).toBe('segment_api')
+ })
+ })
+
+ describe('test identify payload', () => {
+ it('should return converted payload', async () => {
+ const payload = validateInput(settings, fakeIdentifyData, 'user_identify')
+ expect(payload.user_id).toEqual(fakeIdentifyData.user_id)
+ expect(payload.traits.email).toEqual(fakeIdentifyData.email)
+ expect(payload.traits.name).toEqual(fakeIdentifyData.name)
+ expect(payload.traits).toHaveProperty('required')
+ })
+ })
+
+ describe('test group payload', () => {
+ it('should return converted payload', async () => {
+ const payload = validateInput(settings, fakeGroupData, 'account_identify')
+ expect(payload.account_id).toEqual(fakeGroupData.account_id)
+ expect(payload.traits.plan_name).toEqual(fakeGroupData.plan)
+ expect(payload.traits.industry).toEqual(fakeGroupData.industry)
+ expect(payload.traits.website).toEqual(fakeGroupData.website)
+ expect(payload.traits).toHaveProperty('required')
+ })
+ })
+
+ describe('test track payload', () => {
+ it('should return converted payload', async () => {
+ let payload = validateInput(settings, fakeGroupData, 'account_identify')
+ expect(payload.event_type).toEqual('account_identify')
+ payload = validateInput(settings, fakeTrackData, 'track')
+ expect(payload.event_type).toEqual('test')
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/hyperengage/commonFields.ts b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts
new file mode 100644
index 0000000000..60a4ecce9b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/commonFields.ts
@@ -0,0 +1,164 @@
+import { ActionDefinition } from '@segment/actions-core'
+import { Settings } from '../encharge/generated-types'
+
+export const commonFields: ActionDefinition['fields'] = {
+ anonymous_id: {
+ type: 'string',
+ allowNull: true,
+ required: false,
+ description: 'User Anonymous id',
+ label: 'Anonymous ID',
+ default: { '@path': '$.anonymousId' }
+ },
+ event_id: {
+ type: 'string',
+ required: false,
+ description: 'The ID of the event.',
+ label: 'Event ID',
+ default: { '@path': '$.messageId' }
+ },
+ doc_path: {
+ type: 'string',
+ required: false,
+ description: 'The path of the document.',
+ label: 'Document Path',
+ default: { '@path': '$.context.page.path' }
+ },
+ doc_search: {
+ type: 'string',
+ required: false,
+ description: 'The search query of the document.',
+ label: 'Document Search',
+ default: { '@path': '$.context.page.search' }
+ },
+ doc_title: {
+ type: 'string',
+ required: false,
+ description: 'The title of the page where the event occurred.',
+ label: 'Page Title',
+ default: { '@path': '$.context.page.title' }
+ },
+ url: {
+ type: 'string',
+ required: false,
+ description: 'The URL of the page where the event occurred.',
+ label: 'URL',
+ default: { '@path': '$.context.page.url' }
+ },
+ referer: {
+ type: 'string',
+ required: false,
+ description: 'The referrer of the page where the event occurred.',
+ label: 'Referrer',
+ default: { '@path': '$.context.page.referrer' }
+ },
+ user_agent: {
+ type: 'string',
+ required: false,
+ description: 'The user agent of the browser.',
+ label: 'User Agent',
+ default: { '@path': '$.context.userAgent' }
+ },
+ user_language: {
+ type: 'string',
+ required: false,
+ description: 'The language of the browser.',
+ label: 'User Language',
+ default: { '@path': '$.context.locale' }
+ },
+ utc_time: {
+ type: 'string',
+ required: false,
+ description: 'The time of the event in UTC.',
+ label: 'UTC Time',
+ default: { '@path': '$.timestamp' }
+ },
+ utm: {
+ type: 'object',
+ required: false,
+ description: 'Information about the UTM parameters.',
+ label: 'UTM',
+ properties: {
+ source: {
+ label: 'Source',
+ description: 'The source of the campaign.',
+ type: 'string'
+ },
+ medium: {
+ label: 'Medium',
+ description: 'The medium of the campaign.',
+ type: 'string'
+ },
+ name: {
+ label: 'Name',
+ description: 'The name of the campaign.',
+ type: 'string'
+ },
+ term: {
+ label: 'Term',
+ description: 'The term of the campaign.',
+ type: 'string'
+ },
+ content: {
+ label: 'Content',
+ description: 'The content of the campaign.',
+ type: 'string'
+ }
+ },
+ default: {
+ source: { '@path': '$.context.campaign.source' },
+ medium: { '@path': '$.context.campaign.medium' },
+ name: { '@path': '$.context.campaign.name' },
+ term: { '@path': '$.context.campaign.term' },
+ content: { '@path': '$.context.campaign.content' }
+ }
+ },
+ screen: {
+ type: 'object',
+ required: false,
+ description: 'Information about the screen.',
+ label: 'Screen',
+ properties: {
+ height: {
+ label: 'Height',
+ description: 'The height of the screen.',
+ type: 'integer'
+ },
+ width: {
+ label: 'Width',
+ description: 'The width of the screen.',
+ type: 'integer'
+ },
+ density: {
+ label: 'Density',
+ description: 'The density of the screen.',
+ type: 'number'
+ }
+ },
+ default: {
+ height: { '@path': '$.context.screen.height' },
+ width: { '@path': '$.context.screen.width' },
+ density: { '@path': '$.context.screen.density' }
+ }
+ },
+ timezone: {
+ type: 'string',
+ required: false,
+ description: 'The timezone of the browser.',
+ label: 'Timezone',
+ default: {
+ '@if': {
+ exists: { '@path': '$.context.timezone' },
+ then: { '@path': '$.context.timezone' },
+ else: { '@path': '$.properties.timezone' }
+ }
+ }
+ },
+ source_ip: {
+ type: 'string',
+ required: false,
+ description: 'The IP address of the user.',
+ label: 'IP Address',
+ default: { '@path': '$.context.ip' }
+ }
+}
diff --git a/packages/destination-actions/src/destinations/hyperengage/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/generated-types.ts
new file mode 100644
index 0000000000..660b447668
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/generated-types.ts
@@ -0,0 +1,12 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Your Hyperengage API key located in the Integration Settings page.
+ */
+ apiKey: string
+ /**
+ * Your Hyperengage workspace identifier located in the Integration Settings page.
+ */
+ workspaceIdentifier: string
+}
diff --git a/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts
new file mode 100644
index 0000000000..ce30720874
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/group/__tests__/index.test.ts
@@ -0,0 +1,106 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+beforeAll(() => {
+ nock.disableNetConnect()
+})
+
+afterAll(() => {
+ nock.enableNetConnect()
+ nock.cleanAll()
+})
+
+const heGroupMapping = {
+ account_id: {
+ '@path': '$.groupId'
+ },
+ name: {
+ '@if': {
+ exists: { '@path': '$.traits.name' },
+ then: { '@path': '$.traits.name' },
+ else: { '@path': '$.properties.name' }
+ }
+ },
+ created_at: {
+ '@path': '$.traits.created_at'
+ },
+ traits: {
+ '@path': '$.traits'
+ },
+ plan: {
+ '@path': '$.traits.plan'
+ },
+ industry: {
+ '@path': '$.traits.industry'
+ },
+ website: {
+ '@path': '$.traits.website'
+ }
+}
+
+describe('Hyperengage.group', () => {
+ test('Should throw an error if `account_id or` `name` is not defined', async () => {
+ const event = createTestEvent({
+ type: 'group',
+ traits: {
+ email: 'test@company.com'
+ },
+ groupId: 'test@test.com'
+ })
+
+ await expect(
+ testDestination.testAction('group', {
+ event,
+ mapping: heGroupMapping
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => {
+ const event = createTestEvent({
+ type: 'group',
+ traits: {
+ name: 'test'
+ },
+ groupId: '123456'
+ })
+
+ await expect(
+ testDestination.testAction('group', {
+ event,
+ mapping: heGroupMapping,
+ settings: {
+ workspaceIdentifier: '',
+ apiKey: ''
+ }
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should send an group event to Hyperengage', async () => {
+ // Mock: Segment group Call
+ nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true })
+
+ const event = createTestEvent({
+ type: 'group',
+ traits: {
+ name: 'test'
+ },
+ groupId: '123456'
+ })
+
+ const responses = await testDestination.testAction('group', {
+ event,
+ mapping: heGroupMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+
+ expect(responses[0].status).toEqual(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts
new file mode 100644
index 0000000000..2529094d87
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/group/generated-types.ts
@@ -0,0 +1,124 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The External ID of the account to send properties for
+ */
+ account_id: string
+ /**
+ * The Account name
+ */
+ name: string
+ /**
+ * The timestamp when the account was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".
+ */
+ created_at?: string
+ /**
+ * The properties of the account
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+ /**
+ * Subscription plan the account is associated with
+ */
+ plan?: string
+ /**
+ * The account industry
+ */
+ industry?: string
+ /**
+ * The account website
+ */
+ website?: string
+ /**
+ * User Anonymous id
+ */
+ anonymous_id?: string | null
+ /**
+ * The ID of the event.
+ */
+ event_id?: string
+ /**
+ * The path of the document.
+ */
+ doc_path?: string
+ /**
+ * The search query of the document.
+ */
+ doc_search?: string
+ /**
+ * The title of the page where the event occurred.
+ */
+ doc_title?: string
+ /**
+ * The URL of the page where the event occurred.
+ */
+ url?: string
+ /**
+ * The referrer of the page where the event occurred.
+ */
+ referer?: string
+ /**
+ * The user agent of the browser.
+ */
+ user_agent?: string
+ /**
+ * The language of the browser.
+ */
+ user_language?: string
+ /**
+ * The time of the event in UTC.
+ */
+ utc_time?: string
+ /**
+ * Information about the UTM parameters.
+ */
+ utm?: {
+ /**
+ * The source of the campaign.
+ */
+ source?: string
+ /**
+ * The medium of the campaign.
+ */
+ medium?: string
+ /**
+ * The name of the campaign.
+ */
+ name?: string
+ /**
+ * The term of the campaign.
+ */
+ term?: string
+ /**
+ * The content of the campaign.
+ */
+ content?: string
+ }
+ /**
+ * Information about the screen.
+ */
+ screen?: {
+ /**
+ * The height of the screen.
+ */
+ height?: number
+ /**
+ * The width of the screen.
+ */
+ width?: number
+ /**
+ * The density of the screen.
+ */
+ density?: number
+ }
+ /**
+ * The timezone of the browser.
+ */
+ timezone?: string
+ /**
+ * The IP address of the user.
+ */
+ source_ip?: string
+}
diff --git a/packages/destination-actions/src/destinations/hyperengage/group/index.ts b/packages/destination-actions/src/destinations/hyperengage/group/index.ts
new file mode 100644
index 0000000000..26ae905724
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/group/index.ts
@@ -0,0 +1,84 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { validateInput } from '../validateInput'
+import { commonFields } from '../commonFields'
+
+const action: ActionDefinition = {
+ title: 'Group',
+ description: 'Send group calls to Hyperengage.',
+ defaultSubscription: 'type = "group"',
+ fields: {
+ account_id: {
+ type: 'string',
+ required: true,
+ description: 'The External ID of the account to send properties for',
+ label: 'Account id',
+ default: {
+ '@if': {
+ exists: { '@path': '$.context.group_id' },
+ then: { '@path': '$.context.group_id' },
+ else: { '@path': '$.groupId' }
+ }
+ }
+ },
+ name: {
+ type: 'string',
+ required: true,
+ description: 'The Account name',
+ label: 'Account name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.name' },
+ then: { '@path': '$.traits.name' },
+ else: { '@path': '$.properties.name' }
+ }
+ }
+ },
+ created_at: {
+ type: 'string',
+ required: false,
+ description:
+ 'The timestamp when the account was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".',
+ label: 'Account created at',
+ default: { '@path': '$.traits.created_at' }
+ },
+ traits: {
+ type: 'object',
+ required: false,
+ description: 'The properties of the account',
+ label: 'Account properties',
+ default: { '@path': '$.traits' }
+ },
+ plan: {
+ type: 'string',
+ required: false,
+ description: 'Subscription plan the account is associated with',
+ label: 'Account subscription plan',
+ default: { '@path': '$.traits.plan' }
+ },
+ industry: {
+ type: 'string',
+ required: false,
+ description: 'The account industry',
+ label: 'Account industry',
+ default: { '@path': '$.traits.industry' }
+ },
+ website: {
+ type: 'string',
+ required: false,
+ description: 'The account website',
+ label: 'Account website',
+ default: { '@path': '$.traits.website' }
+ },
+ ...commonFields
+ },
+ perform: (request, data) => {
+ return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, {
+ method: 'post',
+ json: validateInput(data.settings, data.payload, 'account_identify')
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts
new file mode 100644
index 0000000000..136cdd94a0
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/identify/__tests__/index.test.ts
@@ -0,0 +1,211 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+beforeAll(() => {
+ nock.disableNetConnect()
+})
+
+afterAll(() => {
+ nock.enableNetConnect()
+ nock.cleanAll()
+})
+
+const heIdentifyMapping = {
+ user_id: {
+ '@path': '$.userId'
+ },
+ name: {
+ '@if': {
+ exists: { '@path': '$.traits.name' },
+ then: { '@path': '$.traits.name' },
+ else: { '@path': '$.properties.name' }
+ }
+ },
+ first_name: {
+ '@if': {
+ exists: { '@path': '$.traits.first_name' },
+ then: { '@path': '$.traits.first_name' },
+ else: { '@path': '$.properties.first_name' }
+ }
+ },
+ last_name: {
+ '@if': {
+ exists: { '@path': '$.traits.last_name' },
+ then: { '@path': '$.traits.last_name' },
+ else: { '@path': '$.properties.last_name' }
+ }
+ },
+ email: {
+ '@if': {
+ exists: { '@path': '$.traits.email' },
+ then: { '@path': '$.traits.email' },
+ else: { '@path': '$.properties.email' }
+ }
+ },
+ created_at: {
+ '@path': '$.traits.created_at'
+ },
+ traits: {
+ '@path': '$.traits'
+ }
+}
+
+describe('Hyperengage.identify', () => {
+ test('Should throw an error if `user_id` is not defined', async () => {
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ name: 'test',
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should throw an error if both `name` and `first_name` & `last_name` are not defined', async () => {
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ },
+ userId: '123456'
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should not throw error if name is defined and first and last name are not', async () => {
+ nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true })
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ name: 'test',
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ },
+ userId: '123456'
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+ ).resolves.not.toThrowError()
+ })
+
+ test('Should not throw error if first_name and last_name are defined and name is not', async () => {
+ nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true })
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ first_name: 'test',
+ last_name: 'test',
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ },
+ userId: '123456'
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+ ).resolves.not.toThrowError()
+ })
+
+ test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => {
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ name: 'test',
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ },
+ userId: '123456'
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ settings: {
+ workspaceIdentifier: '',
+ apiKey: ''
+ }
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should send an identify event to Hyperengage', async () => {
+ // Mock: Segment Identify Call
+ nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true })
+
+ const event = createTestEvent({
+ type: 'identify',
+ traits: {
+ name: 'test',
+ email: 'test@company.com'
+ },
+ properties: {
+ timezone: 'America/New_York'
+ },
+ userId: '123456'
+ })
+
+ const responses = await testDestination.testAction('identify', {
+ event,
+ mapping: heIdentifyMapping,
+ useDefaultMappings: true,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+
+ expect(responses[0].status).toEqual(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts
new file mode 100644
index 0000000000..ccbb2d14da
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/identify/generated-types.ts
@@ -0,0 +1,128 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The External ID of the user
+ */
+ user_id: string
+ /**
+ * The user's name
+ */
+ name?: string | null
+ /**
+ * The user's first name. This field is mandatory if you're not providing a name field
+ */
+ first_name?: string | null
+ /**
+ * The user's last name. This field is mandatory if you're not providing a name field
+ */
+ last_name?: string | null
+ /**
+ * The user's email address
+ */
+ email?: string
+ /**
+ * The account id, to uniquely identify the account associated with the user
+ */
+ account_id?: string
+ /**
+ * The timestamp when the user was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".
+ */
+ created_at?: string
+ /**
+ * Properties to associate with the user
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+ /**
+ * User Anonymous id
+ */
+ anonymous_id?: string | null
+ /**
+ * The ID of the event.
+ */
+ event_id?: string
+ /**
+ * The path of the document.
+ */
+ doc_path?: string
+ /**
+ * The search query of the document.
+ */
+ doc_search?: string
+ /**
+ * The title of the page where the event occurred.
+ */
+ doc_title?: string
+ /**
+ * The URL of the page where the event occurred.
+ */
+ url?: string
+ /**
+ * The referrer of the page where the event occurred.
+ */
+ referer?: string
+ /**
+ * The user agent of the browser.
+ */
+ user_agent?: string
+ /**
+ * The language of the browser.
+ */
+ user_language?: string
+ /**
+ * The time of the event in UTC.
+ */
+ utc_time?: string
+ /**
+ * Information about the UTM parameters.
+ */
+ utm?: {
+ /**
+ * The source of the campaign.
+ */
+ source?: string
+ /**
+ * The medium of the campaign.
+ */
+ medium?: string
+ /**
+ * The name of the campaign.
+ */
+ name?: string
+ /**
+ * The term of the campaign.
+ */
+ term?: string
+ /**
+ * The content of the campaign.
+ */
+ content?: string
+ }
+ /**
+ * Information about the screen.
+ */
+ screen?: {
+ /**
+ * The height of the screen.
+ */
+ height?: number
+ /**
+ * The width of the screen.
+ */
+ width?: number
+ /**
+ * The density of the screen.
+ */
+ density?: number
+ }
+ /**
+ * The timezone of the browser.
+ */
+ timezone?: string
+ /**
+ * The IP address of the user.
+ */
+ source_ip?: string
+}
diff --git a/packages/destination-actions/src/destinations/hyperengage/identify/index.ts b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts
new file mode 100644
index 0000000000..4acd8d5fa8
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/identify/index.ts
@@ -0,0 +1,113 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { validateInput } from '../validateInput'
+import { commonFields } from '../commonFields'
+
+const action: ActionDefinition = {
+ title: 'Identify',
+ description: 'Send identify calls to Hyperengage.',
+ defaultSubscription: 'type = "identify"',
+ platform: 'cloud',
+ fields: {
+ user_id: {
+ type: 'string',
+ required: true,
+ description: 'The External ID of the user',
+ label: 'User ID',
+ default: { '@path': '$.userId' }
+ },
+ name: {
+ type: 'string',
+ required: false,
+ description: "The user's name",
+ allowNull: true,
+ label: 'Name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.name' },
+ then: { '@path': '$.traits.name' },
+ else: { '@path': '$.properties.name' }
+ }
+ }
+ },
+ first_name: {
+ type: 'string',
+ required: false,
+ allowNull: true,
+ description: "The user's first name. This field is mandatory if you're not providing a name field",
+ label: 'First name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.first_name' },
+ then: { '@path': '$.traits.first_name' },
+ else: { '@path': '$.properties.first_name' }
+ }
+ }
+ },
+ last_name: {
+ type: 'string',
+ required: false,
+ allowNull: true,
+ description: "The user's last name. This field is mandatory if you're not providing a name field",
+ label: 'Last name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.last_name' },
+ then: { '@path': '$.traits.last_name' },
+ else: { '@path': '$.properties.last_name' }
+ }
+ }
+ },
+ email: {
+ type: 'string',
+ required: false,
+ description: "The user's email address",
+ label: 'Email address',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.email' },
+ then: { '@path': '$.traits.email' },
+ else: { '@path': '$.properties.email' }
+ }
+ }
+ },
+ account_id: {
+ type: 'string',
+ required: false,
+ description: 'The account id, to uniquely identify the account associated with the user',
+ label: 'Account id',
+ default: {
+ '@if': {
+ exists: { '@path': '$.context.group_id' },
+ then: { '@path': '$.context.group_id' },
+ else: { '@path': '$.groupId' }
+ }
+ }
+ },
+ created_at: {
+ type: 'string',
+ required: false,
+ description:
+ 'The timestamp when the user was created, represented in the ISO-8601 date format. For instance, "2023-09-26T15:30:00Z".',
+ label: 'Created at',
+ default: { '@path': '$.traits.created_at' }
+ },
+ traits: {
+ type: 'object',
+ label: 'Traits',
+ description: 'Properties to associate with the user',
+ required: false,
+ default: { '@path': '$.traits' }
+ },
+ ...commonFields
+ },
+ perform: (request, data) => {
+ return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, {
+ method: 'post',
+ json: validateInput(data.settings, data.payload, 'user_identify')
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/hyperengage/index.ts b/packages/destination-actions/src/destinations/hyperengage/index.ts
new file mode 100644
index 0000000000..af23f8339a
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/index.ts
@@ -0,0 +1,72 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+import { defaultValues } from '@segment/actions-core'
+import identify from './identify'
+import group from './group'
+import track from './track'
+
+const presets: DestinationDefinition['presets'] = [
+ {
+ name: 'Track Event',
+ subscribe: 'type = "track"',
+ partnerAction: 'track',
+ mapping: defaultValues(track.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Identify User',
+ subscribe: 'type = "identify"',
+ partnerAction: 'identify',
+ mapping: defaultValues(identify.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Group',
+ subscribe: 'type = "group"',
+ partnerAction: 'group',
+ mapping: defaultValues(group.fields),
+ type: 'automatic'
+ }
+]
+
+const destination: DestinationDefinition = {
+ name: 'Hyperengage (Actions)',
+ slug: 'actions-hyperengage',
+ mode: 'cloud',
+ description: 'Hyperengage actions destination, to connect your product usage data from Segment to Hyperengage',
+ authentication: {
+ scheme: 'custom',
+ fields: {
+ apiKey: {
+ type: 'string',
+ label: 'API Key',
+ description: 'Your Hyperengage API key located in the Integration Settings page.',
+ required: true
+ },
+ workspaceIdentifier: {
+ type: 'string',
+ label: 'Workspace Identifier',
+ description: 'Your Hyperengage workspace identifier located in the Integration Settings page.',
+ required: true
+ }
+ },
+ testAuthentication: async (request, { settings }) => {
+ return await request('https://api.hyperengage.io/api/v1/verify_api_key', {
+ method: 'post',
+ json: {
+ api_key: `${settings.apiKey}`,
+ workspace_identifier: `${settings.workspaceIdentifier}`
+ }
+ })
+ }
+ },
+
+ presets,
+ actions: {
+ identify,
+ group,
+ track
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts
new file mode 100644
index 0000000000..ab8977280b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/track/__tests__/index.test.ts
@@ -0,0 +1,93 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+beforeAll(() => {
+ nock.disableNetConnect()
+})
+
+afterAll(() => {
+ nock.enableNetConnect()
+ nock.cleanAll()
+})
+
+const heTrackMapping = {
+ event_name: {
+ '@path': '$.event'
+ },
+ properties: {
+ '@path': '$.properties'
+ },
+ user_id: {
+ '@path': '$.userId'
+ },
+ account_id: {
+ '@path': '$.groupId'
+ }
+}
+
+describe('Hyperengage.track', () => {
+ test('Should throw an error if `event_name` is not defined', async () => {
+ const event = createTestEvent({
+ type: 'track',
+ properties: {
+ recency: 'Now'
+ },
+ event: 'Test_Event'
+ })
+
+ await expect(
+ testDestination.testAction('track', {
+ event,
+ mapping: heTrackMapping
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should throw an error if workspaceIdentifier or apiKey is not defined', async () => {
+ const event = createTestEvent({
+ type: 'track',
+ properties: {
+ recency: 'Now'
+ },
+ event: 'Test_Event'
+ })
+
+ await expect(
+ testDestination.testAction('track', {
+ event,
+ mapping: heTrackMapping,
+ settings: {
+ workspaceIdentifier: '',
+ apiKey: ''
+ }
+ })
+ ).rejects.toThrowError()
+ })
+
+ test('Should send an track event to Hyperengage', async () => {
+ // Mock: Segment track Call
+ nock('https://events.hyperengage.io').post('/api/v1/s2s/event?token=apiKey').reply(200, { success: true })
+
+ const event = createTestEvent({
+ type: 'track',
+ properties: {
+ recency: 'Now'
+ },
+ event: 'Test_Event'
+ })
+
+ const responses = await testDestination.testAction('track', {
+ event,
+ mapping: heTrackMapping,
+ settings: {
+ workspaceIdentifier: 'identifier',
+ apiKey: 'apiKey'
+ }
+ })
+
+ expect(responses[0].status).toEqual(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts
new file mode 100644
index 0000000000..f05ca21a4a
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/track/generated-types.ts
@@ -0,0 +1,112 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The name of the event
+ */
+ event_name: string
+ /**
+ * The user id, to uniquely identify the user associated with the event
+ */
+ user_id: string
+ /**
+ * The properties of the track call
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+ /**
+ * The account id, to uniquely identify the account associated with the user
+ */
+ account_id?: string
+ /**
+ * User Anonymous id
+ */
+ anonymous_id?: string | null
+ /**
+ * The ID of the event.
+ */
+ event_id?: string
+ /**
+ * The path of the document.
+ */
+ doc_path?: string
+ /**
+ * The search query of the document.
+ */
+ doc_search?: string
+ /**
+ * The title of the page where the event occurred.
+ */
+ doc_title?: string
+ /**
+ * The URL of the page where the event occurred.
+ */
+ url?: string
+ /**
+ * The referrer of the page where the event occurred.
+ */
+ referer?: string
+ /**
+ * The user agent of the browser.
+ */
+ user_agent?: string
+ /**
+ * The language of the browser.
+ */
+ user_language?: string
+ /**
+ * The time of the event in UTC.
+ */
+ utc_time?: string
+ /**
+ * Information about the UTM parameters.
+ */
+ utm?: {
+ /**
+ * The source of the campaign.
+ */
+ source?: string
+ /**
+ * The medium of the campaign.
+ */
+ medium?: string
+ /**
+ * The name of the campaign.
+ */
+ name?: string
+ /**
+ * The term of the campaign.
+ */
+ term?: string
+ /**
+ * The content of the campaign.
+ */
+ content?: string
+ }
+ /**
+ * Information about the screen.
+ */
+ screen?: {
+ /**
+ * The height of the screen.
+ */
+ height?: number
+ /**
+ * The width of the screen.
+ */
+ width?: number
+ /**
+ * The density of the screen.
+ */
+ density?: number
+ }
+ /**
+ * The timezone of the browser.
+ */
+ timezone?: string
+ /**
+ * The IP address of the user.
+ */
+ source_ip?: string
+}
diff --git a/packages/destination-actions/src/destinations/hyperengage/track/index.ts b/packages/destination-actions/src/destinations/hyperengage/track/index.ts
new file mode 100644
index 0000000000..9565ede19c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/track/index.ts
@@ -0,0 +1,56 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { validateInput } from '../validateInput'
+import { commonFields } from '../commonFields'
+
+const action: ActionDefinition = {
+ title: 'Track',
+ description: 'Send track calls to Hyperengage.',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ event_name: {
+ type: 'string',
+ required: true,
+ description: 'The name of the event',
+ label: 'Event name',
+ default: { '@path': '$.event' }
+ },
+ user_id: {
+ type: 'string',
+ required: true,
+ description: 'The user id, to uniquely identify the user associated with the event',
+ label: 'User id',
+ default: { '@path': '$.userId' }
+ },
+ properties: {
+ type: 'object',
+ required: false,
+ description: 'The properties of the track call',
+ label: 'Event properties',
+ default: { '@path': '$.properties' }
+ },
+ account_id: {
+ type: 'string',
+ required: false,
+ description: 'The account id, to uniquely identify the account associated with the user',
+ label: 'Account id',
+ default: {
+ '@if': {
+ exists: { '@path': '$.context.group_id' },
+ then: { '@path': '$.context.group_id' },
+ else: { '@path': '$.groupId' }
+ }
+ }
+ },
+ ...commonFields
+ },
+ perform: (request, data) => {
+ return request(`https://events.hyperengage.io/api/v1/s2s/event?token=${data.settings.apiKey}`, {
+ method: 'post',
+ json: validateInput(data.settings, data.payload, 'track')
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/hyperengage/validateInput.ts b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts
new file mode 100644
index 0000000000..770b52a320
--- /dev/null
+++ b/packages/destination-actions/src/destinations/hyperengage/validateInput.ts
@@ -0,0 +1,105 @@
+/* eslint-disable @typescript-eslint/no-explicit-any */
+
+import { Settings } from './generated-types'
+import { PayloadValidationError } from '@segment/actions-core'
+
+// Convert relevant input properties to Hyperengage properties
+export const validateInput = (
+ settings: Settings,
+ input: Record,
+ event_type: 'track' | 'user_identify' | 'account_identify'
+): any => {
+ const properties: any = {
+ api_key: settings.apiKey,
+ workspace_key: settings.workspaceIdentifier,
+ doc_encoding: 'UTF-8',
+ src: 'segment_api',
+ screen_resolution: '0',
+ account_id: input?.account_id || input?.traits?.companyId || input?.traits?.company?.id,
+ ids: {},
+ event_type: event_type,
+ ...input
+ }
+ delete properties.event_name
+
+ // Get screen_resolution from the input screen width and height
+ if (input?.screen) {
+ const { width, height } = input.screen
+ properties.screen_resolution = `${width || 0}x${height || 0}`
+ properties.vp_size = `${width || 0}x${height || 0}`
+ delete properties.screen
+ }
+
+ // Resolve local_tz_offset property, we can get local_tz_offset from the input context.timezone
+ if (input?.timezone) {
+ const offset = new Date().toLocaleString('en-US', { timeZone: input.timezone, timeZoneName: 'short' }).split(' ')[2]
+ properties.local_tz_offset = offset
+ delete properties.timezone
+ }
+
+ // Check if event property is present, we will use it as event_type
+ if (input?.event_name && event_type === 'track') {
+ properties.event_type = input?.event_name
+ delete properties.event_name
+ } else {
+ properties.event_type = event_type
+ }
+
+ // Validate user properties
+ if (event_type === 'user_identify') {
+ if (input?.name) {
+ properties.traits = {
+ email: input?.email,
+ name: input?.name,
+ created_at: input?.created_at,
+ ...properties.traits
+ }
+ } else if (input?.first_name || input?.last_name) {
+ properties.traits = {
+ email: input?.email,
+ name: `${input?.first_name} ${input?.last_name}}`,
+ created_at: input?.created_at,
+ ...properties.traits
+ }
+ } else {
+ throw new PayloadValidationError('Either name, or first_name and last_name must be provided.')
+ }
+
+ // Create object if company_id is present in traits
+ if (input?.traits?.company) {
+ properties.company = {
+ ...input.traits.company
+ }
+ delete properties.traits.company
+ }
+ // Delete unnecessary user properties
+ delete properties.email
+ delete properties.name
+ delete properties.first_name
+ delete properties.last_name
+ delete properties.created_at
+ }
+
+ // Validate account properties
+ if (event_type === 'account_identify') {
+ properties.traits = {
+ name: input?.name,
+ created_at: input?.created_at,
+ plan_name: input?.plan,
+ industry: input?.industry,
+ trial_start_date: input?.trial_start,
+ trial_expiry_date: input?.trial_end,
+ website: input?.website,
+ ...properties.traits
+ }
+ delete properties.name
+ delete properties.created_at
+ delete properties.plan
+ delete properties.industry
+ delete properties.trial_start
+ delete properties.trial_end
+ delete properties.website
+ }
+
+ return properties
+}
diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
new file mode 100644
index 0000000000..dde35bd23f
--- /dev/null
+++ b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
@@ -0,0 +1,48 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * User credentials for establishing an SFTP connection with LiveRamp.
+ */
+ sftp_username?: string
+ /**
+ * User credentials for establishing an SFTP connection with LiveRamp.
+ */
+ sftp_password?: string
+ /**
+ * Path within the LiveRamp SFTP server to upload the files to. This path must exist and all subfolders must be pre-created.
+ */
+ sftp_folder_path?: string
+ /**
+ * Unique ID that identifies members of an audience. A typical audience key might be client customer IDs, email addresses, or phone numbers.
+ */
+ audience_key: string
+ /**
+ * Additional data pertaining to the user to be written to the file.
+ */
+ identifier_data?: {
+ [k: string]: unknown
+ }
+ /**
+ * Additional data pertaining to the user to be hashed before written to the file. Use field name **phone_number** or **email** to apply LiveRamp's specific hashing rules.
+ */
+ unhashed_identifier_data?: {
+ [k: string]: unknown
+ }
+ /**
+ * Character used to separate tokens in the resulting file.
+ */
+ delimiter: string
+ /**
+ * Name of the CSV file to upload for LiveRamp ingestion.
+ */
+ filename: string
+ /**
+ * Receive events in a batch payload. This is required for LiveRamp audiences ingestion.
+ */
+ enable_batching: boolean
+ /**
+ * Maximum number of events to include in each batch. Actual batch sizes may be lower.
+ */
+ batch_size?: number
+}
From 17a2f7fca2b90ef3edaf7df398b2da3b662fa7ff Mon Sep 17 00:00:00 2001
From: suppalapati <110847862+Sneha-Uppalapati@users.noreply.github.com>
Date: Tue, 3 Oct 2023 05:49:20 -0700
Subject: [PATCH 011/389] fix: remove eventstreams flagon (#1622)
Co-authored-by: suppalapati
---
.../src/destinations/engage/twilio/__tests__/send-sms.test.ts | 4 ----
.../destinations/engage/twilio/utils/PhoneMessageSender.ts | 2 --
2 files changed, 6 deletions(-)
diff --git a/packages/destination-actions/src/destinations/engage/twilio/__tests__/send-sms.test.ts b/packages/destination-actions/src/destinations/engage/twilio/__tests__/send-sms.test.ts
index b03bbd9a0a..f92a894f88 100644
--- a/packages/destination-actions/src/destinations/engage/twilio/__tests__/send-sms.test.ts
+++ b/packages/destination-actions/src/destinations/engage/twilio/__tests__/send-sms.test.ts
@@ -1,7 +1,6 @@
import nock from 'nock'
import { createTestAction, expectErrorLogged, expectInfoLogged, loggerMock as logger } from './__helpers__/test-utils'
import { FLAGON_NAME_LOG_ERROR, FLAGON_NAME_LOG_INFO, SendabilityStatus } from '../../utils'
-import { FLAGON_EVENT_STREAMS_ONBOARDING } from '../utils'
const defaultTags = JSON.stringify({})
@@ -660,8 +659,6 @@ describe.each(['stage', 'production'])('%s environment', (environment) => {
})
it('add tags to body', async () => {
- const features = { [FLAGON_EVENT_STREAMS_ONBOARDING]: true }
-
const expectedTwilioRequest = new URLSearchParams({
Body: 'Hello world, jane!',
From: 'MG1111222233334444',
@@ -674,7 +671,6 @@ describe.each(['stage', 'production'])('%s environment', (environment) => {
.reply(201, {})
const responses = await testAction({
- features,
mappingOverrides: {
customArgs: {
audience_id: '1',
diff --git a/packages/destination-actions/src/destinations/engage/twilio/utils/PhoneMessageSender.ts b/packages/destination-actions/src/destinations/engage/twilio/utils/PhoneMessageSender.ts
index 3af2c09580..a0ea5b37aa 100644
--- a/packages/destination-actions/src/destinations/engage/twilio/utils/PhoneMessageSender.ts
+++ b/packages/destination-actions/src/destinations/engage/twilio/utils/PhoneMessageSender.ts
@@ -3,8 +3,6 @@
import { TwilioMessageSender, TwilioPayloadBase } from './TwilioMessageSender'
import { OperationDecorator, TrackedError, OperationContext, ExtId } from '../../utils'
-export const FLAGON_EVENT_STREAMS_ONBOARDING = 'event-streams-onboarding'
-
/**
* Base class for sending sms/mms
*/
From b984363f4d63fb9fecfee518be65c0600e8f4f3f Mon Sep 17 00:00:00 2001
From: Elena
Date: Tue, 3 Oct 2023 06:16:59 -0700
Subject: [PATCH 012/389] Yahoo audiences (#1628)
* scaffold files and folders
* updated yahoo integration
* Comments and some fixes.
* Updating definition to have `createSegment` action.
* modified mappings
* updateStatus fix
* Added new action createCustomerNode
Code clean up, extra console.logs for testing
* Yahoo: prep for Staging
* Yahoo: minor fixes
* Yahoo: gdpr support
* Yahoo: added validation that incoming event is Audience update, removed unnecessary logging
* Removing repeated code, improving JSDoc.
* Unifying `updateTaxonomy` calls.
* - `await/try/catch` instead of chained promises;
- Missing `BASE_URL` as constant.
* Yahoo: added createAudience, testAuthentication, updated settings
* Yahoo: async func call fix
* attempting to get project to build
* registering yahoo-audiences
* Adding Destination description
* Adding missing description to Action
* Setting enable_batching field to be boolean
* Setting enable_batching setting to be boolean
* Yahoo: handling errors from taxonomy API
* Yahoo: modifier err handling
* Unit test for `YahooAudiences.updateSegment`.
* Success and failure cases for `YahooAudiences.updateSegment`.
* Unit tests for `createAudience` in Yahoo Audiences.
* Yahoo: removed duplicate file
* Yahoo: updateSegment action changes - added Identifier selector, Yahoo payload checks, set action fields 'required' status to false where needed
* Yahoo: updated audienceSettings
* Yahoo: added more unit tests, added support of preferred identifier in 'audienceSettings' with a fallback to an identifier fetched from the action
* Yahoo: added check of audience_id
* Fixing unit tests.
* Yahoo: minor fixes
* Yahoo: cleaned up comments, console.log
* Snapshots don't make sense here: we have two endpoints. One of them uses OAuth1, which gets a new nonce every time the API is called.
* removing unnecessary and possibly problematic error throw
---------
Co-authored-by: Jina Park
Co-authored-by: Elena Parshina
Co-authored-by: Leonel Sanches <113376080+seg-leonelsanches@users.noreply.github.com>
Co-authored-by: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
---
.../src/destinations/index.ts | 1 +
.../yahoo-audiences/__tests__/index.test.ts | 70 ++++++
.../destinations/yahoo-audiences/constants.ts | 2 +
.../__tests__/index.test.ts | 23 ++
.../createCustomerNode/generated-types.ts | 12 ++
.../createCustomerNode/index.ts | 37 ++++
.../createSegment/__tests__/index.test.ts | 24 +++
.../createSegment/generated-types.ts | 20 ++
.../yahoo-audiences/createSegment/index.ts | 53 +++++
.../yahoo-audiences/generated-types.ts | 40 ++++
.../src/destinations/yahoo-audiences/index.ts | 204 ++++++++++++++++++
.../src/destinations/yahoo-audiences/types.ts | 27 +++
.../updateSegment/__tests__/index.test.ts | 198 +++++++++++++++++
.../updateSegment/generated-types.ts | 54 +++++
.../yahoo-audiences/updateSegment/index.ts | 171 +++++++++++++++
.../destinations/yahoo-audiences/utils-rt.ts | 154 +++++++++++++
.../destinations/yahoo-audiences/utils-tax.ts | 107 +++++++++
17 files changed, 1197 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/constants.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/index.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/types.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
create mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index 347b685560..8b394ca887 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -127,6 +127,7 @@ register('64edec5a4f881f992e432b81', './acoustic-s3tc')
register('64edeb2bee24614fe52ede34', './optimizely-advanced-audience-targeting')
register('64ede9fe67158afa8de61480', './dynamic-yield-audiences')
register('64f703d1f6e9aa0a283ae3e2', './absmartly')
+register('6514281004d549fae3fd086a', './yahoo-audiences')
register('650bdf1a62fb34ef0a8058e1', './klaviyo')
register('6512d7f86bdccc3829fc4ac3', './optimizely-data-platform')
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
new file mode 100644
index 0000000000..56b7a06ba2
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
@@ -0,0 +1,70 @@
+import nock from 'nock'
+import { IntegrationError, createTestIntegration } from '@segment/actions-core'
+
+import Destination from '../index'
+
+const AUDIENCE_ID = 'aud_123456789012345678901234567' // References audienceSettings.audience_id
+const AUDIENCE_KEY = 'sneakers_buyers' // References audienceSettings.audience_key
+const ENGAGE_SPACE_ID = 'acme_corp_engage_space' // References settings.engage_space_id
+const MDM_ID = 'mdm 123' // References settings.mdm_id
+const TX_KEY = '123' // References settings.taxonomy_client_id
+const TX_SECRET = '456' // References settings.taxonomy_client_secret
+const CUST_DESC = 'ACME Corp' // References settings.customer_desc
+
+const createAudienceInput = {
+ settings: {
+ engage_space_id: ENGAGE_SPACE_ID,
+ mdm_id: MDM_ID,
+ taxonomy_client_key: TX_KEY,
+ taxonomy_client_secret: TX_SECRET,
+ customer_desc: CUST_DESC
+ },
+ audienceName: '',
+ audienceSettings: {
+ audience_key: AUDIENCE_KEY,
+ audience_id: AUDIENCE_ID
+ }
+}
+
+describe('Yahoo Audiences', () => {
+ describe('createAudience() function', () => {
+ let testDestination: any
+
+ beforeEach(() => {
+ testDestination = createTestIntegration(Destination)
+ })
+
+ describe('Success cases', () => {
+ it('It should create the audience successfully', async () => {
+ nock('https://datax.yahooapis.com').put(`/v1/taxonomy/append/${ENGAGE_SPACE_ID}`).reply(202, {
+ anything: '123'
+ })
+
+ const result = await testDestination.createAudience(createAudienceInput)
+ expect(result.externalId).toBe(AUDIENCE_ID)
+ })
+ })
+ describe('Failure cases', () => {
+ it('should throw an error when audience_id setting is missing', async () => {
+ createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
+ createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
+ createAudienceInput.audienceSettings.audience_id = ''
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('should throw an error when audience_key setting is missing', async () => {
+ createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
+ createAudienceInput.audienceSettings.audience_key = ''
+ createAudienceInput.audienceSettings.audience_id = 'aud_12345'
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('should throw an error when engage_space_id setting is missing', async () => {
+ createAudienceInput.settings.engage_space_id = ''
+ createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
+ createAudienceInput.audienceSettings.audience_id = 'aud_123456789012345678901234567'
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/constants.ts b/packages/destination-actions/src/destinations/yahoo-audiences/constants.ts
new file mode 100644
index 0000000000..7e3698eb8c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/constants.ts
@@ -0,0 +1,2 @@
+export const TAXONOMY_BASE_URL = 'https://datax.yahooapis.com'
+export const REALTIME_BASE_URL = 'https://dataxonline.yahoo.com/online/audience'
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
new file mode 100644
index 0000000000..d77214c3a3
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
@@ -0,0 +1,23 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+describe('YahooAudiences.createCustomerNode', () => {
+ it.skip('should pull yahoo taxonomy', async () => {
+ const event = createTestEvent()
+ nock(`https://datax.yahooapis.com/v1/taxonomy/append`)
+ .post(event as any)
+ .reply(200)
+
+ const responses = await testDestination.testAction('createCustomerNode', {
+ event,
+ mapping: {},
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
new file mode 100644
index 0000000000..2ddeeb41ba
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
@@ -0,0 +1,12 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy
+ */
+ engage_space_id: string
+ /**
+ * Provide a description for the Customer node in Yahoo taxonomy. This must be less then 1000 characters
+ */
+ customer_desc?: string
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
new file mode 100644
index 0000000000..0d283f4a5b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
@@ -0,0 +1,37 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { gen_customer_taxonomy_payload } from '../utils-tax'
+import { update_taxonomy } from '../utils-tax'
+
+const action: ActionDefinition = {
+ title: 'Create top-level CUSTOMER node in Yahoo taxonomy',
+ defaultSubscription: 'event = "Audience Entered" and event = "Audience Exited"',
+ description: 'Create top-level CUSTOMER node in Yahoo taxonomy',
+ fields: {
+ engage_space_id: {
+ label: 'Engage Space Id',
+ description:
+ 'Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy',
+ type: 'string',
+ required: true
+ },
+ customer_desc: {
+ label: 'Customer Description',
+ description:
+ 'Provide a description for the Customer node in Yahoo taxonomy. This must be less then 1000 characters',
+ type: 'string',
+ required: false
+ }
+ },
+ perform: async (request, { settings, payload }) => {
+ const tx_creds = {
+ tx_client_key: settings.taxonomy_client_key,
+ tx_client_secret: settings.taxonomy_client_secret
+ }
+ const taxonomy_payload = gen_customer_taxonomy_payload(settings, payload)
+ return await update_taxonomy('', tx_creds, request, taxonomy_payload)
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
new file mode 100644
index 0000000000..0504084195
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
@@ -0,0 +1,24 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+import { TAXONOMY_BASE_URL } from '../../constants'
+
+const testDestination = createTestIntegration(Destination)
+
+describe('YahooAudiences.createSegment', () => {
+ it.skip('should pull yahoo taxonomy', async () => {
+ const event = createTestEvent()
+ nock(`${TAXONOMY_BASE_URL}/v1/taxonomy`)
+ .post(event as any)
+ .reply(200)
+
+ const responses = await testDestination.testAction('createSegment', {
+ event,
+ mapping: {},
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
new file mode 100644
index 0000000000..931a2e1faa
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
@@ -0,0 +1,20 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Provide audience key. This maps to the "Name" of the Segment node in Yahoo taxonomy
+ */
+ segment_audience_key: string
+ /**
+ * Provide audience Id (aud_...) from audience URL in Segment Engage. This maps to the "Id" of the Segment node in Yahoo taxonomy
+ */
+ segment_audience_id: string
+ /**
+ * Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy and specifies the parent node for your Segment node in Yahoo taxonomy
+ */
+ engage_space_id?: string
+ /**
+ * Provide the description for Segment node in Yahoo taxonomy. This must be less then 1000 characters
+ */
+ customer_desc?: string
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
new file mode 100644
index 0000000000..3349b15284
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
@@ -0,0 +1,53 @@
+import type { ActionDefinition } from '@segment/actions-core'
+
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { gen_segment_subtaxonomy_payload } from '../utils-tax'
+import { update_taxonomy } from '../utils-tax'
+/* Generates a Segment in Yahoo Taxonomy */
+
+const action: ActionDefinition = {
+ title: 'Create SEGMENT sub-node in Yahoo taxonomy',
+ description: 'Use this action to generate SEGMENT sub-node within CUSTOMER node in Yahoo taxonomy',
+ defaultSubscription: 'event = "Audience Entered" and event = "Audience Exited"',
+
+ fields: {
+ segment_audience_key: {
+ label: 'Audience Key',
+ description: 'Provide audience key. This maps to the "Name" of the Segment node in Yahoo taxonomy',
+ type: 'string',
+ required: true
+ },
+ segment_audience_id: {
+ label: 'Audience Id',
+ description:
+ 'Provide audience Id (aud_...) from audience URL in Segment Engage. This maps to the "Id" of the Segment node in Yahoo taxonomy',
+ type: 'string',
+ required: true
+ },
+ engage_space_id: {
+ label: 'Engage Space Id',
+ description:
+ 'Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy and specifies the parent node for your Segment node in Yahoo taxonomy',
+ type: 'string',
+ required: false
+ },
+ customer_desc: {
+ label: 'Space Description',
+ description: 'Provide the description for Segment node in Yahoo taxonomy. This must be less then 1000 characters',
+ type: 'string',
+ required: false
+ }
+ },
+ perform: async (request, { payload, settings }) => {
+ const tx_creds = {
+ tx_client_key: settings.taxonomy_client_key,
+ tx_client_secret: settings.taxonomy_client_secret
+ }
+
+ const body_form_data = gen_segment_subtaxonomy_payload(payload)
+ return await update_taxonomy(String(payload.engage_space_id), tx_creds, request, body_form_data)
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
new file mode 100644
index 0000000000..220c0f99b8
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
@@ -0,0 +1,40 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Yahoo MDM ID provided by Yahoo representative
+ */
+ mdm_id: string
+ /**
+ * Taxonomy API client Id. Required to update Yahoo taxonomy
+ */
+ taxonomy_client_key: string
+ /**
+ * Taxonomy API client secret. Required to update Yahoo taxonomy
+ */
+ taxonomy_client_secret: string
+ /**
+ * Engage Space Id found in Unify > Settings > API Access
+ */
+ engage_space_id: string
+ /**
+ * Engage space name and description
+ */
+ customer_desc?: string
+}
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface AudienceSettings {
+ /**
+ * Segment Audience Id (aud_...)
+ */
+ audience_id: string
+ /**
+ * Segment Audience Key
+ */
+ audience_key: string
+ /**
+ * Specify the identifier(s) to send to Yahoo
+ */
+ identifier: string
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
new file mode 100644
index 0000000000..74ccc57386
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
@@ -0,0 +1,204 @@
+import type { AudienceDestinationDefinition, ModifiedResponse } from '@segment/actions-core'
+import { IntegrationError } from '@segment/actions-core'
+import type { Settings, AudienceSettings } from './generated-types'
+import { generate_jwt } from './utils-rt'
+import updateSegment from './updateSegment'
+import createSegment from './createSegment'
+import createCustomerNode from './createCustomerNode'
+import { gen_customer_taxonomy_payload, gen_segment_subtaxonomy_payload, update_taxonomy } from './utils-tax'
+
+interface RefreshTokenResponse {
+ access_token: string
+}
+
+const destination: AudienceDestinationDefinition = {
+ name: 'Yahoo Audiences',
+ slug: 'actions-yahoo-audiences',
+ mode: 'cloud',
+ description: 'Sync Segment Engage Audiences to Yahoo Ads',
+ authentication: {
+ scheme: 'oauth2',
+ fields: {
+ mdm_id: {
+ label: 'MDM ID',
+ description: 'Yahoo MDM ID provided by Yahoo representative',
+ type: 'string',
+ required: true
+ },
+ taxonomy_client_key: {
+ label: 'Yahoo Taxonomy API client Id',
+ description: 'Taxonomy API client Id. Required to update Yahoo taxonomy',
+ type: 'string',
+ required: true
+ },
+ taxonomy_client_secret: {
+ label: 'Yahoo Taxonomy API client secret',
+ description: 'Taxonomy API client secret. Required to update Yahoo taxonomy',
+ type: 'password',
+ required: true
+ },
+ engage_space_id: {
+ label: 'Engage Space Id',
+ description: 'Engage Space Id found in Unify > Settings > API Access',
+ type: 'string',
+ required: true
+ },
+ customer_desc: {
+ label: 'Customer Description',
+ description: 'Engage space name and description',
+ type: 'string',
+ required: false
+ }
+ },
+ testAuthentication: async (request, { settings }) => {
+ // Used to create top-level customer node
+ const tx_creds = {
+ tx_client_key: settings.taxonomy_client_key,
+ tx_client_secret: settings.taxonomy_client_secret
+ }
+ const data = {
+ engage_space_id: settings.engage_space_id,
+ customer_desc: settings.customer_desc
+ }
+
+ const body_form_data = gen_customer_taxonomy_payload(settings, data)
+ await update_taxonomy('', tx_creds, request, body_form_data)
+ },
+ refreshAccessToken: async (request, { auth }) => {
+ // Refresh Realtime API token (Oauth2 client_credentials)
+ const rt_client_key = JSON.parse(auth.clientId)['rt_api']
+ const rt_client_secret = JSON.parse(auth.clientSecret)['rt_api']
+ const jwt = generate_jwt(rt_client_key, rt_client_secret)
+ const res: ModifiedResponse = await request(
+ 'https://id.b2b.yahooinc.com/identity/oauth2/access_token',
+ {
+ method: 'POST',
+ body: new URLSearchParams({
+ client_assertion: jwt,
+ client_assertion_type: 'urn:ietf:params:oauth:client-assertion-type:jwt-bearer',
+ grant_type: 'client_credentials',
+ scope: 'audience',
+ realm: 'dataxonline'
+ })
+ }
+ )
+ // Oauth1 credentials
+ // Removed thas temporarily as we're fetching tx creds from the global settings
+ // const tx_client_key = JSON.parse(auth.clientId)['tax_api']
+ // const tx_client_secret = JSON.parse(auth.clientSecret)['tax_api']
+ const rt_access_token = res.data.access_token
+ // const creds = {
+ // // Oauth1
+ // tx: {
+ // tx_client_key: tx_client_key,
+ // tx_client_secret: tx_client_secret
+ // },
+ // // Oauth2
+ // rt: rt_access_token
+ // }
+ // const creds_base64 = Buffer.from(JSON.stringify(creds)).toString('base64')
+ // return { accessToken: creds_base64 }
+ return { accessToken: rt_access_token }
+ }
+ },
+ audienceFields: {
+ audience_id: {
+ type: 'string',
+ label: 'Audience Id',
+ description: 'Segment Audience Id (aud_...)',
+ required: true
+ },
+ audience_key: {
+ label: 'Audience key',
+ description: 'Segment Audience Key',
+ type: 'string',
+ required: true
+ },
+ identifier: {
+ label: 'User Identifier',
+ description: 'Specify the identifier(s) to send to Yahoo',
+ type: 'string',
+ required: true,
+ default: 'email',
+ choices: [
+ { value: 'email', label: 'Send email' },
+ { value: 'maid', label: 'Send MAID' },
+ { value: 'email_maid', label: 'Send email and/or MAID' }
+ ]
+ }
+ },
+ audienceConfig: {
+ mode: {
+ type: 'synced', // Indicates that the audience is synced on some schedule
+ full_audience_sync: false // If true, we send the entire audience. If false, we just send the delta.
+ },
+
+ async createAudience(request, createAudienceInput) {
+ // const tax_client_key = JSON.parse(auth.clientId)['tax_api']
+
+ //engage_space_id, audience_id and audience_key will be removed once we have Payload accessible by createAudience()
+ //context.personas.computation_id
+ //context.personas.computation_key
+ //context.personas.namespace
+ const audience_id = createAudienceInput.audienceSettings?.audience_id
+ const audience_key = createAudienceInput.audienceSettings?.audience_key
+ const engage_space_id = createAudienceInput.settings?.engage_space_id
+ const identifier = createAudienceInput.audienceSettings?.identifier
+ // The 3 errors below will be removed once we have Payload accessible by createAudience()
+ if (!audience_id) {
+ throw new IntegrationError('Create Audience: missing audience Id value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+ /*
+ audience_id will not be exposed in the UI once we have Payload accessible by createAudience()
+
+ const regex = /^aud_[a-zA-Z0-9]{27}$/
+ if (regex.test(audience_id) === false) {
+ throw new IntegrationError(
+ 'Incorrect audience Id. Provide audience Id "aud_..." from audience URL',
+ 'MISSING_REQUIRED_FIELD',
+ 400
+ )
+ }
+ */
+ if (!audience_key) {
+ throw new IntegrationError('Create Audience: missing audience key value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ if (!engage_space_id) {
+ throw new IntegrationError('Create Audience: missing Engage space Id type value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ const input = {
+ segment_audience_id: audience_id,
+ segment_audience_key: audience_key,
+ engage_space_id: engage_space_id,
+ identifier: identifier
+ }
+
+ const body_form_data = gen_segment_subtaxonomy_payload(input)
+
+ const tx_creds = {
+ tx_client_key: createAudienceInput.settings.taxonomy_client_key,
+ tx_client_secret: createAudienceInput.settings.taxonomy_client_secret
+ }
+
+ await update_taxonomy(engage_space_id, tx_creds, request, body_form_data)
+
+ return { externalId: audience_id }
+ },
+ async getAudience(_, getAudienceInput) {
+ const audience_id = getAudienceInput.audienceSettings?.audience_id
+ if (!audience_id) {
+ throw new IntegrationError('Missing audience_id value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+ return { externalId: audience_id }
+ }
+ },
+
+ actions: {
+ updateSegment,
+ createSegment,
+ createCustomerNode
+ }
+}
+export default destination
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/types.ts
new file mode 100644
index 0000000000..962c386d46
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/types.ts
@@ -0,0 +1,27 @@
+export interface CredsObj {
+ tx_client_key: string
+ tx_client_secret: string
+}
+
+export interface TaxonomyObject {
+ id: string
+ name: string
+ description: string
+ users: {
+ include: [string]
+ }
+ subTaxonomy: [
+ {
+ id: string
+ name: string
+ type: string
+ }
+ ]
+}
+
+export interface YahooPayload {
+ schema: Array
+ data: Array
+ gdpr: boolean
+ gdpr_euconsent?: string | undefined
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
new file mode 100644
index 0000000000..b105ca9aa2
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
@@ -0,0 +1,198 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+interface AuthTokens {
+ accessToken: string
+ refreshToken: string
+}
+
+const auth: AuthTokens = {
+ accessToken: 'test',
+ refreshToken: ''
+}
+
+const AUDIENCE_ID = 'aud_12345' // References audienceSettings.audience_id
+const AUDIENCE_KEY = 'sneakers_buyers' // References audienceSettings.audience_key
+const ADVERTISING_ID = 'foobar' // References device.advertisingId
+const ENGAGE_SPACE_ID = 'acme_corp_engage_space' // References settings.engage_space_id
+const MDM_ID = 'mdm 123' // References settings.mdm_id
+const TX_KEY = '123' // References settings.taxonomy_client_id
+const TX_SECRET = '456' // References settings.taxonomy_client_secret
+const CUST_DESC = 'ACME Corp' // References settings.customer_desc
+
+const bad_event = createTestEvent({
+ type: 'identify',
+ traits: {
+ sneakers_buyers: true
+ },
+ context: {
+ traits: {
+ sneakers_buyers: true
+ },
+ personas: {
+ audience_settings: {
+ audience_id: AUDIENCE_ID,
+ audience_key: AUDIENCE_KEY
+ },
+ computation_id: AUDIENCE_ID,
+ computation_key: AUDIENCE_KEY,
+ computation_class: 'audience'
+ }
+ }
+})
+
+describe('YahooAudiences.updateSegment', () => {
+ describe('Success cases', () => {
+ it('should not throw an error if event includes email / maid', async () => {
+ nock(`https://dataxonline.yahoo.com`).post('/online/audience/').reply(200)
+
+ const good_event = createTestEvent({
+ type: 'identify',
+ context: {
+ device: {
+ advertisingId: ADVERTISING_ID
+ },
+ personas: {
+ audience_settings: {
+ audience_id: AUDIENCE_ID,
+ audience_key: AUDIENCE_KEY
+ },
+ computation_id: AUDIENCE_ID,
+ computation_key: AUDIENCE_KEY,
+ computation_class: 'audience'
+ }
+ },
+ traits: {
+ email: 'testing@testing.com',
+ sneakers_buyers: true
+ }
+ })
+
+ const responses = await testDestination.testAction('updateSegment', {
+ auth,
+ event: good_event,
+ mapping: {
+ identifier: 'email_maid'
+ },
+ useDefaultMappings: true,
+ settings: {
+ engage_space_id: ENGAGE_SPACE_ID,
+ mdm_id: MDM_ID,
+ taxonomy_client_key: TX_KEY,
+ taxonomy_client_secret: TX_SECRET,
+ customer_desc: CUST_DESC
+ }
+ })
+
+ // Then
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ })
+ })
+
+ describe('Failure cases', () => {
+ /*
+ it('should fail if credentials are incorrect', async () => {
+ nock(`https://dataxonline.yahoo.com`).post('/online/audience/').reply(401)
+ const response = await testDestination.testAction('updateSegment', {
+ event: good_event,
+ mapping: {},
+ useDefaultMappings: true,
+ settings: {
+ engage_space_id: '123',
+ mdm_id: '234',
+ taxonomy_client_key: '345',
+ taxonomy_client_secret: '456',
+ customer_desc: 'Spacely Sprockets'
+ }
+ })
+
+ // Then
+ expect(response).toHaveLength(1)
+ expect(response[0].status).toBe(401)
+ })
+ */
+ it('should throw an error if audience event missing mandatory "computation_class" field', async () => {
+ const bad_event = createTestEvent({
+ type: 'identify',
+ traits: {
+ sneakers_buyers: true
+ },
+ context: {
+ traits: {
+ sneakers_buyers: true,
+ email: 'joe@doe.com'
+ },
+ personas: {
+ audience_settings: {
+ audience_id: AUDIENCE_ID,
+ audience_key: AUDIENCE_KEY
+ },
+ computation_id: AUDIENCE_ID,
+ computation_key: AUDIENCE_KEY
+ }
+ }
+ })
+ await expect(
+ testDestination.testAction('updateSegment', {
+ event: bad_event,
+ useDefaultMappings: true
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'segment_computation_action'")
+ })
+
+ it('should throw an error if audience key does not match traits object', async () => {
+ const bad_event = createTestEvent({
+ type: 'identify',
+ traits: {
+ sneakers_buyers: true,
+ email: 'joe@doe.com'
+ },
+ context: {
+ personas: {
+ audience_settings: {
+ audience_id: AUDIENCE_ID,
+ audience_key: AUDIENCE_KEY
+ },
+ computation_id: AUDIENCE_ID,
+ computation_key: 'incorrect_audience_key',
+ computation_class: 'audience'
+ }
+ }
+ })
+
+ nock(`https://dataxonline.yahoo.com`).post('/online/audience/').reply(400)
+
+ await expect(
+ testDestination.testAction('syncAudience', {
+ event: bad_event,
+ useDefaultMappings: true
+ })
+ ).rejects.toThrow()
+ })
+
+ it('should throw an error if event does not include email / maid', async () => {
+ nock(`https://dataxonline.yahoo.com`).post('/online/audience/').reply(400)
+
+ await expect(
+ testDestination.testAction('updateSegment', {
+ auth,
+ event: bad_event,
+ mapping: {
+ identifier: 'email_maid'
+ },
+ useDefaultMappings: true,
+ settings: {
+ engage_space_id: ENGAGE_SPACE_ID,
+ mdm_id: MDM_ID,
+ taxonomy_client_key: TX_KEY,
+ taxonomy_client_secret: TX_SECRET,
+ customer_desc: CUST_DESC
+ }
+ })
+ ).rejects.toThrow('Email and / or Advertising Id not available in the profile(s)')
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
new file mode 100644
index 0000000000..6698ba6d84
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
@@ -0,0 +1,54 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Segment Audience Id (aud_...). Maps to "Id" of a Segment node in Yahoo taxonomy
+ */
+ segment_audience_id: string
+ /**
+ * Segment Audience Key. Maps to the "Name" of the Segment node in Yahoo taxonomy
+ */
+ segment_audience_key: string
+ /**
+ * Event traits or properties. Do not modify this setting
+ */
+ event_attributes: {
+ [k: string]: unknown
+ }
+ /**
+ * Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.
+ */
+ segment_computation_action: string
+ /**
+ * Enable batching of requests
+ */
+ enable_batching?: boolean
+ /**
+ * Maximum number of events to include in each batch. Actual batch sizes may be lower.
+ */
+ batch_size?: number
+ /**
+ * Email address of a user
+ */
+ email?: string
+ /**
+ * User's mobile advertising Id
+ */
+ advertising_id?: string
+ /**
+ * User's mobile device type
+ */
+ device_type?: string
+ /**
+ * Specify the identifier(s) to send to Yahoo
+ */
+ identifier: string
+ /**
+ * Set to true to indicate that audience data is subject to GDPR regulations
+ */
+ gdpr_flag: boolean
+ /**
+ * Required if GDPR flag is set to "true". Using IAB Purpose bit descriptions specify the following user consent attributes: "Storage and Access of Information", "Personalization"
+ */
+ gdpr_euconsent?: string
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
new file mode 100644
index 0000000000..d9ca2cb99e
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
@@ -0,0 +1,171 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import { IntegrationError, PayloadValidationError } from '@segment/actions-core'
+import type { Settings, AudienceSettings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { gen_update_segment_payload } from '../utils-rt'
+
+const action: ActionDefinition = {
+ title: 'Sync To Yahoo Ads Segment',
+ description: 'Sync Segment Audience to Yahoo Ads Segment',
+ defaultSubscription: 'type = "identify"',
+ fields: {
+ segment_audience_id: {
+ label: 'Segment Audience Id', // Maps to Yahoo Taxonomy Segment Id
+ description: 'Segment Audience Id (aud_...). Maps to "Id" of a Segment node in Yahoo taxonomy',
+ type: 'hidden',
+ required: true,
+ default: {
+ '@path': '$.context.personas.computation_id'
+ }
+ },
+ segment_audience_key: {
+ label: 'Segment Audience Key',
+ description: 'Segment Audience Key. Maps to the "Name" of the Segment node in Yahoo taxonomy',
+ type: 'hidden',
+ required: true,
+ default: {
+ '@path': '$.context.personas.computation_key'
+ }
+ },
+ // Fetch event traits or props, which will be used to determine user's membership in an audience
+ event_attributes: {
+ label: 'Event traits or properties. Do not modify this setting',
+ description: 'Event traits or properties. Do not modify this setting',
+ type: 'object',
+ readOnly: true,
+ required: true,
+ default: {
+ '@if': {
+ exists: { '@path': '$.properties' },
+ then: { '@path': '$.properties' },
+ else: { '@path': '$.traits' }
+ }
+ }
+ },
+ segment_computation_action: {
+ label: 'Segment Computation Action',
+ description:
+ "Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.",
+ type: 'hidden',
+ required: true,
+ default: {
+ '@path': '$.context.personas.computation_class'
+ },
+ choices: [{ label: 'audience', value: 'audience' }]
+ },
+ enable_batching: {
+ label: 'Enable Batching',
+ description: 'Enable batching of requests',
+ type: 'boolean', // We should always batch Yahoo requests
+ default: true,
+ unsafe_hidden: true
+ },
+ batch_size: {
+ label: 'Batch Size',
+ description: 'Maximum number of events to include in each batch. Actual batch sizes may be lower.',
+ type: 'number',
+ unsafe_hidden: true,
+ default: 1000
+ },
+ email: {
+ label: 'User Email',
+ description: 'Email address of a user',
+ type: 'hidden',
+ required: false,
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.email' },
+ then: { '@path': '$.traits.email' },
+ else: { '@path': '$.properties.email' }
+ }
+ }
+ },
+ advertising_id: {
+ label: 'User Mobile Advertising ID',
+ description: "User's mobile advertising Id",
+ type: 'hidden',
+ default: {
+ '@path': '$.context.device.advertisingId'
+ },
+ required: false
+ },
+ device_type: {
+ label: 'User Mobile Device Type', // This field is required to determine the type of the advertising Id: IDFA or GAID
+ description: "User's mobile device type",
+ type: 'hidden',
+ default: {
+ '@path': '$.context.device.type'
+ },
+ required: false
+ },
+ identifier: {
+ label: 'User Identifier',
+ description: 'Specify the identifier(s) to send to Yahoo',
+ type: 'string',
+ required: true,
+ default: 'email',
+ choices: [
+ { value: 'email', label: 'Send email' },
+ { value: 'maid', label: 'Send MAID' },
+ { value: 'email_maid', label: 'Send email and/or MAID' }
+ ]
+ },
+ gdpr_flag: {
+ label: 'GDPR Flag',
+ description: 'Set to true to indicate that audience data is subject to GDPR regulations',
+ type: 'boolean',
+ required: true,
+ default: false
+ },
+ gdpr_euconsent: {
+ label: 'GDPR Consent Attributes',
+ description:
+ 'Required if GDPR flag is set to "true". Using IAB Purpose bit descriptions specify the following user consent attributes: "Storage and Access of Information", "Personalization"',
+ type: 'string',
+ required: false
+ }
+ },
+
+ perform: (request, { payload, auth, audienceSettings }) => {
+ const rt_access_token = auth?.accessToken
+
+ if (!audienceSettings) {
+ throw new IntegrationError('Bad Request: no audienceSettings found.', 'INVALID_REQUEST_DATA', 400)
+ }
+ const body = gen_update_segment_payload([payload], audienceSettings)
+ // Send request to Yahoo only when the event includes selected Ids
+ if (body.data.length > 0) {
+ return request('https://dataxonline.yahoo.com/online/audience/', {
+ method: 'POST',
+ json: body,
+ headers: {
+ Authorization: `Bearer ${rt_access_token}`
+ }
+ })
+ } else {
+ throw new PayloadValidationError('Email and / or Advertising Id not available in the profile(s)')
+ }
+ },
+ performBatch: (request, { payload, audienceSettings, auth }) => {
+ const rt_access_token = auth?.accessToken
+
+ if (!audienceSettings) {
+ throw new IntegrationError('Bad Request: no audienceSettings found.', 'INVALID_REQUEST_DATA', 400)
+ }
+ const body = gen_update_segment_payload(payload, audienceSettings)
+ // Send request to Yahoo only when all events in the batch include selected Ids
+ if (body.data.length > 0) {
+ return request('https://dataxonline.yahoo.com/online/audience/', {
+ method: 'POST',
+ json: body,
+ headers: {
+ Authorization: `Bearer ${rt_access_token}`
+ }
+ })
+ } else {
+ throw new PayloadValidationError('Email and / or Advertising Id not available in the profile(s)')
+ }
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts b/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
new file mode 100644
index 0000000000..67e397c08c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
@@ -0,0 +1,154 @@
+import { createHmac, createHash } from 'crypto'
+import { Payload } from './updateSegment/generated-types'
+import { YahooPayload } from './types'
+import { gen_random_id } from './utils-tax'
+import { AudienceSettings } from './generated-types'
+
+/**
+ * Creates a SHA256 hash from the input
+ * @param input The input string
+ * @returns The SHA256 hash (string), or undefined if the input is undefined.
+ */
+export function create_hash(input: string | undefined): string | undefined {
+ if (input === undefined) return
+ return createHash('sha256').update(input).digest('hex')
+}
+
+/**
+ * Generates JWT for Realtime API authentication
+ * @param client_id
+ * @param client_secret
+ * @returns The JWT token
+ */
+export function generate_jwt(client_id: string, client_secret: string): string {
+ const random_id = gen_random_id(24)
+ const current_time = Math.floor(new Date().getTime() / 1000)
+ const url = 'https://id.b2b.yahooinc.com/identity/oauth2/access_token'
+ const jwt_payload = {
+ iss: client_id,
+ sub: client_id,
+ aud: url + '?realm=dataxonline',
+ jti: random_id,
+ exp: current_time + 3600,
+ iat: current_time
+ }
+ const jwt_header = {
+ alg: 'HS256',
+ typ: 'JWT'
+ }
+
+ const jwt_header_encoded = Buffer.from(JSON.stringify(jwt_header)).toString('base64')
+ const jwt_payload_encoded = Buffer.from(JSON.stringify(jwt_payload)).toString('base64')
+ const jwt_head_payload = jwt_header_encoded + '.' + jwt_payload_encoded
+
+ const hash = createHmac('sha256', client_secret)
+ const signature = hash.update(jwt_head_payload).digest('base64')
+ const jwt = jwt_head_payload + '.' + signature
+
+ return jwt
+}
+
+/**
+ * Gets the definition to send the hashed email or advertising ID.
+ * @param payload The payload.
+ * @returns {{ maid: boolean; email: boolean }} The definitions object (id_schema).
+ */
+export function get_id_schema(payload: Payload, audienceSettings: AudienceSettings): { maid: boolean; email: boolean } {
+ const schema = {
+ email: false,
+ maid: false
+ }
+ let id_type
+ audienceSettings.identifier ? (id_type = audienceSettings.identifier) : (id_type = payload.identifier)
+ if (id_type == 'email') {
+ schema.email = true
+ }
+ if (id_type == 'maid') {
+ schema.maid = true
+ }
+ if (id_type == 'email_maid') {
+ schema.maid = true
+ schema.email = true
+ }
+ return schema
+ // return {
+ // maid: payload.send_advertising_id === true,
+ // email: payload.send_email === true
+ // }
+}
+
+/**
+ * Validates the payload schema.
+ * If both `Send Email` and `Send Advertising ID` are set to `false`, an error is thrown.
+ * @param payload The payload.
+ */
+// Switched over to a 'choice' field, so this function is no longer required
+// export function check_schema(payload: Payload): void {
+// payload.identifier
+// if (payload.send_email === false && payload.send_advertising_id === false) {
+// throw new IntegrationError(
+// 'Either `Send Email`, or `Send Advertising ID` setting must be set to `true`.',
+// 'INVALID_SETTINGS',
+// 400
+// )
+// }
+// }
+
+/**
+ * The ID schema defines whether the payload should contain the
+ * hashed advertising ID for iOS or Android, or the hashed email.
+ * @param payloads
+ * @returns {YahooPayload} The Yahoo payload.
+ */
+export function gen_update_segment_payload(payloads: Payload[], audienceSettings: AudienceSettings): YahooPayload {
+ const schema = get_id_schema(payloads[0], audienceSettings)
+ const data = []
+ for (const event of payloads) {
+ let hashed_email: string | undefined = ''
+ if (schema.email === true && event.email) {
+ hashed_email = create_hash(event.email)
+ }
+ let idfa: string | undefined = ''
+ let gpsaid: string | undefined = ''
+ if (schema.maid === true && event.advertising_id) {
+ switch (event.device_type) {
+ case 'ios':
+ idfa = event.advertising_id
+ break
+ case 'android':
+ gpsaid = event.advertising_id
+ break
+ }
+ }
+
+ if (hashed_email == '' && idfa == '' && gpsaid == '') {
+ continue
+ }
+ const ts = Math.floor(new Date().getTime() / 1000)
+ const seg_key = event.segment_audience_key
+ let exp
+ // When a user enters an audience - set expiration ts to now() + 90 days
+ if (event.event_attributes[seg_key] === true) {
+ exp = ts + 90 * 24 * 60 * 60
+ }
+ // When a user exits an audience - set expiration ts to 0
+ if (event.event_attributes[seg_key] === false) {
+ exp = 0
+ }
+
+ const seg_id = event.segment_audience_id
+ data.push([hashed_email, idfa, gpsaid, 'exp=' + exp + '&seg_id=' + seg_id + '&ts=' + ts])
+ }
+
+ const yahoo_payload: YahooPayload = {
+ schema: ['SHA256EMAIL', 'IDFA', 'GPADVID', 'SEGMENTS'],
+ data: data,
+ gdpr: payloads[0].gdpr_flag
+ }
+
+ if (payloads[0].gdpr_flag) {
+ yahoo_payload.gdpr_euconsent = payloads[0].gdpr_euconsent
+ }
+
+ return yahoo_payload
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
new file mode 100644
index 0000000000..296fd0f9b1
--- /dev/null
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
@@ -0,0 +1,107 @@
+import { Payload as SegmentNodePayload } from './createSegment/generated-types'
+import { Payload as CustomerNodePayload } from './createCustomerNode/generated-types'
+import type { Settings } from './generated-types'
+import { createHmac } from 'crypto'
+import { CredsObj } from './types'
+import { RequestClient, IntegrationError } from '@segment/actions-core'
+
+export function gen_customer_taxonomy_payload(settings: Settings, payload: CustomerNodePayload) {
+ const data = {
+ id: payload.engage_space_id,
+ name: payload.engage_space_id,
+ description: payload.customer_desc,
+ users: {
+ include: [settings.mdm_id]
+ }
+ }
+ // Form data must be delimited with CRLF = /r/n: RFC https://www.rfc-editor.org/rfc/rfc7578#section-4.1
+ const req_body_form = `--SEGMENT-DATA\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n{ "description" : "${
+ payload.customer_desc
+ }" }\r\n--SEGMENT-DATA\r\nContent-Disposition: form-data; name="data"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n${JSON.stringify(
+ data
+ )}\r\n--SEGMENT-DATA--`
+ return req_body_form
+}
+
+export function gen_segment_subtaxonomy_payload(payload: SegmentNodePayload) {
+ const data = {
+ id: payload.segment_audience_id,
+ name: payload.segment_audience_key,
+ type: 'SEGMENT'
+ }
+ const req_body_form = `--SEGMENT-DATA\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n{ "description" : "${
+ payload.customer_desc
+ }" }\r\n--SEGMENT-DATA\r\nContent-Disposition: form-data; name="data"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n${JSON.stringify(
+ data
+ )}\r\n--SEGMENT-DATA--`
+ return req_body_form
+}
+
+export function gen_random_id(length: number): string {
+ const pattern = 'abcdefghijklmnopqrstuvwxyz123456789'
+ const random_id: string[] = []
+ for (let i = 0; i < length; i++) {
+ random_id.push(pattern[Math.floor(Math.random() * pattern.length)])
+ }
+ return random_id.join('')
+}
+
+export function gen_oauth1_signature(client_key: string, client_secret: string, method: string, url: string) {
+ // Following logic in #9 https://oauth.net/core/1.0a/#sig_norm_param
+ const timestamp = Math.floor(new Date().getTime() / 1000)
+ const nonce = gen_random_id(15)
+
+ const param_string = `oauth_consumer_key=${encodeURIComponent(client_key)}&oauth_nonce=${encodeURIComponent(
+ nonce
+ )}&oauth_signature_method=${encodeURIComponent('HMAC-SHA1')}&oauth_timestamp=${encodeURIComponent(
+ timestamp
+ )}&oauth_version=${encodeURIComponent('1.0')}`
+
+ const base_string = `${method.toUpperCase()}&${encodeURIComponent(url)}&${encodeURIComponent(param_string)}`
+ const encoded_client_secret = encodeURIComponent(client_secret)
+ const signature = encodeURIComponent(
+ createHmac('sha1', encoded_client_secret + '&')
+ .update(base_string)
+ .digest('base64')
+ )
+ const oauth1_auth_string = `OAuth oauth_consumer_key="${client_key}", oauth_nonce="${nonce}", oauth_signature="${signature}", oauth_signature_method="HMAC-SHA1", oauth_timestamp="${timestamp}", oauth_version="1.0"`
+ return oauth1_auth_string
+}
+
+export async function update_taxonomy(
+ engage_space_id: string,
+ tx_creds: CredsObj,
+ request: RequestClient,
+ body_form_data: string
+) {
+ const tx_client_secret = tx_creds.tx_client_secret
+ const tx_client_key = tx_creds.tx_client_key
+ const url = `https://datax.yahooapis.com/v1/taxonomy/append${engage_space_id.length > 0 ? '/' + engage_space_id : ''}`
+ const oauth1_auth_string = gen_oauth1_signature(tx_client_key, tx_client_secret, 'PUT', url)
+ try {
+ const add_segment_node = await request(url, {
+ method: 'PUT',
+ body: body_form_data,
+ headers: {
+ Authorization: oauth1_auth_string,
+ 'Content-Type': 'multipart/form-data; boundary=SEGMENT-DATA'
+ }
+ })
+ return await add_segment_node.json()
+ } catch (error) {
+ const _error = error as { response: { data: unknown; status: string } }
+ // If Taxonomy API returned 401, throw Integration error w/status 400 to prevent refreshAccessToken from firing
+ // Otherwise throw the orifinal error
+ if (parseInt(_error.response.status) == 401) {
+ throw new IntegrationError(
+ `Error while updating taxonomy: ${JSON.stringify(_error.response.data)} ${
+ _error.response.status
+ }. Validate Yahoo credentials`,
+ 'YAHOO_TAXONOMY_API_AUTH_ERR',
+ 400
+ )
+ } else {
+ throw error
+ }
+ }
+}
From 3ef6f30ab682463415f5eb1be5f026638c17a279 Mon Sep 17 00:00:00 2001
From: Ryan Rouleau
Date: Tue, 3 Oct 2023 09:23:31 -0400
Subject: [PATCH 013/389] Track s3 call (#1600)
---
.../engage/sendgrid/sendEmail/SendEmailPerformer.ts | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/packages/destination-actions/src/destinations/engage/sendgrid/sendEmail/SendEmailPerformer.ts b/packages/destination-actions/src/destinations/engage/sendgrid/sendEmail/SendEmailPerformer.ts
index b2068fae2d..7a73a98205 100644
--- a/packages/destination-actions/src/destinations/engage/sendgrid/sendEmail/SendEmailPerformer.ts
+++ b/packages/destination-actions/src/destinations/engage/sendgrid/sendEmail/SendEmailPerformer.ts
@@ -94,6 +94,7 @@ export class SendEmailPerformer extends MessageSendPerformer
this.logOnError(() => 'Content type: ' + contentType)
return parsedContent
}
+
async sendToRecepient(emailProfile: ExtId) {
const traits = await this.getProfileTraits()
@@ -211,6 +212,12 @@ export class SendEmailPerformer extends MessageSendPerformer
return response
}
+ @track()
+ async getBodyTemplateFromS3(bodyUrl: string) {
+ const { content } = await this.request(bodyUrl, { method: 'GET', skipResponseCloning: true })
+ return content
+ }
+
@track()
async getBodyHtml(
profile: Profile,
@@ -228,7 +235,7 @@ export class SendEmailPerformer extends MessageSendPerformer
) {
let parsedBodyHtml
if (this.payload.bodyUrl && this.settings.unlayerApiKey) {
- const { content: body } = await this.request(this.payload.bodyUrl, { method: 'GET', skipResponseCloning: true })
+ const body = await this.getBodyTemplateFromS3(this.payload.bodyUrl)
const bodyHtml = this.payload.bodyType === 'html' ? body : await this.generateEmailHtml(body)
parsedBodyHtml = await this.parseTemplating(bodyHtml, { profile, [apiLookupLiquidKey]: apiLookupData }, 'Body')
} else {
From f3c9b8ca15425f51664690f13b287b4a11cf23e1 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 3 Oct 2023 16:22:13 +0200
Subject: [PATCH 014/389] Registering hyperengage
Registering hyperengage Destination
---
packages/destination-actions/src/destinations/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index 8b394ca887..570498c125 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -130,6 +130,7 @@ register('64f703d1f6e9aa0a283ae3e2', './absmartly')
register('6514281004d549fae3fd086a', './yahoo-audiences')
register('650bdf1a62fb34ef0a8058e1', './klaviyo')
register('6512d7f86bdccc3829fc4ac3', './optimizely-data-platform')
+register('651c1db19de92d8e595ff55d', './hyperengage')
function register(id: MetadataId, destinationPath: string) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
From fa3afde967611b4b689a4120ec6927404d373485 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 3 Oct 2023 15:23:55 +0100
Subject: [PATCH 015/389] Publish
- @segment/action-destinations@3.220.0
---
packages/destination-actions/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 89d5329e41..8612b95020 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.219.0",
+ "version": "3.220.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
From 4b31c5b5cbb9164afde1a7730909a518a9170930 Mon Sep 17 00:00:00 2001
From: rhall-twilio <103517471+rhall-twilio@users.noreply.github.com>
Date: Thu, 5 Oct 2023 11:33:54 -0400
Subject: [PATCH 016/389] remove timestamp from LiveRamp filename default
(#1633)
---
.../audienceEnteredS3/index.ts | 2 +-
.../audienceEnteredSFTP.types.ts | 48 -------------------
.../audienceEnteredSftp/index.ts | 2 +-
3 files changed, 2 insertions(+), 50 deletions(-)
delete mode 100644 packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredS3/index.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredS3/index.ts
index 65042a2dd8..4d23f52698 100644
--- a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredS3/index.ts
+++ b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredS3/index.ts
@@ -67,7 +67,7 @@ const action: ActionDefinition = {
description: `Name of the CSV file to upload for LiveRamp ingestion.`,
type: 'string',
required: true,
- default: { '@template': '{{properties.audience_key}}_PII_{{timestamp}}.csv' }
+ default: { '@template': '{{properties.audience_key}}.csv' }
},
enable_batching: {
type: 'boolean',
diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
deleted file mode 100644
index dde35bd23f..0000000000
--- a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSFTP.types.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-// Generated file. DO NOT MODIFY IT BY HAND.
-
-export interface Payload {
- /**
- * User credentials for establishing an SFTP connection with LiveRamp.
- */
- sftp_username?: string
- /**
- * User credentials for establishing an SFTP connection with LiveRamp.
- */
- sftp_password?: string
- /**
- * Path within the LiveRamp SFTP server to upload the files to. This path must exist and all subfolders must be pre-created.
- */
- sftp_folder_path?: string
- /**
- * Unique ID that identifies members of an audience. A typical audience key might be client customer IDs, email addresses, or phone numbers.
- */
- audience_key: string
- /**
- * Additional data pertaining to the user to be written to the file.
- */
- identifier_data?: {
- [k: string]: unknown
- }
- /**
- * Additional data pertaining to the user to be hashed before written to the file. Use field name **phone_number** or **email** to apply LiveRamp's specific hashing rules.
- */
- unhashed_identifier_data?: {
- [k: string]: unknown
- }
- /**
- * Character used to separate tokens in the resulting file.
- */
- delimiter: string
- /**
- * Name of the CSV file to upload for LiveRamp ingestion.
- */
- filename: string
- /**
- * Receive events in a batch payload. This is required for LiveRamp audiences ingestion.
- */
- enable_batching: boolean
- /**
- * Maximum number of events to include in each batch. Actual batch sizes may be lower.
- */
- batch_size?: number
-}
diff --git a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSftp/index.ts b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSftp/index.ts
index 6c4dc9cdad..83dd6b7296 100644
--- a/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSftp/index.ts
+++ b/packages/destination-actions/src/destinations/liveramp-audiences/audienceEnteredSftp/index.ts
@@ -65,7 +65,7 @@ const action: ActionDefinition = {
description: `Name of the CSV file to upload for LiveRamp ingestion.`,
type: 'string',
required: true,
- default: { '@template': '{{properties.audience_key}}_PII_{{timestamp}}.csv' }
+ default: { '@template': '{{properties.audience_key}}_PII.csv' }
},
enable_batching: {
type: 'boolean',
From 34fbab66f3fd9fceba6e86242a6e6aba33d821c6 Mon Sep 17 00:00:00 2001
From: Elena
Date: Thu, 5 Oct 2023 13:06:00 -0700
Subject: [PATCH 017/389] Yahoo audiences 2 (#1636)
* scaffold files and folders
* updated yahoo integration
* Comments and some fixes.
* Updating definition to have `createSegment` action.
* modified mappings
* updateStatus fix
* Added new action createCustomerNode
Code clean up, extra console.logs for testing
* Yahoo: prep for Staging
* Yahoo: minor fixes
* Yahoo: gdpr support
* Yahoo: added validation that incoming event is Audience update, removed unnecessary logging
* Removing repeated code, improving JSDoc.
* Unifying `updateTaxonomy` calls.
* - `await/try/catch` instead of chained promises;
- Missing `BASE_URL` as constant.
* Yahoo: added createAudience, testAuthentication, updated settings
* Yahoo: async func call fix
* attempting to get project to build
* registering yahoo-audiences
* Adding Destination description
* Adding missing description to Action
* Setting enable_batching field to be boolean
* Setting enable_batching setting to be boolean
* Yahoo: handling errors from taxonomy API
* Yahoo: modifier err handling
* Unit test for `YahooAudiences.updateSegment`.
* Success and failure cases for `YahooAudiences.updateSegment`.
* Unit tests for `createAudience` in Yahoo Audiences.
* Yahoo: removed duplicate file
* Yahoo: updateSegment action changes - added Identifier selector, Yahoo payload checks, set action fields 'required' status to false where needed
* Yahoo: updated audienceSettings
* Yahoo: added more unit tests, added support of preferred identifier in 'audienceSettings' with a fallback to an identifier fetched from the action
* Yahoo: added check of audience_id
* Fixing unit tests.
* Yahoo: minor fixes
* Yahoo: cleaned up comments, console.log
* Snapshots don't make sense here: we have two endpoints. One of them uses OAuth1, which gets a new nonce every time the API is called.
* Removing unnecessary `else`s.
* Yahoo: Taxonomy API auth change
* Yahoo: unit tests
* deleting actions
---------
Co-authored-by: Jina Park
Co-authored-by: Elena Parshina
Co-authored-by: Leonel Sanches <113376080+seg-leonelsanches@users.noreply.github.com>
Co-authored-by: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
---
README.md | 1 +
.../src/destinations/airship/utilities.ts | 5 +-
.../__tests__/index.test.ts | 1 -
.../__tests__/snapshot.test.ts | 8 +-
.../emailEvent/__tests__/snapshot.test.ts | 8 +-
.../upsertContact/__tests__/index.test.ts | 4 +-
.../upsertContact/__tests__/snapshot.test.ts | 10 +--
.../_tests_/index.test.ts | 4 +-
.../yahoo-audiences/__tests__/index.test.ts | 12 +--
.../__tests__/index.test.ts | 23 ------
.../createCustomerNode/generated-types.ts | 12 ---
.../createCustomerNode/index.ts | 37 ----------
.../createSegment/__tests__/index.test.ts | 24 ------
.../createSegment/generated-types.ts | 20 -----
.../yahoo-audiences/createSegment/index.ts | 53 -------------
.../yahoo-audiences/generated-types.ts | 8 --
.../src/destinations/yahoo-audiences/index.ts | 74 ++++++-------------
.../src/destinations/yahoo-audiences/types.ts | 7 ++
.../updateSegment/__tests__/index.test.ts | 6 --
.../yahoo-audiences/updateSegment/index.ts | 1 -
.../destinations/yahoo-audiences/utils-tax.ts | 20 +++--
21 files changed, 62 insertions(+), 276 deletions(-)
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
delete mode 100644 packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
diff --git a/README.md b/README.md
index 145bd84c09..f666d4255b 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# Action Destinations
+
Action Destinations are the new way to build streaming destinations on Segment.
Action Destinations were [launched in December 2021](https://segment.com/blog/introducing-destination-actions/) to enable customers with a customizable framework to map Segment event sources to their favorite 3rd party tools like Google Analytics.
diff --git a/packages/destination-actions/src/destinations/airship/utilities.ts b/packages/destination-actions/src/destinations/airship/utilities.ts
index 9a0bcf79e0..23ac196c24 100644
--- a/packages/destination-actions/src/destinations/airship/utilities.ts
+++ b/packages/destination-actions/src/destinations/airship/utilities.ts
@@ -230,8 +230,8 @@ function _build_attribute(attribute_key: string, attribute_value: any, occurred:
adjustedDate = _parse_date(attribute_value)
}
- if (['home_phone', 'work_phone', 'mobile_phone'].includes(attribute_key) && typeof(attribute_value) == "string") {
- attribute_value = parseInt(attribute_value.replace(/[^0-9]/g, ""))
+ if (['home_phone', 'work_phone', 'mobile_phone'].includes(attribute_key) && typeof attribute_value == 'string') {
+ attribute_value = parseInt(attribute_value.replace(/[^0-9]/g, ''))
}
const attribute: {
@@ -257,7 +257,6 @@ function _build_attribute(attribute_key: string, attribute_value: any, occurred:
return attribute
}
-
function _build_tags_object(payload: TagsPayload): object {
/*
This function takes a Group event and builds a Tag payload. It assumes values are booleans
diff --git a/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/index.test.ts b/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/index.test.ts
index 6470dfa403..dfc0039843 100644
--- a/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/index.test.ts
@@ -6,7 +6,6 @@ const testDestination = createTestIntegration(Definition)
describe('Optimizely Data Platform', () => {
describe('testAuthentication', () => {
-
it('should validate authentication inputs', async () => {
nock('https://function.zaius.app/twilio_segment').post('/auth').reply(200)
diff --git a/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/snapshot.test.ts
index 99e7dce990..236bc581aa 100644
--- a/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/snapshot.test.ts
+++ b/packages/destination-actions/src/destinations/optimizely-data-platform/__tests__/snapshot.test.ts
@@ -21,8 +21,8 @@ describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
const responses = await testDestination.testAction(actionSlug, {
event: event,
@@ -58,8 +58,8 @@ describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
const responses = await testDestination.testAction(actionSlug, {
event: event,
diff --git a/packages/destination-actions/src/destinations/optimizely-data-platform/emailEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/optimizely-data-platform/emailEvent/__tests__/snapshot.test.ts
index 740296081a..1537860449 100644
--- a/packages/destination-actions/src/destinations/optimizely-data-platform/emailEvent/__tests__/snapshot.test.ts
+++ b/packages/destination-actions/src/destinations/optimizely-data-platform/emailEvent/__tests__/snapshot.test.ts
@@ -21,8 +21,8 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
const responses = await testDestination.testAction(actionSlug, {
event: event,
@@ -57,8 +57,8 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
const responses = await testDestination.testAction(actionSlug, {
event: event,
diff --git a/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/index.test.ts b/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/index.test.ts
index 5874606c65..1a20294adc 100644
--- a/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/index.test.ts
@@ -40,9 +40,9 @@ describe('OptimizelyDataPlatform.upsertContact', () => {
useDefaultMappings: true
})
- const expectedBody = `"{\\"user_identifiers\\":{\\"anonymousId\\":\\"anonId1234\\",\\"userId\\":\\"user1234\\",\\"email\\":\\"test.email@test.com\\"},\\"title\\":\\"Mr\\",\\"name\\":\\"John Doe\\",\\"first_name\\":\\"John\\",\\"last_name\\":\\"Doe\\",\\"age\\":50,\\"dob\\":\\"01/01/1990\\",\\"gender\\":\\"male\\",\\"phone\\":\\"1234567890\\",\\"address\\":{\\"street\\":\\"Victoria st\\",\\"city\\":\\"London\\",\\"state\\":\\"London\\",\\"country\\":\\"UK\\"},\\"company\\":\\"Optimizely\\",\\"image_url\\":\\"https://image-url.com\\"}"`;
+ const expectedBody = `"{\\"user_identifiers\\":{\\"anonymousId\\":\\"anonId1234\\",\\"userId\\":\\"user1234\\",\\"email\\":\\"test.email@test.com\\"},\\"title\\":\\"Mr\\",\\"name\\":\\"John Doe\\",\\"first_name\\":\\"John\\",\\"last_name\\":\\"Doe\\",\\"age\\":50,\\"dob\\":\\"01/01/1990\\",\\"gender\\":\\"male\\",\\"phone\\":\\"1234567890\\",\\"address\\":{\\"street\\":\\"Victoria st\\",\\"city\\":\\"London\\",\\"state\\":\\"London\\",\\"country\\":\\"UK\\"},\\"company\\":\\"Optimizely\\",\\"image_url\\":\\"https://image-url.com\\"}"`
- expect(response[0].status).toBe(201);
+ expect(response[0].status).toBe(201)
expect(response[0].options.body).toMatchInlineSnapshot(expectedBody)
})
})
diff --git a/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/snapshot.test.ts
index c570c53896..b75f60da83 100644
--- a/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/snapshot.test.ts
+++ b/packages/destination-actions/src/destinations/optimizely-data-platform/upsertContact/__tests__/snapshot.test.ts
@@ -21,8 +21,8 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
const responses = await testDestination.testAction(actionSlug, {
event: event,
@@ -57,9 +57,9 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
properties: eventData
})
- settingsData['apiKey'] = 'abc123';
- settingsData['region'] = 'US';
-
+ settingsData['apiKey'] = 'abc123'
+ settingsData['region'] = 'US'
+
const responses = await testDestination.testAction(actionSlug, {
event: event,
mapping: event.properties,
diff --git a/packages/destination-actions/src/destinations/snap-conversions-api/_tests_/index.test.ts b/packages/destination-actions/src/destinations/snap-conversions-api/_tests_/index.test.ts
index b46cd9eadf..77d6e9313e 100644
--- a/packages/destination-actions/src/destinations/snap-conversions-api/_tests_/index.test.ts
+++ b/packages/destination-actions/src/destinations/snap-conversions-api/_tests_/index.test.ts
@@ -32,8 +32,8 @@ const testEvent = createTestEvent({
const conversionEventUrl = 'https://tr.snapchat.com/v2/conversion'
beforeEach(() => {
- nock.cleanAll(); // Clear all Nock interceptors and filters
-});
+ nock.cleanAll() // Clear all Nock interceptors and filters
+})
describe('Snap Conversions API ', () => {
describe('ReportConversionEvent', () => {
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
index 56b7a06ba2..91a368a99b 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
@@ -7,16 +7,12 @@ const AUDIENCE_ID = 'aud_123456789012345678901234567' // References audienceSett
const AUDIENCE_KEY = 'sneakers_buyers' // References audienceSettings.audience_key
const ENGAGE_SPACE_ID = 'acme_corp_engage_space' // References settings.engage_space_id
const MDM_ID = 'mdm 123' // References settings.mdm_id
-const TX_KEY = '123' // References settings.taxonomy_client_id
-const TX_SECRET = '456' // References settings.taxonomy_client_secret
const CUST_DESC = 'ACME Corp' // References settings.customer_desc
const createAudienceInput = {
settings: {
engage_space_id: ENGAGE_SPACE_ID,
mdm_id: MDM_ID,
- taxonomy_client_key: TX_KEY,
- taxonomy_client_secret: TX_SECRET,
customer_desc: CUST_DESC
},
audienceName: '',
@@ -35,7 +31,7 @@ describe('Yahoo Audiences', () => {
})
describe('Success cases', () => {
- it('It should create the audience successfully', async () => {
+ it.skip('It should create the audience successfully', async () => {
nock('https://datax.yahooapis.com').put(`/v1/taxonomy/append/${ENGAGE_SPACE_ID}`).reply(202, {
anything: '123'
})
@@ -45,21 +41,21 @@ describe('Yahoo Audiences', () => {
})
})
describe('Failure cases', () => {
- it('should throw an error when audience_id setting is missing', async () => {
+ it.skip('should throw an error when audience_id setting is missing', async () => {
createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
createAudienceInput.audienceSettings.audience_id = ''
await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
})
- it('should throw an error when audience_key setting is missing', async () => {
+ it.skip('should throw an error when audience_key setting is missing', async () => {
createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
createAudienceInput.audienceSettings.audience_key = ''
createAudienceInput.audienceSettings.audience_id = 'aud_12345'
await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
})
- it('should throw an error when engage_space_id setting is missing', async () => {
+ it.skip('should throw an error when engage_space_id setting is missing', async () => {
createAudienceInput.settings.engage_space_id = ''
createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
createAudienceInput.audienceSettings.audience_id = 'aud_123456789012345678901234567'
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
deleted file mode 100644
index d77214c3a3..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/__tests__/index.test.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import nock from 'nock'
-import { createTestEvent, createTestIntegration } from '@segment/actions-core'
-import Destination from '../../index'
-
-const testDestination = createTestIntegration(Destination)
-
-describe('YahooAudiences.createCustomerNode', () => {
- it.skip('should pull yahoo taxonomy', async () => {
- const event = createTestEvent()
- nock(`https://datax.yahooapis.com/v1/taxonomy/append`)
- .post(event as any)
- .reply(200)
-
- const responses = await testDestination.testAction('createCustomerNode', {
- event,
- mapping: {},
- useDefaultMappings: true
- })
-
- expect(responses.length).toBe(1)
- expect(responses[0].status).toBe(200)
- })
-})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
deleted file mode 100644
index 2ddeeb41ba..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/generated-types.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-// Generated file. DO NOT MODIFY IT BY HAND.
-
-export interface Payload {
- /**
- * Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy
- */
- engage_space_id: string
- /**
- * Provide a description for the Customer node in Yahoo taxonomy. This must be less then 1000 characters
- */
- customer_desc?: string
-}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
deleted file mode 100644
index 0d283f4a5b..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createCustomerNode/index.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-import type { ActionDefinition } from '@segment/actions-core'
-import type { Settings } from '../generated-types'
-import type { Payload } from './generated-types'
-import { gen_customer_taxonomy_payload } from '../utils-tax'
-import { update_taxonomy } from '../utils-tax'
-
-const action: ActionDefinition = {
- title: 'Create top-level CUSTOMER node in Yahoo taxonomy',
- defaultSubscription: 'event = "Audience Entered" and event = "Audience Exited"',
- description: 'Create top-level CUSTOMER node in Yahoo taxonomy',
- fields: {
- engage_space_id: {
- label: 'Engage Space Id',
- description:
- 'Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy',
- type: 'string',
- required: true
- },
- customer_desc: {
- label: 'Customer Description',
- description:
- 'Provide a description for the Customer node in Yahoo taxonomy. This must be less then 1000 characters',
- type: 'string',
- required: false
- }
- },
- perform: async (request, { settings, payload }) => {
- const tx_creds = {
- tx_client_key: settings.taxonomy_client_key,
- tx_client_secret: settings.taxonomy_client_secret
- }
- const taxonomy_payload = gen_customer_taxonomy_payload(settings, payload)
- return await update_taxonomy('', tx_creds, request, taxonomy_payload)
- }
-}
-
-export default action
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
deleted file mode 100644
index 0504084195..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/__tests__/index.test.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import nock from 'nock'
-import { createTestEvent, createTestIntegration } from '@segment/actions-core'
-import Destination from '../../index'
-import { TAXONOMY_BASE_URL } from '../../constants'
-
-const testDestination = createTestIntegration(Destination)
-
-describe('YahooAudiences.createSegment', () => {
- it.skip('should pull yahoo taxonomy', async () => {
- const event = createTestEvent()
- nock(`${TAXONOMY_BASE_URL}/v1/taxonomy`)
- .post(event as any)
- .reply(200)
-
- const responses = await testDestination.testAction('createSegment', {
- event,
- mapping: {},
- useDefaultMappings: true
- })
-
- expect(responses.length).toBe(1)
- expect(responses[0].status).toBe(200)
- })
-})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
deleted file mode 100644
index 931a2e1faa..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/generated-types.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-// Generated file. DO NOT MODIFY IT BY HAND.
-
-export interface Payload {
- /**
- * Provide audience key. This maps to the "Name" of the Segment node in Yahoo taxonomy
- */
- segment_audience_key: string
- /**
- * Provide audience Id (aud_...) from audience URL in Segment Engage. This maps to the "Id" of the Segment node in Yahoo taxonomy
- */
- segment_audience_id: string
- /**
- * Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy and specifies the parent node for your Segment node in Yahoo taxonomy
- */
- engage_space_id?: string
- /**
- * Provide the description for Segment node in Yahoo taxonomy. This must be less then 1000 characters
- */
- customer_desc?: string
-}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
deleted file mode 100644
index 3349b15284..0000000000
--- a/packages/destination-actions/src/destinations/yahoo-audiences/createSegment/index.ts
+++ /dev/null
@@ -1,53 +0,0 @@
-import type { ActionDefinition } from '@segment/actions-core'
-
-import type { Settings } from '../generated-types'
-import type { Payload } from './generated-types'
-import { gen_segment_subtaxonomy_payload } from '../utils-tax'
-import { update_taxonomy } from '../utils-tax'
-/* Generates a Segment in Yahoo Taxonomy */
-
-const action: ActionDefinition = {
- title: 'Create SEGMENT sub-node in Yahoo taxonomy',
- description: 'Use this action to generate SEGMENT sub-node within CUSTOMER node in Yahoo taxonomy',
- defaultSubscription: 'event = "Audience Entered" and event = "Audience Exited"',
-
- fields: {
- segment_audience_key: {
- label: 'Audience Key',
- description: 'Provide audience key. This maps to the "Name" of the Segment node in Yahoo taxonomy',
- type: 'string',
- required: true
- },
- segment_audience_id: {
- label: 'Audience Id',
- description:
- 'Provide audience Id (aud_...) from audience URL in Segment Engage. This maps to the "Id" of the Segment node in Yahoo taxonomy',
- type: 'string',
- required: true
- },
- engage_space_id: {
- label: 'Engage Space Id',
- description:
- 'Provide Engage Space Id found in Unify > Settings > API Access. This maps to the "Id" and "Name" of the top-level Customer node in Yahoo taxonomy and specifies the parent node for your Segment node in Yahoo taxonomy',
- type: 'string',
- required: false
- },
- customer_desc: {
- label: 'Space Description',
- description: 'Provide the description for Segment node in Yahoo taxonomy. This must be less then 1000 characters',
- type: 'string',
- required: false
- }
- },
- perform: async (request, { payload, settings }) => {
- const tx_creds = {
- tx_client_key: settings.taxonomy_client_key,
- tx_client_secret: settings.taxonomy_client_secret
- }
-
- const body_form_data = gen_segment_subtaxonomy_payload(payload)
- return await update_taxonomy(String(payload.engage_space_id), tx_creds, request, body_form_data)
- }
-}
-
-export default action
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
index 220c0f99b8..915ca716e8 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/generated-types.ts
@@ -5,14 +5,6 @@ export interface Settings {
* Yahoo MDM ID provided by Yahoo representative
*/
mdm_id: string
- /**
- * Taxonomy API client Id. Required to update Yahoo taxonomy
- */
- taxonomy_client_key: string
- /**
- * Taxonomy API client secret. Required to update Yahoo taxonomy
- */
- taxonomy_client_secret: string
/**
* Engage Space Id found in Unify > Settings > API Access
*/
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
index 74ccc57386..6435a378bd 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
@@ -3,8 +3,6 @@ import { IntegrationError } from '@segment/actions-core'
import type { Settings, AudienceSettings } from './generated-types'
import { generate_jwt } from './utils-rt'
import updateSegment from './updateSegment'
-import createSegment from './createSegment'
-import createCustomerNode from './createCustomerNode'
import { gen_customer_taxonomy_payload, gen_segment_subtaxonomy_payload, update_taxonomy } from './utils-tax'
interface RefreshTokenResponse {
@@ -25,18 +23,6 @@ const destination: AudienceDestinationDefinition = {
type: 'string',
required: true
},
- taxonomy_client_key: {
- label: 'Yahoo Taxonomy API client Id',
- description: 'Taxonomy API client Id. Required to update Yahoo taxonomy',
- type: 'string',
- required: true
- },
- taxonomy_client_secret: {
- label: 'Yahoo Taxonomy API client secret',
- description: 'Taxonomy API client secret. Required to update Yahoo taxonomy',
- type: 'password',
- required: true
- },
engage_space_id: {
label: 'Engage Space Id',
description: 'Engage Space Id found in Unify > Settings > API Access',
@@ -51,17 +37,19 @@ const destination: AudienceDestinationDefinition = {
}
},
testAuthentication: async (request, { settings }) => {
+ if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET) {
+ throw new IntegrationError('Missing Taxonomy API client secret', 'MISSING_REQUIRED_FIELD', 400)
+ }
+ if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID) {
+ throw new IntegrationError('Missing Taxonomy API client Id', 'MISSING_REQUIRED_FIELD', 400)
+ }
// Used to create top-level customer node
const tx_creds = {
- tx_client_key: settings.taxonomy_client_key,
- tx_client_secret: settings.taxonomy_client_secret
- }
- const data = {
- engage_space_id: settings.engage_space_id,
- customer_desc: settings.customer_desc
+ tx_client_key: process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID,
+ tx_client_secret: process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET
}
- const body_form_data = gen_customer_taxonomy_payload(settings, data)
+ const body_form_data = gen_customer_taxonomy_payload(settings)
await update_taxonomy('', tx_creds, request, body_form_data)
},
refreshAccessToken: async (request, { auth }) => {
@@ -82,22 +70,7 @@ const destination: AudienceDestinationDefinition = {
})
}
)
- // Oauth1 credentials
- // Removed thas temporarily as we're fetching tx creds from the global settings
- // const tx_client_key = JSON.parse(auth.clientId)['tax_api']
- // const tx_client_secret = JSON.parse(auth.clientSecret)['tax_api']
const rt_access_token = res.data.access_token
- // const creds = {
- // // Oauth1
- // tx: {
- // tx_client_key: tx_client_key,
- // tx_client_secret: tx_client_secret
- // },
- // // Oauth2
- // rt: rt_access_token
- // }
- // const creds_base64 = Buffer.from(JSON.stringify(creds)).toString('base64')
- // return { accessToken: creds_base64 }
return { accessToken: rt_access_token }
}
},
@@ -148,18 +121,7 @@ const destination: AudienceDestinationDefinition = {
if (!audience_id) {
throw new IntegrationError('Create Audience: missing audience Id value', 'MISSING_REQUIRED_FIELD', 400)
}
- /*
- audience_id will not be exposed in the UI once we have Payload accessible by createAudience()
- const regex = /^aud_[a-zA-Z0-9]{27}$/
- if (regex.test(audience_id) === false) {
- throw new IntegrationError(
- 'Incorrect audience Id. Provide audience Id "aud_..." from audience URL',
- 'MISSING_REQUIRED_FIELD',
- 400
- )
- }
- */
if (!audience_key) {
throw new IntegrationError('Create Audience: missing audience key value', 'MISSING_REQUIRED_FIELD', 400)
}
@@ -168,6 +130,16 @@ const destination: AudienceDestinationDefinition = {
throw new IntegrationError('Create Audience: missing Engage space Id type value', 'MISSING_REQUIRED_FIELD', 400)
}
+ if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET) {
+ throw new IntegrationError('Missing Taxonomy API client secret', 'MISSING_REQUIRED_FIELD', 400)
+ }
+ if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID) {
+ throw new IntegrationError('Missing Taxonomy API client Id', 'MISSING_REQUIRED_FIELD', 400)
+ }
+ if (!identifier) {
+ throw new IntegrationError('Create Audience: missing Identifier type value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
const input = {
segment_audience_id: audience_id,
segment_audience_key: audience_key,
@@ -178,8 +150,8 @@ const destination: AudienceDestinationDefinition = {
const body_form_data = gen_segment_subtaxonomy_payload(input)
const tx_creds = {
- tx_client_key: createAudienceInput.settings.taxonomy_client_key,
- tx_client_secret: createAudienceInput.settings.taxonomy_client_secret
+ tx_client_key: process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID,
+ tx_client_secret: process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET
}
await update_taxonomy(engage_space_id, tx_creds, request, body_form_data)
@@ -196,9 +168,7 @@ const destination: AudienceDestinationDefinition = {
},
actions: {
- updateSegment,
- createSegment,
- createCustomerNode
+ updateSegment
}
}
export default destination
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/types.ts
index 962c386d46..ab9ed2426b 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/types.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/types.ts
@@ -25,3 +25,10 @@ export interface YahooPayload {
gdpr: boolean
gdpr_euconsent?: string | undefined
}
+
+export interface YahooSubTaxonomy {
+ segment_audience_id: string
+ segment_audience_key: string
+ engage_space_id: string
+ identifier: string
+}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
index b105ca9aa2..bc53b14f04 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
@@ -18,8 +18,6 @@ const AUDIENCE_KEY = 'sneakers_buyers' // References audienceSettings.audience_k
const ADVERTISING_ID = 'foobar' // References device.advertisingId
const ENGAGE_SPACE_ID = 'acme_corp_engage_space' // References settings.engage_space_id
const MDM_ID = 'mdm 123' // References settings.mdm_id
-const TX_KEY = '123' // References settings.taxonomy_client_id
-const TX_SECRET = '456' // References settings.taxonomy_client_secret
const CUST_DESC = 'ACME Corp' // References settings.customer_desc
const bad_event = createTestEvent({
@@ -80,8 +78,6 @@ describe('YahooAudiences.updateSegment', () => {
settings: {
engage_space_id: ENGAGE_SPACE_ID,
mdm_id: MDM_ID,
- taxonomy_client_key: TX_KEY,
- taxonomy_client_secret: TX_SECRET,
customer_desc: CUST_DESC
}
})
@@ -187,8 +183,6 @@ describe('YahooAudiences.updateSegment', () => {
settings: {
engage_space_id: ENGAGE_SPACE_ID,
mdm_id: MDM_ID,
- taxonomy_client_key: TX_KEY,
- taxonomy_client_secret: TX_SECRET,
customer_desc: CUST_DESC
}
})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
index d9ca2cb99e..53ea8e29ad 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
@@ -128,7 +128,6 @@ const action: ActionDefinition = {
perform: (request, { payload, auth, audienceSettings }) => {
const rt_access_token = auth?.accessToken
-
if (!audienceSettings) {
throw new IntegrationError('Bad Request: no audienceSettings found.', 'INVALID_REQUEST_DATA', 400)
}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
index 296fd0f9b1..bf10905d3e 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
@@ -1,36 +1,34 @@
-import { Payload as SegmentNodePayload } from './createSegment/generated-types'
-import { Payload as CustomerNodePayload } from './createCustomerNode/generated-types'
import type { Settings } from './generated-types'
import { createHmac } from 'crypto'
-import { CredsObj } from './types'
+import { CredsObj, YahooSubTaxonomy } from './types'
import { RequestClient, IntegrationError } from '@segment/actions-core'
-export function gen_customer_taxonomy_payload(settings: Settings, payload: CustomerNodePayload) {
+export function gen_customer_taxonomy_payload(settings: Settings) {
const data = {
- id: payload.engage_space_id,
- name: payload.engage_space_id,
- description: payload.customer_desc,
+ id: settings.engage_space_id,
+ name: settings.engage_space_id,
+ description: settings.customer_desc,
users: {
include: [settings.mdm_id]
}
}
// Form data must be delimited with CRLF = /r/n: RFC https://www.rfc-editor.org/rfc/rfc7578#section-4.1
const req_body_form = `--SEGMENT-DATA\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n{ "description" : "${
- payload.customer_desc
+ settings.customer_desc
}" }\r\n--SEGMENT-DATA\r\nContent-Disposition: form-data; name="data"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n${JSON.stringify(
data
)}\r\n--SEGMENT-DATA--`
return req_body_form
}
-export function gen_segment_subtaxonomy_payload(payload: SegmentNodePayload) {
+export function gen_segment_subtaxonomy_payload(payload: YahooSubTaxonomy) {
const data = {
id: payload.segment_audience_id,
name: payload.segment_audience_key,
type: 'SEGMENT'
}
- const req_body_form = `--SEGMENT-DATA\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n{ "description" : "${
- payload.customer_desc
+ const req_body_form = `--SEGMENT-DATA\r\nContent-Disposition: form-data; name="metadata"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n{ "description" : "Create segment ${
+ data.id
}" }\r\n--SEGMENT-DATA\r\nContent-Disposition: form-data; name="data"\r\nContent-Type: application/json;charset=UTF-8\r\n\r\n${JSON.stringify(
data
)}\r\n--SEGMENT-DATA--`
From 2f16bc82c6eb57a131238681c1e705d8b1a839ec Mon Sep 17 00:00:00 2001
From: Ankit Gupta <139338151+AnkitSegment@users.noreply.github.com>
Date: Mon, 9 Oct 2023 19:45:54 +0530
Subject: [PATCH 018/389] Revert "[STRATCONN] 3183 Added email subscribe as
dynamic field in braze (#1606)" (#1639)
This reverts commit 17bd01f7917b6528b44c9e26559446116d96d243.
---
.../destinations/braze/src/updateUserProfile/index.ts | 7 +------
.../src/destinations/braze/updateUserProfile/index.ts | 7 +------
2 files changed, 2 insertions(+), 12 deletions(-)
diff --git a/packages/browser-destinations/destinations/braze/src/updateUserProfile/index.ts b/packages/browser-destinations/destinations/braze/src/updateUserProfile/index.ts
index 7edf1f64c7..a45ccc5414 100644
--- a/packages/browser-destinations/destinations/braze/src/updateUserProfile/index.ts
+++ b/packages/browser-destinations/destinations/braze/src/updateUserProfile/index.ts
@@ -79,12 +79,7 @@ const action: BrowserActionDefinition
email_subscribe: {
label: 'Email Subscribe',
description: `The user's email subscription preference: “opted_in” (explicitly registered to receive email messages), “unsubscribed” (explicitly opted out of email messages), and “subscribed” (neither opted in nor out).`,
- type: 'string',
- choices: [
- { label: 'OTPED_IN', value: 'opted_in' },
- { label: 'SUBSCRIBED', value: 'subscribed' },
- { label: 'UNSUBSCRIBED', value: 'unsubscribed' }
- ]
+ type: 'string'
},
first_name: {
label: 'First Name',
diff --git a/packages/destination-actions/src/destinations/braze/updateUserProfile/index.ts b/packages/destination-actions/src/destinations/braze/updateUserProfile/index.ts
index 6fa7772eb8..f120c8409b 100644
--- a/packages/destination-actions/src/destinations/braze/updateUserProfile/index.ts
+++ b/packages/destination-actions/src/destinations/braze/updateUserProfile/index.ts
@@ -154,12 +154,7 @@ const action: ActionDefinition = {
email_subscribe: {
label: 'Email Subscribe',
description: `The user's email subscription preference: “opted_in” (explicitly registered to receive email messages), “unsubscribed” (explicitly opted out of email messages), and “subscribed” (neither opted in nor out).`,
- type: 'string',
- choices: [
- { label: 'OTPED_IN', value: 'opted_in' },
- { label: 'SUBSCRIBED', value: 'subscribed' },
- { label: 'UNSUBSCRIBED', value: 'unsubscribed' }
- ]
+ type: 'string'
},
email_open_tracking_disabled: {
label: 'Email Open Tracking Disabled',
From 5a1cb53fab37acfdc3b89bc3ad18ed7646ea46f4 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 9 Oct 2023 18:16:38 +0200
Subject: [PATCH 019/389] updating wording on field (#1631)
---
.../destinations/tiktok-pixel/src/generated-types.ts | 2 +-
.../destinations/tiktok-pixel/src/index.ts | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/generated-types.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/generated-types.ts
index a410308693..608ad2bb52 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/src/generated-types.ts
+++ b/packages/browser-destinations/destinations/tiktok-pixel/src/generated-types.ts
@@ -6,7 +6,7 @@ export interface Settings {
*/
pixelCode: string
/**
- * Select "true" to use existing Pixel that is already installed on your website.
+ * Important! Changing this setting may block data collection to Segment if not done correctly. Select "true" to use an existing TikTok Pixel which is already installed on your website. The Pixel MUST be installed on your website when this is set to "true" or all data collection to Segment may fail.
*/
useExistingPixel?: boolean
}
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/index.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/index.ts
index 90ef30ce3e..6c5c13a28b 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/src/index.ts
+++ b/packages/browser-destinations/destinations/tiktok-pixel/src/index.ts
@@ -139,7 +139,8 @@ export const destination: BrowserDestinationDefinition =
useExistingPixel: {
label: 'Use Existing Pixel',
type: 'boolean',
- description: 'Select "true" to use existing Pixel that is already installed on your website.'
+ description:
+ 'Important! Changing this setting may block data collection to Segment if not done correctly. Select "true" to use an existing TikTok Pixel which is already installed on your website. The Pixel MUST be installed on your website when this is set to "true" or all data collection to Segment may fail.'
}
},
initialize: async ({ settings }, deps) => {
From ebfe43eae3898801bd30401b29e22f6cb258ae2b Mon Sep 17 00:00:00 2001
From: hvardhan-unth <117922634+hvardhan-unth@users.noreply.github.com>
Date: Tue, 10 Oct 2023 15:39:02 +0530
Subject: [PATCH 020/389] [STRATCONN 3248] Added timestamp mapping (#1637)
* Added new timestamp in segment profile destination
* updated the snapshot test and added a new unit test
* Update the timestamp on unitr test
* Update unit test case for segment-profile destinations
* Update unit test case for segment-profile destinations
* Made some changes in test cases
---------
Co-authored-by: Harsh Vardhan
---
.../__tests__/__snapshots__/snapshot.test.ts.snap | 2 ++
.../segment-profiles/segment-properties.ts | 9 +++++++++
.../__tests__/__snapshots__/index.test.ts.snap | 2 ++
.../__tests__/__snapshots__/snapshot.test.ts.snap | 1 +
.../sendGroup/__tests__/index.test.ts | 11 ++++++++---
.../segment-profiles/sendGroup/generated-types.ts | 4 ++++
.../destinations/segment-profiles/sendGroup/index.ts | 6 ++++--
.../__tests__/__snapshots__/index.test.ts.snap | 2 ++
.../__tests__/__snapshots__/snapshot.test.ts.snap | 1 +
.../sendIdentify/__tests__/index.test.ts | 11 ++++++++---
.../segment-profiles/sendIdentify/generated-types.ts | 4 ++++
.../segment-profiles/sendIdentify/index.ts | 6 ++++--
.../__tests__/__snapshots__/index.test.ts.snap | 3 +++
.../sendSubscription/__tests__/index.test.ts | 10 +++++++++-
.../sendSubscription/generated-types.ts | 4 ++++
.../segment-profiles/sendSubscription/index.ts | 5 ++++-
16 files changed, 69 insertions(+), 12 deletions(-)
diff --git a/packages/destination-actions/src/destinations/segment-profiles/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/__tests__/__snapshots__/snapshot.test.ts.snap
index 0536863506..e35c9f095e 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -7,6 +7,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2021-02-01T00:00:00.000Z",
"traits": Object {
"testType": "cZE8HyAL0!BF#)WQb^",
},
@@ -33,6 +34,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2021-02-01T00:00:00.000Z",
"traits": Object {
"testType": "hIC1OAmWa[Q!&d%o",
},
diff --git a/packages/destination-actions/src/destinations/segment-profiles/segment-properties.ts b/packages/destination-actions/src/destinations/segment-profiles/segment-properties.ts
index eef1f1587c..923d9ba94d 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/segment-properties.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/segment-properties.ts
@@ -35,3 +35,12 @@ export const engage_space: InputField = {
required: true,
dynamic: true
}
+
+export const timestamp: InputField = {
+ label: 'Timestamp',
+ description: 'The timestamp of the event.',
+ type: 'datetime',
+ default: {
+ '@path': '$.timestamp'
+ }
+}
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/index.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/index.test.ts.snap
index a29b2058a8..2b0ec81dcd 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/index.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/index.test.ts.snap
@@ -9,6 +9,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-09-26T09:46:28.290Z",
"traits": Object {
"industry": "Technology",
"name": "Example Corp",
@@ -40,6 +41,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-09-26T09:46:28.290Z",
"traits": Object {
"industry": "Technology",
"name": "Example Corp",
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/snapshot.test.ts.snap
index 093f9ffd0b..261c640cef 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -7,6 +7,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2021-02-01T00:00:00.000Z",
"traits": Object {
"testType": "tKaa(2A",
},
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/index.test.ts b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/index.test.ts
index 887a001ccd..24a5903d5d 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/__tests__/index.test.ts
@@ -22,7 +22,10 @@ const defaultGroupMapping = {
traits: {
'@path': '$.traits'
},
- engage_space: 'engage-space-writekey'
+ engage_space: 'engage-space-writekey',
+ timestamp: {
+ '@path': '$.timestamp'
+ }
}
describe('SegmentProfiles.sendGroup', () => {
@@ -81,7 +84,8 @@ describe('SegmentProfiles.sendGroup', () => {
},
userId: 'test-user-ufi5bgkko5',
anonymousId: 'arky4h2sh7k',
- groupId: 'test-group-ks2i7e'
+ groupId: 'test-group-ks2i7e',
+ timestamp: '2023-09-26T09:46:28.290Z'
})
const responses = await testDestination.testAction('sendGroup', {
@@ -106,7 +110,8 @@ describe('SegmentProfiles.sendGroup', () => {
},
userId: 'test-user-ufi5bgkko5',
anonymousId: 'arky4h2sh7k',
- groupId: 'test-group-ks2i7e'
+ groupId: 'test-group-ks2i7e',
+ timestamp: '2023-09-26T09:46:28.290Z'
})
const responses = await testDestination.testAction('sendGroup', {
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/generated-types.ts b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/generated-types.ts
index b16e6a4c9f..9b08b43059 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/generated-types.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/generated-types.ts
@@ -23,4 +23,8 @@ export interface Payload {
traits?: {
[k: string]: unknown
}
+ /**
+ * The timestamp of the event.
+ */
+ timestamp?: string | number
}
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/index.ts b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/index.ts
index aecdafc7cd..ea503a0031 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendGroup/index.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendGroup/index.ts
@@ -1,7 +1,7 @@
import type { ActionDefinition } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
-import { user_id, anonymous_id, group_id, traits, engage_space } from '../segment-properties'
+import { user_id, anonymous_id, group_id, traits, engage_space, timestamp } from '../segment-properties'
import { generateSegmentAPIAuthHeaders } from '../helperFunctions'
import { SEGMENT_ENDPOINTS } from '../properties'
import { MissingUserOrAnonymousIdThrowableError, InvalidEndpointSelectedThrowableError } from '../errors'
@@ -15,7 +15,8 @@ const action: ActionDefinition = {
user_id,
anonymous_id,
group_id: { ...group_id, required: true },
- traits
+ traits,
+ timestamp
},
perform: (request, { payload, settings, features, statsContext }) => {
if (!payload.anonymous_id && !payload.user_id) {
@@ -28,6 +29,7 @@ const action: ActionDefinition = {
traits: {
...payload?.traits
},
+ timestamp: payload?.timestamp,
integrations: {
// Setting 'integrations.All' to false will ensure that we don't send events
// to any destinations which is connected to the Segment Profiles space.
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/index.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/index.test.ts.snap
index 5fea1f8ff3..75e88e146c 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/index.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/index.test.ts.snap
@@ -9,6 +9,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-09-26T09:46:28.290Z",
"traits": Object {
"email": "test-user@test-company.com",
"name": "Test User",
@@ -40,6 +41,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-09-26T09:46:28.290Z",
"traits": Object {
"email": "test-user@test-company.com",
"name": "Test User",
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/snapshot.test.ts.snap
index d0706d1f1e..d8da27b194 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -7,6 +7,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2021-02-01T00:00:00.000Z",
"traits": Object {
"testType": "mV[ZQcEVgZO$MX",
},
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/index.test.ts
index 97786f8f97..1b5c2d52ea 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/__tests__/index.test.ts
@@ -19,7 +19,10 @@ const defaultIdentifyMapping = {
traits: {
'@path': '$.traits'
},
- engage_space: 'engage-space-writekey'
+ engage_space: 'engage-space-writekey',
+ timestamp: {
+ '@path': '$.timestamp'
+ }
}
describe('Segment.sendIdentify', () => {
@@ -76,7 +79,8 @@ describe('Segment.sendIdentify', () => {
email: 'test-user@test-company.com'
},
userId: 'test-user-ufi5bgkko5',
- anonymousId: 'arky4h2sh7k'
+ anonymousId: 'arky4h2sh7k',
+ timestamp: '2023-09-26T09:46:28.290Z'
})
const responses = await testDestination.testAction('sendIdentify', {
@@ -101,7 +105,8 @@ describe('Segment.sendIdentify', () => {
email: 'test-user@test-company.com'
},
userId: 'test-user-ufi5bgkko5',
- anonymousId: 'arky4h2sh7k'
+ anonymousId: 'arky4h2sh7k',
+ timestamp: '2023-09-26T09:46:28.290Z'
})
const responses = await testDestination.testAction('sendIdentify', {
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/generated-types.ts b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/generated-types.ts
index 5afd99d1f6..c8c5e30af9 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/generated-types.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/generated-types.ts
@@ -23,4 +23,8 @@ export interface Payload {
traits?: {
[k: string]: unknown
}
+ /**
+ * The timestamp of the event.
+ */
+ timestamp?: string | number
}
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/index.ts b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/index.ts
index 9b8bc56578..9308436db4 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/index.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendIdentify/index.ts
@@ -1,7 +1,7 @@
import type { ActionDefinition } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
-import { user_id, anonymous_id, group_id, traits, engage_space } from '../segment-properties'
+import { user_id, anonymous_id, group_id, traits, engage_space, timestamp } from '../segment-properties'
import { generateSegmentAPIAuthHeaders } from '../helperFunctions'
import { SEGMENT_ENDPOINTS } from '../properties'
import { MissingUserOrAnonymousIdThrowableError, InvalidEndpointSelectedThrowableError } from '../errors'
@@ -16,7 +16,8 @@ const action: ActionDefinition = {
user_id,
anonymous_id,
group_id,
- traits
+ traits,
+ timestamp
},
perform: (request, { payload, settings, features, statsContext }) => {
if (!payload.anonymous_id && !payload.user_id) {
@@ -29,6 +30,7 @@ const action: ActionDefinition = {
traits: {
...payload?.traits
},
+ timestamp: payload?.timestamp,
integrations: {
// Setting 'integrations.All' to false will ensure that we don't send events
// to any destinations which is connected to the Segment Profiles space.
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/__snapshots__/index.test.ts.snap b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/__snapshots__/index.test.ts.snap
index 3e11f8a54a..a046c7923a 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/__snapshots__/index.test.ts.snap
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/__snapshots__/index.test.ts.snap
@@ -64,6 +64,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-10-10T07:24:07.036Z",
"traits": Object {
"email": "test-user@test-company.com",
"name": "Test User",
@@ -150,6 +151,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-10-10T07:24:07.036Z",
"traits": Object {
"email": "test-user@test-company.com",
"name": "Test User",
@@ -206,6 +208,7 @@ Object {
"integrations": Object {
"All": false,
},
+ "timestamp": "2023-10-10T07:24:07.036Z",
"traits": Object {
"email": "test-user@test-company.com",
"name": "Test User",
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
index d2a1873847..4433858629 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
@@ -54,7 +54,10 @@ export const defaultSubscriptionMapping = {
android_push_subscription_status: {
'@path': '$.properties.android_push_subscription_status'
},
- engage_space: 'engage-space-writekey'
+ engage_space: 'engage-space-writekey',
+ timestamp: {
+ '@path': '$.timestamp'
+ }
}
describe('SegmentProfiles.sendSubscription', () => {
test('Should throw an error if `userId` or `anonymousId` is not defined', async () => {
@@ -184,6 +187,7 @@ describe('SegmentProfiles.sendSubscription', () => {
name: 'Test User',
email: 'test-user@test-company.com'
},
+ timestamp: '2023-10-10T07:24:07.036Z',
properties: {
email: 'tester11@seg.com',
email_subscription_status: 'true',
@@ -221,6 +225,7 @@ describe('SegmentProfiles.sendSubscription', () => {
name: 'Test User',
email: 'test-user@test-company.com'
},
+ timestamp: '2023-10-10T07:24:07.036Z',
properties: {
email: 'tester11@seg.com',
email_subscription_status: 'true',
@@ -239,6 +244,8 @@ describe('SegmentProfiles.sendSubscription', () => {
}
})
+ console.log('edwuy: ', event)
+
const responses = await testDestination.testAction('sendSubscription', {
event,
mapping: defaultSubscriptionMapping,
@@ -259,6 +266,7 @@ describe('SegmentProfiles.sendSubscription', () => {
name: 'Test User',
email: 'test-user@test-company.com'
},
+ timestamp: '2023-10-10T07:24:07.036Z',
properties: {
email: 'tester11@seg.com',
email_subscription_status: 'true',
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
index 42a6ef59da..f3863b13d8 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
@@ -61,4 +61,8 @@ export interface Payload {
traits?: {
[k: string]: unknown
}
+ /**
+ * The timestamp of the event.
+ */
+ timestamp?: string | number
}
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
index cd91d4b1a1..d17170c9e3 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
@@ -30,6 +30,7 @@ import {
} from '../errors'
import { generateSegmentAPIAuthHeaders } from '../helperFunctions'
import { SEGMENT_ENDPOINTS } from '../properties'
+import { timestamp } from '../segment-properties'
import { StatsClient } from '@segment/actions-core/destination-kit'
interface SubscriptionStatusConfig {
@@ -279,7 +280,8 @@ const action: ActionDefinition = {
android_push_subscription_status,
ios_push_token,
ios_push_subscription_status,
- traits
+ traits,
+ timestamp
},
perform: (request, { payload, settings, features, statsContext }) => {
const statsClient = statsContext?.statsClient
@@ -307,6 +309,7 @@ const action: ActionDefinition = {
externalIds,
messaging_subscriptions_retl: true
},
+ timestamp: payload?.timestamp,
integrations: {
// Setting 'integrations.All' to false will ensure that we don't send events
// to any destinations which is connected to the Segment Profiles space
From a3877e5832a7acd67bf5429497b93a4b41c563d7 Mon Sep 17 00:00:00 2001
From: Innovative-GauravKochar
<117165746+Innovative-GauravKochar@users.noreply.github.com>
Date: Tue, 10 Oct 2023 16:43:23 +0530
Subject: [PATCH 021/389] STRATCONN-3229 | Hubspot Cloud Actions- Can not read
properties of undefined (Setting actions) (#1632)
* STRATCONN-3229 | Hubspot Cloud Actions- Can not read properties of undefined (Setting actions)
* removed reindexing and some code cleaning
---------
Co-authored-by: Gaurav Kochar
---
.../__tests__/__helpers__/test-utils.ts | 2 +
.../__snapshots__/index.test.ts.snap | 99 ++++++++++++++++++-
.../upsertContact/__tests__/index.test.ts | 57 ++++++++++-
.../hubspot/upsertContact/index.ts | 48 ++++++---
4 files changed, 187 insertions(+), 19 deletions(-)
diff --git a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__helpers__/test-utils.ts b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__helpers__/test-utils.ts
index ee1b416882..0d18fdfcfe 100644
--- a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__helpers__/test-utils.ts
+++ b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__helpers__/test-utils.ts
@@ -7,6 +7,7 @@ export type BatchContactListItem = {
firstname: string
lastname: string
lifecyclestage?: string | undefined
+ additionalemail?: string | null
}
export const createBatchTestEvents = (batchContactList: BatchContactListItem[]) =>
@@ -51,6 +52,7 @@ export const generateBatchReadResponse = (batchContactList: BatchContactListItem
properties: {
createdate: '2023-07-06T12:47:47.626Z',
email: contact.email,
+ hs_additional_emails: contact?.additionalemail ?? null,
hs_object_id: contact.id,
lastmodifieddate: '2023-07-06T12:48:02.784Z'
}
diff --git a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__snapshots__/index.test.ts.snap b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__snapshots__/index.test.ts.snap
index 906ae8f77a..81fd85adf7 100644
--- a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__snapshots__/index.test.ts.snap
+++ b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/__snapshots__/index.test.ts.snap
@@ -1,5 +1,87 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
+exports[`HubSpot.upsertContactBatch Should update contact on the basis of secondary email if it's not getting mapped with Primary email addresses 1`] = `
+Object {
+ "afterResponse": Array [
+ [Function],
+ [Function],
+ [Function],
+ ],
+ "beforeRequest": Array [
+ [Function],
+ ],
+ "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\",\\"hs_additional_emails\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"secondaryemail@gmail.com\\"}]}",
+ "headers": Headers {
+ Symbol(map): Object {
+ "authorization": Array [
+ "Bearer undefined",
+ ],
+ "user-agent": Array [
+ "Segment (Actions)",
+ ],
+ },
+ },
+ "json": Object {
+ "idProperty": "email",
+ "inputs": Array [
+ Object {
+ "id": "secondaryemail@gmail.com",
+ },
+ ],
+ "properties": Array [
+ "email",
+ "lifecyclestage",
+ "hs_additional_emails",
+ ],
+ },
+ "method": "POST",
+ "signal": AbortSignal {},
+ "skipResponseCloning": true,
+ "statsContext": Object {},
+ "throwHttpErrors": true,
+ "timeout": 10000,
+}
+`;
+
+exports[`HubSpot.upsertContactBatch Should update contact on the basis of secondary email if it's not getting mapped with Primary email addresses 2`] = `
+Object {
+ "errors": Array [],
+ "numErrors": 0,
+ "results": Array [
+ Object {
+ "id": "113",
+ "properties": Object {
+ "createdate": "2023-07-06T12:47:47.626Z",
+ "email": "userthree@somecompany.com",
+ "hs_additional_emails": "secondaryemail@gmail.com;secondaryemail+2@gmail.com",
+ "hs_object_id": "113",
+ "lastmodifieddate": "2023-07-06T12:48:02.784Z",
+ },
+ },
+ ],
+ "status": "COMPLETE",
+}
+`;
+
+exports[`HubSpot.upsertContactBatch Should update contact on the basis of secondary email if it's not getting mapped with Primary email addresses 3`] = `
+Object {
+ "results": Array [
+ Object {
+ "id": "113",
+ "properties": Object {
+ "createdate": "2023-07-06T12:47:47.626Z",
+ "email": "secondaryemail@gmail.com",
+ "firstname": "User",
+ "lastmodifieddate": "2023-07-06T12:48:02.784Z",
+ "lastname": "Three",
+ "lifecyclestage": "subscriber",
+ },
+ },
+ ],
+ "status": "COMPLETE",
+}
+`;
+
exports[`HubSpot.upsertContactBatch should create and update contact successfully 1`] = `
Object {
"afterResponse": Array [
@@ -10,7 +92,7 @@ Object {
"beforeRequest": Array [
[Function],
],
- "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"},{\\"id\\":\\"usertwo@somecompany.com\\"},{\\"id\\":\\"userthree@somecompany.com\\"},{\\"id\\":\\"userfour@somecompany.com\\"}]}",
+ "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\",\\"hs_additional_emails\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"},{\\"id\\":\\"usertwo@somecompany.com\\"},{\\"id\\":\\"userthree@somecompany.com\\"},{\\"id\\":\\"userfour@somecompany.com\\"}]}",
"headers": Headers {
Symbol(map): Object {
"authorization": Array [
@@ -40,6 +122,7 @@ Object {
"properties": Array [
"email",
"lifecyclestage",
+ "hs_additional_emails",
],
},
"method": "POST",
@@ -73,6 +156,7 @@ Object {
"properties": Object {
"createdate": "2023-07-06T12:47:47.626Z",
"email": "userthree@somecompany.com",
+ "hs_additional_emails": null,
"hs_object_id": "103",
"lastmodifieddate": "2023-07-06T12:48:02.784Z",
},
@@ -82,6 +166,7 @@ Object {
"properties": Object {
"createdate": "2023-07-06T12:47:47.626Z",
"email": "userfour@somecompany.com",
+ "hs_additional_emails": null,
"hs_object_id": "104",
"lastmodifieddate": "2023-07-06T12:48:02.784Z",
},
@@ -161,7 +246,7 @@ Object {
"beforeRequest": Array [
[Function],
],
- "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"},{\\"id\\":\\"usertwo@somecompany.com\\"}]}",
+ "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\",\\"hs_additional_emails\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"},{\\"id\\":\\"usertwo@somecompany.com\\"}]}",
"headers": Headers {
Symbol(map): Object {
"authorization": Array [
@@ -185,6 +270,7 @@ Object {
"properties": Array [
"email",
"lifecyclestage",
+ "hs_additional_emails",
],
},
"method": "POST",
@@ -257,7 +343,7 @@ Object {
"beforeRequest": Array [
[Function],
],
- "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"}]}",
+ "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\",\\"hs_additional_emails\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userone@somecompany.com\\"}]}",
"headers": Headers {
Symbol(map): Object {
"authorization": Array [
@@ -278,6 +364,7 @@ Object {
"properties": Array [
"email",
"lifecyclestage",
+ "hs_additional_emails",
],
},
"method": "POST",
@@ -299,6 +386,7 @@ Object {
"properties": Object {
"createdate": "2023-07-06T12:47:47.626Z",
"email": "userone@somecompany.com",
+ "hs_additional_emails": null,
"hs_object_id": "103",
"lastmodifieddate": "2023-07-06T12:48:02.784Z",
},
@@ -375,7 +463,7 @@ Object {
"beforeRequest": Array [
[Function],
],
- "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userthree@somecompany.com\\"},{\\"id\\":\\"userfour@somecompany.com\\"}]}",
+ "body": "{\\"properties\\":[\\"email\\",\\"lifecyclestage\\",\\"hs_additional_emails\\"],\\"idProperty\\":\\"email\\",\\"inputs\\":[{\\"id\\":\\"userthree@somecompany.com\\"},{\\"id\\":\\"userfour@somecompany.com\\"}]}",
"headers": Headers {
Symbol(map): Object {
"authorization": Array [
@@ -399,6 +487,7 @@ Object {
"properties": Array [
"email",
"lifecyclestage",
+ "hs_additional_emails",
],
},
"method": "POST",
@@ -420,6 +509,7 @@ Object {
"properties": Object {
"createdate": "2023-07-06T12:47:47.626Z",
"email": "userthree@somecompany.com",
+ "hs_additional_emails": null,
"hs_object_id": "103",
"lastmodifieddate": "2023-07-06T12:48:02.784Z",
},
@@ -429,6 +519,7 @@ Object {
"properties": Object {
"createdate": "2023-07-06T12:47:47.626Z",
"email": "userfour@somecompany.com",
+ "hs_additional_emails": null,
"hs_object_id": "104",
"lastmodifieddate": "2023-07-06T12:48:02.784Z",
},
diff --git a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/index.test.ts b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/index.test.ts
index 2f9edadb11..7aefb04ba5 100644
--- a/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/hubspot/upsertContact/__tests__/index.test.ts
@@ -555,7 +555,7 @@ describe('HubSpot.upsertContactBatch', () => {
nock(HUBSPOT_BASE_URL)
.post(
`/crm/v3/objects/contacts/batch/update`,
- '{"inputs":[{"id":"103","properties":{"company":"Some Company","phone":"+13134561129","address":"Vancover st","city":"San Francisco","state":"California","country":"USA","zip":"600001","email":"userone@somecompany.com","website":"somecompany.com","lifecyclestage":"subscriber","graduation_date":1664533942262}}]}'
+ '{"inputs":[{"id":"103","properties":{"company":"Some Company","phone":"+13134561129","address":"Vancover st","city":"San Francisco","state":"California","country":"USA","zip":"600001","website":"somecompany.com","lifecyclestage":"subscriber","graduation_date":1664533942262}}]}'
)
.reply(
200,
@@ -650,4 +650,59 @@ describe('HubSpot.upsertContactBatch', () => {
})
).rejects.toThrowError("'lastname' Property does not exist")
})
+
+ test("Should update contact on the basis of secondary email if it's not getting mapped with Primary email addresses", async () => {
+ //Each Contact can have multiple email addresses,one as Primary and others as Secondary.
+ const updateContactList = [
+ {
+ id: '113',
+ email: 'secondaryemail@gmail.com',
+ firstname: 'User',
+ lastname: 'Three',
+ lifecyclestage: 'subscriber',
+ additionalemail: 'secondaryemail@gmail.com;secondaryemail+2@gmail.com'
+ }
+ ]
+ const events = createBatchTestEvents([...updateContactList])
+
+ // Mock: Read Contact Using Email
+ nock(HUBSPOT_BASE_URL)
+ .post(`/crm/v3/objects/contacts/batch/read`)
+ .reply(
+ 200,
+ generateBatchReadResponse([
+ {
+ id: '113',
+ email: 'userthree@somecompany.com',
+ firstname: 'User',
+ lastname: 'Three',
+ lifecyclestage: 'subscriber',
+ additionalemail: 'secondaryemail@gmail.com;secondaryemail+2@gmail.com'
+ }
+ ])
+ )
+
+ // Mock: Update Contact
+ nock(HUBSPOT_BASE_URL)
+ .post(`/crm/v3/objects/contacts/batch/update`)
+ .reply(200, generateBatchCreateResponse(updateContactList))
+
+ const mapping = {
+ properties: {
+ graduation_date: {
+ '@path': '$.traits.graduation_date'
+ }
+ }
+ }
+
+ const testBatchResponses = await testDestination.testBatchAction('upsertContact', {
+ mapping,
+ useDefaultMappings: true,
+ events
+ })
+
+ expect(testBatchResponses[0].options).toMatchSnapshot()
+ expect(testBatchResponses[0].data).toMatchSnapshot()
+ expect(testBatchResponses[1].data).toMatchSnapshot()
+ })
})
diff --git a/packages/destination-actions/src/destinations/hubspot/upsertContact/index.ts b/packages/destination-actions/src/destinations/hubspot/upsertContact/index.ts
index 7d95f689f7..138c1cc695 100644
--- a/packages/destination-actions/src/destinations/hubspot/upsertContact/index.ts
+++ b/packages/destination-actions/src/destinations/hubspot/upsertContact/index.ts
@@ -4,6 +4,7 @@ import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { HUBSPOT_BASE_URL } from '../properties'
import { flattenObject } from '../utils'
+import split from 'lodash/split'
interface ContactProperties {
company?: string | undefined
@@ -32,7 +33,7 @@ interface ContactUpdateRequestPayload {
interface ContactSuccessResponse {
id: string
- properties: Record
+ properties: Record
}
interface ContactErrorResponse {
@@ -264,6 +265,7 @@ const action: ActionDefinition = {
if (action === 'create') {
createList.push(payload)
} else if (action === 'update') {
+ delete payload['properties']['email']
updateList.push({
id: payload.id as string,
properties: payload.properties
@@ -305,7 +307,7 @@ async function updateContact(request: RequestClient, email: string, properties:
async function readContactsBatch(request: RequestClient, emails: string[]) {
const requestPayload = {
- properties: ['email', 'lifecyclestage'],
+ properties: ['email', 'lifecyclestage', 'hs_additional_emails'],
idProperty: 'email',
inputs: emails.map((email) => ({
id: email
@@ -376,17 +378,8 @@ function updateActionsForBatchedContacts(
// Throw any other error responses
// Case 1: Loop over results if there are any
if (readResponse.data?.results && readResponse.data.results.length > 0) {
- for (const result of readResponse.data.results) {
- // Set the action to update for contacts that exist in HubSpot
- contactsUpsertMap[result.properties.email].action = 'update'
-
- // Set the id for contacts that exist in HubSpot
- contactsUpsertMap[result.properties.email].payload.id = result.id
-
- // Re-index the payload with ID
- contactsUpsertMap[result.id] = { ...contactsUpsertMap[result.properties.email] }
- delete contactsUpsertMap[result.properties.email]
- }
+ //create and map payload to update contact
+ contactsUpsertMap = createPayloadToUpdateContact(readResponse, contactsUpsertMap)
}
// Case 2: Loop over errors if there are any
@@ -416,7 +409,8 @@ async function checkAndRetryUpdatingLifecycleStage(
const retryLifeCycleStagePayload: ContactUpdateRequestPayload[] = []
for (const result of updateContactResponse.data.results) {
- const desiredLifeCycleStage = contactsUpsertMap[result.id].payload.properties.lifecyclestage
+ const key = Object.keys(contactsUpsertMap).find((key) => contactsUpsertMap[key].payload.id == result.id)
+ const desiredLifeCycleStage = key ? contactsUpsertMap[key]?.payload?.properties?.lifecyclestage : null
const currentLifeCycleStage = result.properties.lifecyclestage
if (desiredLifeCycleStage && desiredLifeCycleStage !== currentLifeCycleStage) {
@@ -444,4 +438,30 @@ async function checkAndRetryUpdatingLifecycleStage(
await updateContactsBatch(request, retryLifeCycleStagePayload)
}
}
+
+function createPayloadToUpdateContact(
+ readResponse: BatchContactResponse,
+ contactsUpsertMap: Record
+) {
+ for (const result of readResponse.data.results) {
+ let email: string | undefined | null
+ //Each Hubspot Contact can have mutiple email addresses ,one as primary and others as secondary emails
+ if (!contactsUpsertMap[`${result.properties.email}`]) {
+ // If contact is not getting mapped with Primary email then checking it in secondary email for same contact.
+ if (result.properties.hs_additional_emails) {
+ const secondaryEmails = split(result.properties.hs_additional_emails, ';')
+ email = Object.keys(contactsUpsertMap).find((key) => secondaryEmails.includes(key))
+ }
+ } else {
+ email = result.properties.email
+ }
+ if (email) {
+ // Set the action to update for contacts that exist in HubSpot
+ contactsUpsertMap[email].action = 'update'
+ // Set the id for contacts that exist in HubSpot
+ contactsUpsertMap[email].payload.id = result.id
+ }
+ }
+ return contactsUpsertMap
+}
export default action
From 44eb9a8abf4af696dc7cd16323489f44f3f68210 Mon Sep 17 00:00:00 2001
From: Trackey <103515068+clickoutio@users.noreply.github.com>
Date: Tue, 10 Oct 2023 15:49:55 +0200
Subject: [PATCH 022/389] Trackey integration (#1590)
* set up the tests
* adding fields, etc
* finished with tests
---------
Co-authored-by: Javier Morales de Vera
Co-authored-by: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
---
.../__snapshots__/snapshot.test.ts.snap | 69 ++++++
.../trackey/__tests__/index.test.ts | 22 ++
.../trackey/__tests__/snapshot.test.ts | 77 +++++++
.../destinations/trackey/generated-types.ts | 8 +
.../src/destinations/trackey/group.types.ts | 28 +++
.../destinations/trackey/identify.types.ts | 28 +++
.../src/destinations/trackey/index.ts | 216 ++++++++++++++++++
.../src/destinations/trackey/track.types.ts | 32 +++
8 files changed, 480 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/trackey/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/trackey/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/group.types.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/identify.types.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/index.ts
create mode 100644 packages/destination-actions/src/destinations/trackey/track.types.ts
diff --git a/packages/destination-actions/src/destinations/trackey/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/trackey/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..7282eada67
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,69 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-trackey destination: group action - all fields 1`] = `
+Object {
+ "groupId": Object {
+ "testType": "^Vvf$jtvC",
+ },
+ "messageId": "^Vvf$jtvC",
+ "timestamp": "^Vvf$jtvC",
+ "traits": Object {
+ "testType": "^Vvf$jtvC",
+ },
+ "userId": "^Vvf$jtvC",
+}
+`;
+
+exports[`Testing snapshot for actions-trackey destination: group action - required fields 1`] = `
+Object {
+ "groupId": Object {
+ "testType": "^Vvf$jtvC",
+ },
+ "timestamp": "^Vvf$jtvC",
+ "userId": "^Vvf$jtvC",
+}
+`;
+
+exports[`Testing snapshot for actions-trackey destination: identify action - all fields 1`] = `
+Object {
+ "groupId": Object {
+ "testType": "6aniX&1",
+ },
+ "messageId": "6aniX&1",
+ "timestamp": "6aniX&1",
+ "traits": Object {
+ "testType": "6aniX&1",
+ },
+ "userId": "6aniX&1",
+}
+`;
+
+exports[`Testing snapshot for actions-trackey destination: identify action - required fields 1`] = `
+Object {
+ "timestamp": "6aniX&1",
+ "userId": "6aniX&1",
+}
+`;
+
+exports[`Testing snapshot for actions-trackey destination: track action - all fields 1`] = `
+Object {
+ "event": "eT[K8ft@uBryp",
+ "groupId": Object {
+ "testType": "eT[K8ft@uBryp",
+ },
+ "messageId": "eT[K8ft@uBryp",
+ "properties": Object {
+ "testType": "eT[K8ft@uBryp",
+ },
+ "timestamp": "eT[K8ft@uBryp",
+ "userId": "eT[K8ft@uBryp",
+}
+`;
+
+exports[`Testing snapshot for actions-trackey destination: track action - required fields 1`] = `
+Object {
+ "event": "eT[K8ft@uBryp",
+ "timestamp": "eT[K8ft@uBryp",
+ "userId": "eT[K8ft@uBryp",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/trackey/__tests__/index.test.ts b/packages/destination-actions/src/destinations/trackey/__tests__/index.test.ts
new file mode 100644
index 0000000000..5445ccd329
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/__tests__/index.test.ts
@@ -0,0 +1,22 @@
+import nock from 'nock'
+import { createTestIntegration } from '@segment/actions-core'
+import Definition from '../index'
+
+const testDestination = createTestIntegration(Definition)
+const base = 'https://app.trackey.io'
+const url = '/public-api/integrations/segment/webhook'
+
+describe('Trackey', () => {
+ it('should validate api key', async () => {
+ nock(base).get(url).reply(200, {
+ status: 'success',
+ data: 'Test client'
+ })
+
+ const authData = {
+ apiKey: 'test-api-key'
+ }
+
+ await expect(testDestination.testAuthentication(authData)).resolves.not.toThrowError()
+ })
+})
diff --git a/packages/destination-actions/src/destinations/trackey/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/trackey/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..143b803168
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/__tests__/snapshot.test.ts
@@ -0,0 +1,77 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-trackey'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/trackey/generated-types.ts b/packages/destination-actions/src/destinations/trackey/generated-types.ts
new file mode 100644
index 0000000000..0935a87f13
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/generated-types.ts
@@ -0,0 +1,8 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Your Trackey API Key
+ */
+ apiKey: string
+}
diff --git a/packages/destination-actions/src/destinations/trackey/group.types.ts b/packages/destination-actions/src/destinations/trackey/group.types.ts
new file mode 100644
index 0000000000..d75610dbb4
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/group.types.ts
@@ -0,0 +1,28 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The user identifier to associate the event with
+ */
+ userId: string
+ /**
+ * A unique value for each event.
+ */
+ messageId?: string
+ /**
+ * Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z
+ */
+ timestamp: string
+ /**
+ * Company profile information
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+ /**
+ * Company ID associated with the event
+ */
+ groupId: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/trackey/identify.types.ts b/packages/destination-actions/src/destinations/trackey/identify.types.ts
new file mode 100644
index 0000000000..638c1f2250
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/identify.types.ts
@@ -0,0 +1,28 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The user identifier to associate the event with
+ */
+ userId: string
+ /**
+ * A unique value for each event.
+ */
+ messageId?: string
+ /**
+ * Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z
+ */
+ timestamp: string
+ /**
+ * User profile information
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+ /**
+ * Company ID associated with the event
+ */
+ groupId?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/trackey/index.ts b/packages/destination-actions/src/destinations/trackey/index.ts
new file mode 100644
index 0000000000..b461e5bd72
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/index.ts
@@ -0,0 +1,216 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+
+//const base = 'https://6550-2-139-22-73.ngrok-free.app/';
+const base = 'https://eo493p73oqjeket.m.pipedream.net/'
+const endpoint = base + 'public-api/integrations/segment/webhook'
+
+const destination: DestinationDefinition = {
+ name: 'Trackey',
+ slug: 'actions-trackey',
+ mode: 'cloud',
+ description: 'Send Segment events to Trackey',
+
+ authentication: {
+ scheme: 'custom',
+ fields: {
+ apiKey: {
+ label: 'API Key',
+ description: 'Your Trackey API Key',
+ type: 'string',
+ required: true
+ }
+ }
+ },
+ extendRequest: ({ settings }) => {
+ return {
+ headers: {
+ 'api-key': settings.apiKey,
+ 'Content-Type': 'application/json'
+ }
+ }
+ },
+ onDelete: async () => {
+ // Return a request that performs a GDPR delete for the provided Segment userId or anonymousId
+ // provided in the payload. If your destination does not support GDPR deletion you should not
+ // implement this function and should remove it completely.
+ return true
+ },
+ actions: {
+ track: {
+ title: 'track',
+ description: 'Track an event',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ userId: {
+ label: 'User ID',
+ type: 'string',
+ required: true,
+ description: 'The user identifier to associate the event with',
+ default: { '@path': '$.userId' }
+ },
+ event: {
+ label: 'Event Name',
+ type: 'string',
+ required: true,
+ description: 'Name of the Segment track() event',
+ default: { '@path': '$.event' }
+ },
+ messageId: {
+ label: 'Message ID',
+ type: 'string',
+ description: 'A unique value for each event.',
+ default: {
+ '@path': '$.messageId'
+ }
+ },
+ timestamp: {
+ label: 'Event Timestamp',
+ type: 'string',
+ required: true,
+ description: 'Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z',
+ default: { '@path': '$.timestamp' }
+ },
+ properties: {
+ label: 'Event Properties',
+ type: 'object',
+ required: false,
+ description: 'Additional information associated with the track() event',
+ default: { '@path': '$.properties' }
+ },
+ groupId: {
+ label: 'Group ID',
+ type: 'object',
+ required: false,
+ description: 'Company ID associated with the event',
+ default: { '@path': '$.context.group_id' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request(endpoint, {
+ method: 'POST',
+ json: {
+ userId: payload.userId,
+ event: payload.event,
+ messageId: payload.messageId,
+ timestamp: payload.timestamp,
+ properties: payload.properties,
+ groupId: payload.groupId
+ }
+ })
+ }
+ },
+ identify: {
+ title: 'Identify',
+ description: 'Identify a user',
+ defaultSubscription: 'type = "identify"',
+ fields: {
+ userId: {
+ label: 'User ID',
+ type: 'string',
+ required: true,
+ description: 'The user identifier to associate the event with',
+ default: { '@path': '$.userId' }
+ },
+ messageId: {
+ label: 'Message ID',
+ type: 'string',
+ description: 'A unique value for each event.',
+ default: {
+ '@path': '$.messageId'
+ }
+ },
+ timestamp: {
+ label: 'Event Timestamp',
+ type: 'string',
+ required: true,
+ description: 'Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z',
+ default: { '@path': '$.timestamp' }
+ },
+ traits: {
+ label: 'User Traits',
+ type: 'object',
+ required: false,
+ description: 'User profile information',
+ default: { '@path': '$.traits' }
+ },
+ groupId: {
+ label: 'Group ID',
+ type: 'object',
+ required: false,
+ description: 'Company ID associated with the event',
+ default: { '@path': '$.context.group_id' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request(endpoint, {
+ method: 'POST',
+ json: {
+ userId: payload.userId,
+ messageId: payload.messageId,
+ timestamp: payload.timestamp,
+ traits: payload.traits,
+ groupId: payload.groupId
+ }
+ })
+ }
+ },
+ group: {
+ title: 'Group',
+ description: 'Group a user',
+ defaultSubscription: 'type = "group"',
+ fields: {
+ userId: {
+ label: 'User ID',
+ type: 'string',
+ required: true,
+ description: 'The user identifier to associate the event with',
+ default: { '@path': '$.userId' }
+ },
+ messageId: {
+ label: 'Message ID',
+ type: 'string',
+ description: 'A unique value for each event.',
+ default: {
+ '@path': '$.messageId'
+ }
+ },
+ timestamp: {
+ label: 'Event Timestamp',
+ type: 'string',
+ required: true,
+ description: 'Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z',
+ default: { '@path': '$.timestamp' }
+ },
+ traits: {
+ label: 'COmpany Traits',
+ type: 'object',
+ required: false,
+ description: 'Company profile information',
+ default: { '@path': '$.traits' }
+ },
+ groupId: {
+ label: 'Group ID',
+ type: 'object',
+ required: true,
+ description: 'Company ID associated with the event',
+ default: { '@path': '$.groupId' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request(endpoint, {
+ method: 'POST',
+ json: {
+ userId: payload.userId,
+ messageId: payload.messageId,
+ timestamp: payload.timestamp,
+ traits: payload.traits,
+ groupId: payload.groupId
+ }
+ })
+ }
+ }
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/trackey/track.types.ts b/packages/destination-actions/src/destinations/trackey/track.types.ts
new file mode 100644
index 0000000000..85c91413d9
--- /dev/null
+++ b/packages/destination-actions/src/destinations/trackey/track.types.ts
@@ -0,0 +1,32 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The user identifier to associate the event with
+ */
+ userId: string
+ /**
+ * Name of the Segment track() event
+ */
+ event: string
+ /**
+ * A unique value for each event.
+ */
+ messageId?: string
+ /**
+ * Timestamp that the event took place, in ISO 8601 format. e.g. 2019-06-12T19:11:01.152Z
+ */
+ timestamp: string
+ /**
+ * Additional information associated with the track() event
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+ /**
+ * Company ID associated with the event
+ */
+ groupId?: {
+ [k: string]: unknown
+ }
+}
From d581fcb03daea4fe96140d57ffb34d9a41fbea35 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 10 Oct 2023 14:55:50 +0100
Subject: [PATCH 023/389] tidying up trackey prior to deploy
---
.../src/destinations/trackey/index.ts | 9 +--------
1 file changed, 1 insertion(+), 8 deletions(-)
diff --git a/packages/destination-actions/src/destinations/trackey/index.ts b/packages/destination-actions/src/destinations/trackey/index.ts
index b461e5bd72..a73bccb1bb 100644
--- a/packages/destination-actions/src/destinations/trackey/index.ts
+++ b/packages/destination-actions/src/destinations/trackey/index.ts
@@ -10,7 +10,6 @@ const destination: DestinationDefinition = {
slug: 'actions-trackey',
mode: 'cloud',
description: 'Send Segment events to Trackey',
-
authentication: {
scheme: 'custom',
fields: {
@@ -30,12 +29,6 @@ const destination: DestinationDefinition = {
}
}
},
- onDelete: async () => {
- // Return a request that performs a GDPR delete for the provided Segment userId or anonymousId
- // provided in the payload. If your destination does not support GDPR deletion you should not
- // implement this function and should remove it completely.
- return true
- },
actions: {
track: {
title: 'track',
@@ -183,7 +176,7 @@ const destination: DestinationDefinition = {
default: { '@path': '$.timestamp' }
},
traits: {
- label: 'COmpany Traits',
+ label: 'Company Traits',
type: 'object',
required: false,
description: 'Company profile information',
From f6a6d3e840dd9bc62d58bad407a491667ad3ad7d Mon Sep 17 00:00:00 2001
From: Dan
Date: Tue, 10 Oct 2023 18:12:46 +0400
Subject: [PATCH 024/389] Optional `email` field in the Loops integration
(#1629)
* Update delete method to a POST
* commit test fix
* Make email optional in `createOrUpdateContact`
* Fixed test for missing `email`
* Re-instate original yarn.lock
* Added note about `email` being required
* Updated test
* slightly different approach
* Fix for `responses` carrying over between tests
---------
Co-authored-by: Adam Kaczmarek
Co-authored-by: Adam Kaczmarek
---
.../__snapshots__/snapshot.test.ts.snap | 1 -
.../__snapshots__/snapshot.test.ts.snap | 1 -
.../__tests__/index.test.ts | 34 +++++++++++++++++--
.../createOrUpdateContact/generated-types.ts | 4 +--
.../loops/createOrUpdateContact/index.ts | 4 +--
5 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/packages/destination-actions/src/destinations/loops/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/loops/__tests__/__snapshots__/snapshot.test.ts.snap
index ed065434fb..27df5a17ad 100644
--- a/packages/destination-actions/src/destinations/loops/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/loops/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -16,7 +16,6 @@ Object {
exports[`Testing snapshot for actions-loops destination: createOrUpdateContact action - required fields 1`] = `
Object {
- "email": "bivjag@ennaato.st",
"userId": "3dQ7ER]1HKW",
}
`;
diff --git a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/__snapshots__/snapshot.test.ts.snap
index caa2e0f849..971dd5c476 100644
--- a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -16,7 +16,6 @@ Object {
exports[`Testing snapshot for Loops's createOrUpdateContact destination action: required fields 1`] = `
Object {
- "email": "macepa@tariviz.sm",
"userId": "IAIhDY9yOUxjQs(FSFfe",
}
`;
diff --git a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/index.test.ts b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/index.test.ts
index 419e5b6188..0a69d9412b 100644
--- a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/__tests__/index.test.ts
@@ -2,7 +2,11 @@ import nock from 'nock'
import { createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
-const testDestination = createTestIntegration(Destination)
+let testDestination = createTestIntegration(Destination)
+beforeEach(() => {
+ nock.cleanAll()
+ testDestination = createTestIntegration(Destination)
+})
const LOOPS_API_KEY = 'some random secret'
@@ -14,7 +18,6 @@ describe('Loops.createOrUpdateContact', () => {
})
} catch (err) {
expect(err.message).toContain("missing the required field 'userId'.")
- expect(err.message).toContain("missing the required field 'email'.")
}
})
@@ -55,12 +58,33 @@ describe('Loops.createOrUpdateContact', () => {
expect(responses.length).toBe(1)
expect(responses[0].status).toBe(200)
+ expect(responses[0].data).toStrictEqual({
+ success: true,
+ id: 'someId'
+ })
+ })
+
+ it('should not work without email', async () => {
+ const testPayload = {
+ firstName: 'Ellen',
+ userId: 'some-id-1'
+ }
+ nock('https://app.loops.so/api/v1').put('/contacts/update', testPayload).reply(400, {
+ success: false,
+ message: 'userId not found and cannot create a new contact without an email.'
+ })
+ await expect(
+ testDestination.testAction('createOrUpdateContact', {
+ mapping: testPayload,
+ settings: { apiKey: LOOPS_API_KEY }
+ })
+ ).rejects.toThrow('Bad Request')
})
it('should work without optional fields', async () => {
const testPayload = {
email: 'test@example.com',
- userId: 'some-id-1'
+ userId: 'some-id-2'
}
nock('https://app.loops.so/api/v1').put('/contacts/update', testPayload).reply(200, {
success: true,
@@ -74,5 +98,9 @@ describe('Loops.createOrUpdateContact', () => {
expect(responses.length).toBe(1)
expect(responses[0].status).toBe(200)
+ expect(responses[0].data).toStrictEqual({
+ success: true,
+ id: 'someId'
+ })
})
})
diff --git a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/generated-types.ts b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/generated-types.ts
index be39d06ee5..6365c7c2f9 100644
--- a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/generated-types.ts
+++ b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/generated-types.ts
@@ -12,9 +12,9 @@ export interface Payload {
[k: string]: unknown
}
/**
- * Email address for the contact.
+ * Email address for the contact. This is required when creating new contacts.
*/
- email: string
+ email?: string
/**
* The contact's given name.
*/
diff --git a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/index.ts b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/index.ts
index 3565da201b..6097de88bd 100644
--- a/packages/destination-actions/src/destinations/loops/createOrUpdateContact/index.ts
+++ b/packages/destination-actions/src/destinations/loops/createOrUpdateContact/index.ts
@@ -23,10 +23,10 @@ const action: ActionDefinition = {
},
email: {
label: 'Contact Email',
- description: 'Email address for the contact.',
+ description: 'Email address for the contact. This is required when creating new contacts.',
type: 'string',
format: 'email',
- required: true,
+ required: false,
default: {
'@if': {
exists: { '@path': '$.traits.email' },
From 06f18a636bb05773edc0aef98cc1623058c9f865 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 10 Oct 2023 16:38:01 +0200
Subject: [PATCH 025/389] Registering trackey Destination
---
packages/destination-actions/src/destinations/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index 570498c125..335c13c8f5 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -131,6 +131,7 @@ register('6514281004d549fae3fd086a', './yahoo-audiences')
register('650bdf1a62fb34ef0a8058e1', './klaviyo')
register('6512d7f86bdccc3829fc4ac3', './optimizely-data-platform')
register('651c1db19de92d8e595ff55d', './hyperengage')
+register('65256052ac030f823df6c1a5', './trackey')
function register(id: MetadataId, destinationPath: string) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
From d9843a59ab362c2295981a3824385af6e238536c Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 10 Oct 2023 15:43:57 +0100
Subject: [PATCH 026/389] Publish
- @segment/action-destinations@3.221.0
- @segment/destinations-manifest@1.23.0
- @segment/analytics-browser-actions-braze-cloud-plugins@1.18.0
- @segment/analytics-browser-actions-braze@1.18.0
- @segment/analytics-browser-actions-tiktok-pixel@1.11.0
---
.../destinations/braze-cloud-plugins/package.json | 4 ++--
.../browser-destinations/destinations/braze/package.json | 2 +-
.../destinations/tiktok-pixel/package.json | 2 +-
packages/destination-actions/package.json | 2 +-
packages/destinations-manifest/package.json | 8 ++++----
5 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
index c7360e0af6..63cc0d9550 100644
--- a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
+++ b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze-cloud-plugins",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/analytics-browser-actions-braze": "^1.17.0",
+ "@segment/analytics-browser-actions-braze": "^1.18.0",
"@segment/browser-destination-runtime": "^1.14.0"
},
"peerDependencies": {
diff --git a/packages/browser-destinations/destinations/braze/package.json b/packages/browser-destinations/destinations/braze/package.json
index 00a28a8439..4aec1bcfc0 100644
--- a/packages/browser-destinations/destinations/braze/package.json
+++ b/packages/browser-destinations/destinations/braze/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/package.json b/packages/browser-destinations/destinations/tiktok-pixel/package.json
index c33e2f7d1f..e4ccfa3a94 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/package.json
+++ b/packages/browser-destinations/destinations/tiktok-pixel/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-tiktok-pixel",
- "version": "1.10.0",
+ "version": "1.11.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 8612b95020..350a92eda5 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.220.0",
+ "version": "3.221.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index dd22ed0c13..9fcd425a04 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destinations-manifest",
- "version": "1.22.0",
+ "version": "1.23.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
@@ -14,8 +14,8 @@
"dependencies": {
"@segment/analytics-browser-actions-adobe-target": "^1.15.0",
"@segment/analytics-browser-actions-amplitude-plugins": "^1.15.0",
- "@segment/analytics-browser-actions-braze": "^1.17.0",
- "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.17.0",
+ "@segment/analytics-browser-actions-braze": "^1.18.0",
+ "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.18.0",
"@segment/analytics-browser-actions-cdpresolution": "^1.2.0",
"@segment/analytics-browser-actions-commandbar": "^1.15.0",
"@segment/analytics-browser-actions-devrev": "^1.2.0",
@@ -36,7 +36,7 @@
"@segment/analytics-browser-actions-screeb": "^1.15.0",
"@segment/analytics-browser-actions-sprig": "^1.15.0",
"@segment/analytics-browser-actions-stackadapt": "^1.15.0",
- "@segment/analytics-browser-actions-tiktok-pixel": "^1.10.0",
+ "@segment/analytics-browser-actions-tiktok-pixel": "^1.11.0",
"@segment/analytics-browser-actions-upollo": "^1.15.0",
"@segment/analytics-browser-actions-userpilot": "^1.15.0",
"@segment/analytics-browser-actions-utils": "^1.15.0",
From 4f6dabbcb295bf4ff9334b4b28e80f8a9961174f Mon Sep 17 00:00:00 2001
From: Nick Aguilar
Date: Wed, 11 Oct 2023 14:27:01 -0700
Subject: [PATCH 027/389] Migrates `type: hidden` to `type: 'string', hidden:
true` (#1643)
* Refactors existing usages of type: hidden to type: string, hidden: true
* Removes references to type: 'hidden' in core
* Updates core unit test
---
.../src/__tests__/schema-validation.test.ts | 5 ++--
.../destination-kit/fields-to-jsonschema.ts | 1 -
packages/core/src/destination-kit/types.ts | 11 +-------
.../ambee/subscribeUserToCampaign/index.ts | 6 +++--
.../braze-cohorts/syncAudiences/index.ts | 9 ++++---
.../destinations/cordial/identities-fields.ts | 14 +++++-----
.../syncAudience/index.ts | 15 +++++++----
.../google-sheets/postSheet/index.ts | 3 ++-
.../syncAudience/index.ts | 18 ++++++++-----
.../updateAudience/index.ts | 12 ++++++---
.../livelike-cloud/trackEvent/index.ts | 3 ++-
.../syncAudience/index.ts | 12 ++++++---
.../trackEvent/index.ts | 3 ++-
.../outfunnel/forwardGroupEvent/index.ts | 27 +++++++++++--------
.../outfunnel/forwardIdentifyEvent/index.ts | 24 ++++++++++-------
.../outfunnel/forwardTrackEvent/index.ts | 24 ++++++++++-------
.../tiktok-audiences/properties.ts | 12 ++++++---
.../twilio-studio/triggerStudioFlow/index.ts | 9 ++++---
.../yahoo-audiences/updateSegment/index.ts | 18 ++++++++-----
19 files changed, 136 insertions(+), 90 deletions(-)
diff --git a/packages/core/src/__tests__/schema-validation.test.ts b/packages/core/src/__tests__/schema-validation.test.ts
index d5a691c4e2..0e6f76841e 100644
--- a/packages/core/src/__tests__/schema-validation.test.ts
+++ b/packages/core/src/__tests__/schema-validation.test.ts
@@ -111,11 +111,12 @@ describe('validateSchema', () => {
expect(payload).toMatchInlineSnapshot(`Object {}`)
})
- it('should not throw when type = hidden', () => {
+ it('should not throw when hidden = true', () => {
const hiddenSchema = fieldsToJsonSchema({
h: {
label: 'h',
- type: 'hidden'
+ type: 'string',
+ unsafe_hidden: true
}
})
diff --git a/packages/core/src/destination-kit/fields-to-jsonschema.ts b/packages/core/src/destination-kit/fields-to-jsonschema.ts
index 80a537f10a..38948485e3 100644
--- a/packages/core/src/destination-kit/fields-to-jsonschema.ts
+++ b/packages/core/src/destination-kit/fields-to-jsonschema.ts
@@ -6,7 +6,6 @@ function toJsonSchemaType(type: FieldTypeName): JSONSchema4TypeName | JSONSchema
case 'string':
case 'text':
case 'password':
- case 'hidden':
return 'string'
case 'datetime':
return ['string', 'number']
diff --git a/packages/core/src/destination-kit/types.ts b/packages/core/src/destination-kit/types.ts
index 5c30d8ee03..f5b5e9d3e0 100644
--- a/packages/core/src/destination-kit/types.ts
+++ b/packages/core/src/destination-kit/types.ts
@@ -83,16 +83,7 @@ export interface GlobalSetting {
}
/** The supported field type names */
-export type FieldTypeName =
- | 'string'
- | 'text'
- | 'number'
- | 'integer'
- | 'datetime'
- | 'boolean'
- | 'password'
- | 'object'
- | 'hidden'
+export type FieldTypeName = 'string' | 'text' | 'number' | 'integer' | 'datetime' | 'boolean' | 'password' | 'object'
/** The shape of an input field definition */
export interface InputField {
diff --git a/packages/destination-actions/src/destinations/ambee/subscribeUserToCampaign/index.ts b/packages/destination-actions/src/destinations/ambee/subscribeUserToCampaign/index.ts
index 056e2e59bf..13eb50379d 100644
--- a/packages/destination-actions/src/destinations/ambee/subscribeUserToCampaign/index.ts
+++ b/packages/destination-actions/src/destinations/ambee/subscribeUserToCampaign/index.ts
@@ -10,13 +10,15 @@ const action: ActionDefinition = {
label: 'Segment Library',
description:
'The Segment library used when the event was triggered. This Integration will only work with analytics.js or Mobile Segment libraries',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: { '@path': '$.context.library.name' }
},
platform: {
label: 'User Device Platform',
description: 'The platform of the device which generated the event e.g. "Android" or "iOS"',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: { '@path': '$.context.device.type' }
},
campaignId: {
diff --git a/packages/destination-actions/src/destinations/braze-cohorts/syncAudiences/index.ts b/packages/destination-actions/src/destinations/braze-cohorts/syncAudiences/index.ts
index 8b7cdf73ca..84ff91303b 100644
--- a/packages/destination-actions/src/destinations/braze-cohorts/syncAudiences/index.ts
+++ b/packages/destination-actions/src/destinations/braze-cohorts/syncAudiences/index.ts
@@ -47,7 +47,8 @@ const action: ActionDefinition = {
cohort_id: {
label: 'Cohort ID',
description: 'The Cohort Identifier',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_id'
@@ -56,7 +57,8 @@ const action: ActionDefinition = {
cohort_name: {
label: 'Cohort Name',
description: 'The name of Cohort',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_key'
@@ -92,7 +94,8 @@ const action: ActionDefinition = {
time: {
label: 'Time',
description: 'When the event occurred.',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.timestamp'
diff --git a/packages/destination-actions/src/destinations/cordial/identities-fields.ts b/packages/destination-actions/src/destinations/cordial/identities-fields.ts
index 1e84debb1c..897fb5c07e 100644
--- a/packages/destination-actions/src/destinations/cordial/identities-fields.ts
+++ b/packages/destination-actions/src/destinations/cordial/identities-fields.ts
@@ -1,17 +1,19 @@
-import {InputField} from "@segment/actions-core";
+import { InputField } from '@segment/actions-core'
-export const userIdentityFields : Record = {
+export const userIdentityFields: Record = {
segmentId: {
label: 'Segment User ID',
description: 'Segment User ID value',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.userId' }
},
anonymousId: {
label: 'Segment Anonymous ID',
description: 'Segment Anonymous ID value',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.anonymousId' }
},
@@ -22,7 +24,7 @@ export const userIdentityFields : Record = {
type: 'object',
required: false,
defaultObjectUI: 'keyvalue:only'
- },
+ }
}
-export default userIdentityFields;
+export default userIdentityFields
diff --git a/packages/destination-actions/src/destinations/dynamic-yield-audiences/syncAudience/index.ts b/packages/destination-actions/src/destinations/dynamic-yield-audiences/syncAudience/index.ts
index d613105774..46ee346b20 100644
--- a/packages/destination-actions/src/destinations/dynamic-yield-audiences/syncAudience/index.ts
+++ b/packages/destination-actions/src/destinations/dynamic-yield-audiences/syncAudience/index.ts
@@ -13,7 +13,8 @@ const action: ActionDefinition = {
segment_audience_key: {
label: 'Audience Key',
description: 'Segment Audience key / name',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_key'
@@ -23,7 +24,8 @@ const action: ActionDefinition = {
label: 'Segment Computation Action',
description:
"Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_class'
@@ -33,21 +35,24 @@ const action: ActionDefinition = {
segment_user_id: {
label: 'Segment User ID',
description: 'The Segment userId value.',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.userId' }
},
segment_anonymous_id: {
label: 'Segment Anonymous ID',
description: 'The Segment anonymousId value.',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.anonymousId' }
},
user_email: {
label: 'Email address',
description: "The user's email address",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: {
'@if': {
diff --git a/packages/destination-actions/src/destinations/google-sheets/postSheet/index.ts b/packages/destination-actions/src/destinations/google-sheets/postSheet/index.ts
index 5f3040a1f9..63757f3072 100644
--- a/packages/destination-actions/src/destinations/google-sheets/postSheet/index.ts
+++ b/packages/destination-actions/src/destinations/google-sheets/postSheet/index.ts
@@ -21,7 +21,8 @@ const action: ActionDefinition = {
label: 'Operation Type',
description:
"Describes the nature of the operation being performed. Only supported values are 'new' and 'updated'.",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: { '@path': '$.event' }
},
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
index edfc87cc95..4b4ebe53dc 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
@@ -13,7 +13,8 @@ const action: ActionDefinition = {
segment_audience_key: {
label: 'Audience Key',
description: 'Segment Audience key to which user identifier should be added or removed',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_key'
@@ -23,7 +24,8 @@ const action: ActionDefinition = {
label: 'Segment Computation Action',
description:
"Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_class'
@@ -41,21 +43,24 @@ const action: ActionDefinition = {
segment_user_id: {
label: 'Segment User ID',
description: 'The Segment userId value.',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.userId' }
},
segment_anonymous_id: {
label: 'Segment Anonymous ID',
description: 'The Segment anonymousId value.',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: { '@path': '$.anonymousId' }
},
user_email: {
label: 'Email address',
description: "The user's email address",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: {
'@if': {
@@ -103,7 +108,8 @@ const action: ActionDefinition = {
audience_action: {
label: 'Audience Action',
description: 'Indicates if the user will be added or removed from the Audience',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
choices: [
{ label: CONSTANTS.ADD as AudienceAction, value: CONSTANTS.ADD as AudienceAction },
{ label: CONSTANTS.REMOVE as AudienceAction, value: CONSTANTS.REMOVE as AudienceAction }
diff --git a/packages/destination-actions/src/destinations/linkedin-audiences/updateAudience/index.ts b/packages/destination-actions/src/destinations/linkedin-audiences/updateAudience/index.ts
index 9d1f856743..6648981d97 100644
--- a/packages/destination-actions/src/destinations/linkedin-audiences/updateAudience/index.ts
+++ b/packages/destination-actions/src/destinations/linkedin-audiences/updateAudience/index.ts
@@ -28,7 +28,8 @@ const action: ActionDefinition = {
email: {
label: 'User Email',
description: "The user's email address to send to LinkedIn.",
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.context.traits.email' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.context.traits.email' in Personas events.
default: {
'@path': '$.context.traits.email'
}
@@ -36,7 +37,8 @@ const action: ActionDefinition = {
google_advertising_id: {
label: 'User Google Advertising ID',
description: "The user's Google Advertising ID to send to LinkedIn.",
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.context.device.advertisingId' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.context.device.advertisingId' in Personas events.
default: {
'@path': '$.context.device.advertisingId'
}
@@ -45,7 +47,8 @@ const action: ActionDefinition = {
label: 'LinkedIn Source Segment ID',
description:
"A Segment-specific key associated with the LinkedIn DMP Segment. This is the lookup key Segment uses to fetch the DMP Segment from LinkedIn's API.",
- type: 'hidden', // This field is hidden from customers because the desired value always appears at '$.properties.audience_key' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at '$.properties.audience_key' in Personas events.
default: {
'@path': '$.properties.audience_key'
}
@@ -60,7 +63,8 @@ const action: ActionDefinition = {
event_name: {
label: 'Event Name',
description: 'The name of the current Segment event.',
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.event' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.event' in Personas events.
default: {
'@path': '$.event'
}
diff --git a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts
index ddba9f054d..34634b8809 100644
--- a/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts
+++ b/packages/destination-actions/src/destinations/livelike-cloud/trackEvent/index.ts
@@ -67,7 +67,8 @@ const action: ActionDefinition = {
label: 'Segment Anonymous ID',
description: 'Segment Anonymous ID.',
required: false,
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: {
'@path': '$.anonymousId'
}
diff --git a/packages/destination-actions/src/destinations/optimizely-advanced-audience-targeting/syncAudience/index.ts b/packages/destination-actions/src/destinations/optimizely-advanced-audience-targeting/syncAudience/index.ts
index 7d4ec5205c..2a58d7522f 100644
--- a/packages/destination-actions/src/destinations/optimizely-advanced-audience-targeting/syncAudience/index.ts
+++ b/packages/destination-actions/src/destinations/optimizely-advanced-audience-targeting/syncAudience/index.ts
@@ -33,7 +33,8 @@ const action: ActionDefinition = {
custom_audience_name: {
label: 'Custom Audience Name',
description: 'Name of custom audience to add or remove the user from',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_key'
@@ -42,7 +43,8 @@ const action: ActionDefinition = {
segment_computation_action: {
label: 'Segment Computation Action',
description: 'Segment computation class used to determine payload is for an Audience',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_class'
@@ -52,7 +54,8 @@ const action: ActionDefinition = {
segment_computation_id: {
label: 'Segment Computation ID',
description: 'Segment computation ID',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_id'
@@ -73,7 +76,8 @@ const action: ActionDefinition = {
},
timestamp: {
label: 'Timestamp',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'Timestamp indicates when the user was added or removed from the Audience',
default: {
diff --git a/packages/destination-actions/src/destinations/optimizely-feature-experimentation-actions/trackEvent/index.ts b/packages/destination-actions/src/destinations/optimizely-feature-experimentation-actions/trackEvent/index.ts
index 4dd13db520..61509c7b80 100644
--- a/packages/destination-actions/src/destinations/optimizely-feature-experimentation-actions/trackEvent/index.ts
+++ b/packages/destination-actions/src/destinations/optimizely-feature-experimentation-actions/trackEvent/index.ts
@@ -93,7 +93,8 @@ const action: ActionDefinition = {
},
uuid: {
label: 'Unique ID',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'Unique ID for the event',
required: true,
default: {
diff --git a/packages/destination-actions/src/destinations/outfunnel/forwardGroupEvent/index.ts b/packages/destination-actions/src/destinations/outfunnel/forwardGroupEvent/index.ts
index 86b98d7dbb..f9c2d827de 100644
--- a/packages/destination-actions/src/destinations/outfunnel/forwardGroupEvent/index.ts
+++ b/packages/destination-actions/src/destinations/outfunnel/forwardGroupEvent/index.ts
@@ -1,7 +1,7 @@
-import { ActionDefinition } from '@segment/actions-core';
-import type { Settings } from '../generated-types';
-import type { Payload } from './generated-types';
-import { getEndpoint } from '../utils';
+import { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { getEndpoint } from '../utils'
const action: ActionDefinition = {
title: 'Forward group event',
@@ -9,14 +9,16 @@ const action: ActionDefinition = {
defaultSubscription: 'type = "group"',
fields: {
action: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'Indicates which action was triggered',
label: 'Action name',
default: 'group'
},
user_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'The identifier of the user',
label: 'User ID',
default: {
@@ -24,7 +26,8 @@ const action: ActionDefinition = {
}
},
anonymous_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'Anonymous ID of the user',
label: 'Anonymous ID',
default: {
@@ -32,7 +35,8 @@ const action: ActionDefinition = {
}
},
group_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'ID of the group',
label: 'Group ID',
default: {
@@ -48,7 +52,8 @@ const action: ActionDefinition = {
}
},
timestamp: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'The time the event occured in UTC',
label: 'Event timestamp',
@@ -75,12 +80,12 @@ const action: ActionDefinition = {
},
perform: async (request, { settings, payload }) => {
- const endpoint = getEndpoint(settings.userId);
+ const endpoint = getEndpoint(settings.userId)
return request(endpoint, {
method: 'POST',
json: payload
- });
+ })
}
}
diff --git a/packages/destination-actions/src/destinations/outfunnel/forwardIdentifyEvent/index.ts b/packages/destination-actions/src/destinations/outfunnel/forwardIdentifyEvent/index.ts
index 74a529dd1a..ccb18d842d 100644
--- a/packages/destination-actions/src/destinations/outfunnel/forwardIdentifyEvent/index.ts
+++ b/packages/destination-actions/src/destinations/outfunnel/forwardIdentifyEvent/index.ts
@@ -1,7 +1,7 @@
-import { ActionDefinition } from '@segment/actions-core';
-import type { Settings } from '../generated-types';
-import type { Payload } from './generated-types';
-import { getEndpoint } from '../utils';
+import { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { getEndpoint } from '../utils'
const action: ActionDefinition = {
title: 'Forward identify event',
@@ -9,14 +9,16 @@ const action: ActionDefinition = {
defaultSubscription: 'type = "identify"',
fields: {
action: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'Indicates which action was triggered',
label: 'Action name',
default: 'identify'
},
user_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'The identifier of the user',
label: 'User ID',
default: {
@@ -24,7 +26,8 @@ const action: ActionDefinition = {
}
},
anonymous_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'Anonymous ID of the user',
label: 'Anonymous ID',
default: {
@@ -41,7 +44,8 @@ const action: ActionDefinition = {
}
},
timestamp: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'The time the event occured in UTC',
label: 'Event timestamp',
@@ -68,12 +72,12 @@ const action: ActionDefinition = {
},
perform: async (request, { settings, payload }) => {
- const endpoint = getEndpoint(settings.userId);
+ const endpoint = getEndpoint(settings.userId)
return request(endpoint, {
method: 'POST',
json: payload
- });
+ })
}
}
diff --git a/packages/destination-actions/src/destinations/outfunnel/forwardTrackEvent/index.ts b/packages/destination-actions/src/destinations/outfunnel/forwardTrackEvent/index.ts
index 84e2d4d7c8..c6d837d01c 100644
--- a/packages/destination-actions/src/destinations/outfunnel/forwardTrackEvent/index.ts
+++ b/packages/destination-actions/src/destinations/outfunnel/forwardTrackEvent/index.ts
@@ -1,7 +1,7 @@
-import { ActionDefinition } from '@segment/actions-core';
-import type { Settings } from '../generated-types';
-import type { Payload } from './generated-types';
-import { getEndpoint } from '../utils';
+import { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { getEndpoint } from '../utils'
const action: ActionDefinition = {
title: 'Forward track event',
@@ -9,7 +9,8 @@ const action: ActionDefinition = {
defaultSubscription: 'type = "track"',
fields: {
action: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'Indicates which action was triggered',
label: 'Action name',
@@ -25,7 +26,8 @@ const action: ActionDefinition = {
}
},
user_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'The identifier of the user who performed the event',
label: 'User ID',
default: {
@@ -33,7 +35,8 @@ const action: ActionDefinition = {
}
},
anonymous_id: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'Anonymous ID of the user',
label: 'Anonymous ID',
default: {
@@ -61,7 +64,8 @@ const action: ActionDefinition = {
}
},
timestamp: {
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
description: 'The time the event occured in UTC',
label: 'Event timestamp',
@@ -87,7 +91,7 @@ const action: ActionDefinition = {
}
},
perform: async (request, { settings, payload }) => {
- const endpoint = getEndpoint(settings.userId);
+ const endpoint = getEndpoint(settings.userId)
return request(endpoint, {
method: 'POST',
@@ -96,4 +100,4 @@ const action: ActionDefinition = {
}
}
-export default action;
+export default action
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/properties.ts b/packages/destination-actions/src/destinations/tiktok-audiences/properties.ts
index 21c609ffd5..74391c115b 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/properties.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/properties.ts
@@ -42,7 +42,8 @@ export const custom_audience_name: InputField = {
export const email: InputField = {
label: 'User Email',
description: "The user's email address to send to TikTok.",
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.context.traits.email' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.context.traits.email' in Personas events.
default: {
'@path': '$.context.traits.email'
}
@@ -58,7 +59,8 @@ export const send_email: InputField = {
export const advertising_id: InputField = {
label: 'User Advertising ID',
description: "The user's mobile advertising ID to send to TikTok. This could be a GAID, IDFA, or AAID",
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.context.device.advertisingId' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.context.device.advertisingId' in Personas events.
default: {
'@path': '$.context.device.advertisingId'
}
@@ -75,7 +77,8 @@ export const send_advertising_id: InputField = {
export const event_name: InputField = {
label: 'Event Name',
description: 'The name of the current Segment event.',
- type: 'hidden', // This field is hidden from customers because the desired value always appears at path '$.event' in Personas events.
+ type: 'string',
+ unsafe_hidden: true, // This field is hidden from customers because the desired value always appears at path '$.event' in Personas events.
default: {
'@path': '$.event'
}
@@ -91,7 +94,8 @@ export const enable_batching: InputField = {
export const external_audience_id: InputField = {
label: 'External Audience ID',
description: "The Audience ID in TikTok's DB.",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: {
'@path': '$.context.personas.external_audience_id'
}
diff --git a/packages/destination-actions/src/destinations/twilio-studio/triggerStudioFlow/index.ts b/packages/destination-actions/src/destinations/twilio-studio/triggerStudioFlow/index.ts
index e62cc0311d..e3c9bd65fd 100644
--- a/packages/destination-actions/src/destinations/twilio-studio/triggerStudioFlow/index.ts
+++ b/packages/destination-actions/src/destinations/twilio-studio/triggerStudioFlow/index.ts
@@ -37,18 +37,21 @@ const action: ActionDefinition = {
userId: {
label: 'User ID',
description: 'A Distinct User ID',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: { '@path': '$.userId' }
},
anonymousId: {
label: 'Anonymous ID',
description: 'A Distinct External ID',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: { '@path': '$.anonymousId' }
},
eventType: {
label: 'Event type',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
description: 'The type of the event being performed.',
required: true,
default: {
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
index 53ea8e29ad..8b80419ca6 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
@@ -12,7 +12,8 @@ const action: ActionDefinition = {
segment_audience_id: {
label: 'Segment Audience Id', // Maps to Yahoo Taxonomy Segment Id
description: 'Segment Audience Id (aud_...). Maps to "Id" of a Segment node in Yahoo taxonomy',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_id'
@@ -21,7 +22,8 @@ const action: ActionDefinition = {
segment_audience_key: {
label: 'Segment Audience Key',
description: 'Segment Audience Key. Maps to the "Name" of the Segment node in Yahoo taxonomy',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_key'
@@ -46,7 +48,8 @@ const action: ActionDefinition = {
label: 'Segment Computation Action',
description:
"Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: true,
default: {
'@path': '$.context.personas.computation_class'
@@ -70,7 +73,8 @@ const action: ActionDefinition = {
email: {
label: 'User Email',
description: 'Email address of a user',
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
required: false,
default: {
'@if': {
@@ -83,7 +87,8 @@ const action: ActionDefinition = {
advertising_id: {
label: 'User Mobile Advertising ID',
description: "User's mobile advertising Id",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: {
'@path': '$.context.device.advertisingId'
},
@@ -92,7 +97,8 @@ const action: ActionDefinition = {
device_type: {
label: 'User Mobile Device Type', // This field is required to determine the type of the advertising Id: IDFA or GAID
description: "User's mobile device type",
- type: 'hidden',
+ type: 'string',
+ unsafe_hidden: true,
default: {
'@path': '$.context.device.type'
},
From bb112a5107107066a3fbc439b75e7909a06fd901 Mon Sep 17 00:00:00 2001
From: Christopher Radek <14189820+chrisradek@users.noreply.github.com>
Date: Fri, 13 Oct 2023 10:15:55 -0700
Subject: [PATCH 028/389] Removes the concurrency=1 setting from the top-level
build commands (#1650)
---
package.json | 4 ++--
packages/actions-shared/package.json | 2 +-
.../browser-destination-runtime/package.json | 20 ++++++++++++++---
.../tsconfig.build.json | 22 +++++++++++++++++++
.../browser-destination-runtime/tsconfig.json | 11 ++++++++--
.../browser-destinations/tsconfig.build.json | 11 ++++++++--
packages/cli/package.json | 2 +-
packages/destination-actions/package.json | 2 +-
.../destination-subscriptions/package.json | 2 +-
tsconfig.json | 1 +
10 files changed, 64 insertions(+), 13 deletions(-)
create mode 100644 packages/browser-destination-runtime/tsconfig.build.json
diff --git a/package.json b/package.json
index 919d3caead..3642661243 100644
--- a/package.json
+++ b/package.json
@@ -18,8 +18,8 @@
"cli-internal": "yarn workspace @segment/actions-cli-internal",
"core": "yarn workspace @segment/actions-core",
"bootstrap": "lerna bootstrap",
- "build": "./bin/run generate:types && lerna run build --concurrency 1 --stream --ignore @segment/actions-cli-internal && yarn browser build-web",
- "build:browser-destinations": "yarn lerna run build --concurrency 1 --scope=@segment/destinations-manifest --include-dependencies --stream && yarn browser build-web",
+ "build": "./bin/run generate:types && lerna run build --stream --ignore @segment/actions-cli-internal && yarn browser build-web",
+ "build:browser-destinations": "yarn lerna run build --scope=@segment/destinations-manifest --include-dependencies --stream && yarn browser build-web",
"types": "./bin/run generate:types",
"validate": "./bin/run validate",
"lint": "ls -d ./packages/* | xargs -I {} eslint '{}/**/*.ts' --cache",
diff --git a/packages/actions-shared/package.json b/packages/actions-shared/package.json
index 0b7290b9c7..1cf8cd6f70 100644
--- a/packages/actions-shared/package.json
+++ b/packages/actions-shared/package.json
@@ -23,7 +23,7 @@
"registry": "https://registry.npmjs.org"
},
"scripts": {
- "build": "yarn clean && yarn tsc -b tsconfig.build.json",
+ "build": "yarn tsc -b tsconfig.build.json",
"clean": "tsc -b tsconfig.build.json --clean",
"postclean": "rm -rf dist",
"prepublishOnly": "yarn build",
diff --git a/packages/browser-destination-runtime/package.json b/packages/browser-destination-runtime/package.json
index e02c841693..d48a2f58ee 100644
--- a/packages/browser-destination-runtime/package.json
+++ b/packages/browser-destination-runtime/package.json
@@ -7,9 +7,11 @@
"registry": "https://registry.npmjs.org"
},
"scripts": {
- "build": "yarn build:esm && yarn build:cjs",
- "build:esm": "tsc --outDir ./dist/esm",
- "build:cjs": "tsc --module commonjs --outDir ./dist/cjs"
+ "build-ts": "yarn tsc -p tsconfig.build.json",
+ "build": "yarn build-ts && yarn build:esm && yarn build:cjs",
+ "build:esm": "tsc -p tsconfig.build.json --outDir ./dist/esm",
+ "build:cjs": "tsc -p tsconfig.build.json --module commonjs --outDir ./dist/cjs",
+ "clean": "tsc -b tsconfig.build.json --clean"
},
"exports": {
".": {
@@ -67,5 +69,17 @@
},
"peerDependencies": {
"@segment/analytics-next": "*"
+ },
+ "jest": {
+ "preset": "ts-jest",
+ "testEnvironment": "node",
+ "modulePathIgnorePatterns": [
+ "/dist/"
+ ],
+ "moduleNameMapper": {
+ "@segment/ajv-human-errors": "/../ajv-human-errors/src",
+ "@segment/actions-core": "/../core/src",
+ "@segment/destination-subscriptions": "/../destination-subscriptions/src"
+ }
}
}
diff --git a/packages/browser-destination-runtime/tsconfig.build.json b/packages/browser-destination-runtime/tsconfig.build.json
new file mode 100644
index 0000000000..8c38965829
--- /dev/null
+++ b/packages/browser-destination-runtime/tsconfig.build.json
@@ -0,0 +1,22 @@
+{
+ "extends": "../../tsconfig.json",
+ "compilerOptions": {
+ "module": "esnext",
+ "composite": true,
+ "outDir": "dist",
+ "rootDir": "src",
+ "allowJs": true,
+ "importHelpers": true,
+ "lib": ["es2020", "dom"],
+ "baseUrl": ".",
+ "paths": {
+ "@segment/actions-core/*": ["../core/src/*"]
+ }
+ },
+ "exclude": ["**/__tests__/**/*.ts"],
+ "include": ["src"],
+ "references": [
+ { "path": "../core/tsconfig.build.json" },
+ { "path": "../destination-subscriptions/tsconfig.build.json" }
+ ]
+}
diff --git a/packages/browser-destination-runtime/tsconfig.json b/packages/browser-destination-runtime/tsconfig.json
index b311e107d5..81a9959f93 100644
--- a/packages/browser-destination-runtime/tsconfig.json
+++ b/packages/browser-destination-runtime/tsconfig.json
@@ -3,7 +3,14 @@
"compilerOptions": {
"module": "esnext",
"removeComments": false,
- "baseUrl": "."
+ "baseUrl": ".",
+ "paths": {
+ "@segment/actions-core": ["../core/src"],
+ "@segment/actions-core/*": ["../core/src/*"],
+ "@segment/actions-shared": ["../actions-shared/src"],
+ "@segment/action-destinations": ["../destination-actions/src"],
+ "@segment/destination-subscriptions": ["../destination-subscriptions/src"]
+ }
},
"exclude": ["dist"]
-}
\ No newline at end of file
+}
diff --git a/packages/browser-destinations/tsconfig.build.json b/packages/browser-destinations/tsconfig.build.json
index 8c38965829..907c54e8a2 100644
--- a/packages/browser-destinations/tsconfig.build.json
+++ b/packages/browser-destinations/tsconfig.build.json
@@ -10,13 +10,20 @@
"lib": ["es2020", "dom"],
"baseUrl": ".",
"paths": {
- "@segment/actions-core/*": ["../core/src/*"]
+ "@segment/actions-core": ["../core/src"],
+ "@segment/actions-core/*": ["../core/src/*"],
+ "@segment/actions-shared": ["../actions-shared/src"],
+ "@segment/action-destinations": ["../destination-actions/src"],
+ "@segment/destination-subscriptions": ["../destination-subscriptions/src"],
+ "@segment/browser-destination-runtime": ["../browser-destination-runtime/src"],
+ "@segment/browser-destination-runtime/*": ["../browser-destination-runtime/src/*"]
}
},
"exclude": ["**/__tests__/**/*.ts"],
"include": ["src"],
"references": [
{ "path": "../core/tsconfig.build.json" },
- { "path": "../destination-subscriptions/tsconfig.build.json" }
+ { "path": "../destination-subscriptions/tsconfig.build.json" },
+ { "path": "../browser-destination-runtime/tsconfig.build.json" }
]
}
diff --git a/packages/cli/package.json b/packages/cli/package.json
index c2807198ed..816184d4ad 100644
--- a/packages/cli/package.json
+++ b/packages/cli/package.json
@@ -26,7 +26,7 @@
"scripts": {
"postpack": "rm -f oclif.manifest.json",
"prepack": "yarn build && oclif-dev manifest && oclif-dev readme",
- "build": "yarn clean && yarn tsc -b tsconfig.build.json",
+ "build": "yarn tsc -b tsconfig.build.json",
"clean": "tsc -b tsconfig.build.json --clean",
"postclean": "rm -rf dist",
"create:destination": "./bin/run init",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 350a92eda5..49c77ba175 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -23,7 +23,7 @@
"registry": "https://registry.npmjs.org"
},
"scripts": {
- "build": "yarn clean && yarn tsc -b tsconfig.build.json",
+ "build": "yarn tsc -b tsconfig.build.json",
"clean": "tsc -b tsconfig.build.json --clean",
"postclean": "rm -rf dist",
"prepublishOnly": "yarn build",
diff --git a/packages/destination-subscriptions/package.json b/packages/destination-subscriptions/package.json
index 5b0ae6fe8b..38c20ab368 100644
--- a/packages/destination-subscriptions/package.json
+++ b/packages/destination-subscriptions/package.json
@@ -9,7 +9,7 @@
"directory": "packages/destination-subscriptions"
},
"scripts": {
- "build": "yarn clean && yarn build:cjs && yarn build:esm",
+ "build": "yarn build:cjs && yarn build:esm",
"build:cjs": "yarn tsc -p tsconfig.build.json -m commonjs --outDir dist/cjs",
"build:esm": "yarn tsc -p tsconfig.build.json -m es2015 --outDir dist/esm",
"clean": "tsc -b tsconfig.build.json --clean",
diff --git a/tsconfig.json b/tsconfig.json
index 38a5caf050..c49deef7ec 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -20,6 +20,7 @@
"references": [
{ "path": "./packages/ajv-human-errors/tsconfig.build.json" },
{ "path": "./packages/browser-destinations/tsconfig.build.json" },
+ { "path": "./packages/browser-destination-runtime/tsconfig.build.json" },
{ "path": "./packages/core/tsconfig.build.json" },
{ "path": "./packages/destination-actions/tsconfig.build.json" },
{ "path": "./packages/destination-subscriptions/tsconfig.build.json" },
From 0e2afc58adc9b54ce21f720045e7d5217d727625 Mon Sep 17 00:00:00 2001
From: harsh-joshi99 <129737395+harsh-joshi99@users.noreply.github.com>
Date: Mon, 16 Oct 2023 12:37:24 +0530
Subject: [PATCH 029/389] Add upsert profile, track event and order completed
actions to klaviyo (#1645)
* Add upsert profile and track event actions to klaviyo
* Add order complete action to klaviyo
* Address PR comments
---
.../__snapshots__/snapshot.test.ts.snap | 102 +++++++++++
.../klaviyo/__tests__/snapshot.test.ts | 43 +++++
.../src/destinations/klaviyo/config.ts | 2 +
.../src/destinations/klaviyo/index.ts | 11 +-
.../__snapshots__/snapshot.test.ts.snap | 36 ++++
.../orderCompleted/__tests__/index.test.ts | 142 +++++++++++++++
.../orderCompleted/__tests__/snapshot.test.ts | 42 +++++
.../klaviyo/orderCompleted/generated-types.ts | 54 ++++++
.../klaviyo/orderCompleted/index.ts | 155 +++++++++++++++++
.../__snapshots__/snapshot.test.ts.snap | 36 ++++
.../trackEvent/__tests__/index.test.ts | 121 +++++++++++++
.../trackEvent/__tests__/snapshot.test.ts | 42 +++++
.../klaviyo/trackEvent/generated-types.ts | 43 +++++
.../destinations/klaviyo/trackEvent/index.ts | 121 +++++++++++++
.../src/destinations/klaviyo/types.ts | 64 +++++++
.../__snapshots__/snapshot.test.ts.snap | 32 ++++
.../upsertProfile/__tests__/index.test.ts | 141 +++++++++++++++
.../upsertProfile/__tests__/snapshot.test.ts | 42 +++++
.../klaviyo/upsertProfile/generated-types.ts | 51 +++++-
.../klaviyo/upsertProfile/index.ts | 163 +++++++++++++++++-
20 files changed, 1433 insertions(+), 10 deletions(-)
create mode 100644 packages/destination-actions/src/destinations/klaviyo/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/klaviyo/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/config.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/orderCompleted/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/orderCompleted/index.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/trackEvent/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/types.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/snapshot.test.ts
diff --git a/packages/destination-actions/src/destinations/klaviyo/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/klaviyo/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..51139559f6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,102 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-klaviyo destination: orderCompleted action - all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "metric": Object {
+ "data": Object {
+ "attributes": Object {
+ "name": "Order Completed",
+ },
+ "type": "metric",
+ },
+ },
+ "profile": Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "rafebezuv@micfeoz.zm",
+ "other_properties": Object {
+ "testType": "PE*zlOgIPA]mVozMLBaL",
+ },
+ "phone_number": "PE*zlOgIPA]mVozMLBaL",
+ },
+ "type": "profile",
+ },
+ },
+ "properties": Object {
+ "testType": "PE*zlOgIPA]mVozMLBaL",
+ },
+ "time": "2021-02-01T00:00:00.000Z",
+ "value": 83414764297912.31,
+ },
+ "type": "event",
+ },
+}
+`;
+
+exports[`Testing snapshot for actions-klaviyo destination: trackEvent action - all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "metric": Object {
+ "data": Object {
+ "attributes": Object {
+ "name": "mTdOx(Nl)",
+ },
+ "type": "metric",
+ },
+ },
+ "profile": Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "ujoeri@ifosi.kp",
+ "other_properties": Object {
+ "testType": "mTdOx(Nl)",
+ },
+ "phone_number": "mTdOx(Nl)",
+ },
+ "type": "profile",
+ },
+ },
+ "properties": Object {
+ "testType": "mTdOx(Nl)",
+ },
+ "time": "2021-02-01T00:00:00.000Z",
+ "value": -35080566000844.8,
+ },
+ "type": "event",
+ },
+}
+`;
+
+exports[`Testing snapshot for actions-klaviyo destination: upsertProfile action - all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "rob@cagtud.eu",
+ "external_id": "$Fd4HHQmxNI0jTCTt(t",
+ "first_name": "$Fd4HHQmxNI0jTCTt(t",
+ "image": "$Fd4HHQmxNI0jTCTt(t",
+ "last_name": "$Fd4HHQmxNI0jTCTt(t",
+ "location": Object {
+ "address1": "$Fd4HHQmxNI0jTCTt(t",
+ "address2": "$Fd4HHQmxNI0jTCTt(t",
+ "city": "$Fd4HHQmxNI0jTCTt(t",
+ "country": "$Fd4HHQmxNI0jTCTt(t",
+ "latitude": "$Fd4HHQmxNI0jTCTt(t",
+ "longitude": "$Fd4HHQmxNI0jTCTt(t",
+ "region": "$Fd4HHQmxNI0jTCTt(t",
+ "zip": "$Fd4HHQmxNI0jTCTt(t",
+ },
+ "organization": "$Fd4HHQmxNI0jTCTt(t",
+ "phone_number": "$Fd4HHQmxNI0jTCTt(t",
+ "properties": Object {
+ "testType": "$Fd4HHQmxNI0jTCTt(t",
+ },
+ "title": "$Fd4HHQmxNI0jTCTt(t",
+ },
+ "type": "profile",
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/klaviyo/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/klaviyo/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..08427e84d2
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/__tests__/snapshot.test.ts
@@ -0,0 +1,43 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-klaviyo'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/config.ts b/packages/destination-actions/src/destinations/klaviyo/config.ts
new file mode 100644
index 0000000000..37fb5a6316
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/config.ts
@@ -0,0 +1,2 @@
+export const API_URL = 'https://a.klaviyo.com/api'
+export const REVISION_DATE = '2023-09-15'
diff --git a/packages/destination-actions/src/destinations/klaviyo/index.ts b/packages/destination-actions/src/destinations/klaviyo/index.ts
index fa43643603..2efaca325e 100644
--- a/packages/destination-actions/src/destinations/klaviyo/index.ts
+++ b/packages/destination-actions/src/destinations/klaviyo/index.ts
@@ -2,8 +2,11 @@ import type { DestinationDefinition } from '@segment/actions-core'
import type { Settings } from './generated-types'
import upsertProfile from './upsertProfile'
+import { API_URL, REVISION_DATE } from './config'
-const API_URL = 'https://a.klaviyo.com/api'
+import trackEvent from './trackEvent'
+
+import orderCompleted from './orderCompleted'
const destination: DestinationDefinition = {
name: 'Klaviyo (Actions)',
@@ -51,13 +54,15 @@ const destination: DestinationDefinition = {
headers: {
Authorization: `Klaviyo-API-Key ${settings.api_key}`,
Accept: 'application/json',
- revision: new Date().toISOString().slice(0, 10)
+ revision: REVISION_DATE
}
}
},
actions: {
- upsertProfile
+ upsertProfile,
+ trackEvent,
+ orderCompleted
}
}
diff --git a/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..7cc6800285
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,36 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Klaviyo's orderCompleted destination action: all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "metric": Object {
+ "data": Object {
+ "attributes": Object {
+ "name": "Order Completed",
+ },
+ "type": "metric",
+ },
+ },
+ "profile": Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "tobul@dij.uz",
+ "other_properties": Object {
+ "testType": "923^%f]tQn]lN2o",
+ },
+ "phone_number": "923^%f]tQn]lN2o",
+ },
+ "type": "profile",
+ },
+ },
+ "properties": Object {
+ "testType": "923^%f]tQn]lN2o",
+ },
+ "time": "2021-02-01T00:00:00.000Z",
+ "value": 28946631197982.72,
+ },
+ "type": "event",
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/index.test.ts b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/index.test.ts
new file mode 100644
index 0000000000..b5be238c9e
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/index.test.ts
@@ -0,0 +1,142 @@
+import nock from 'nock'
+import { IntegrationError, createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Definition from '../../index'
+import { API_URL } from '../../config'
+
+const testDestination = createTestIntegration(Definition)
+const apiKey = 'fake-api-key'
+
+export const settings = {
+ api_key: apiKey
+}
+
+const createProfile = (email: string, phoneNumber: string) => ({
+ data: {
+ type: 'profile',
+ attributes: {
+ email,
+ phone_number: phoneNumber
+ }
+ }
+})
+
+const createMetric = (name: string) => ({
+ data: {
+ type: 'metric',
+ attributes: {
+ name
+ }
+ }
+})
+
+const createRequestBody = (
+ properties: Record,
+ value: number,
+ metricName: string,
+ profile: { email: string; phone_number: string }
+) => ({
+ data: {
+ type: 'event',
+ attributes: {
+ properties,
+ value,
+ metric: createMetric(metricName),
+ profile: createProfile(profile.email, profile.phone_number)
+ }
+ }
+})
+
+describe('Order Completed', () => {
+ it('should throw error if no email or phone_number is provided', async () => {
+ const event = createTestEvent({ type: 'track' })
+ const mapping = { profile: {}, metric_name: 'fake-name', properties: {} }
+
+ await expect(testDestination.testAction('orderCompleted', { event, mapping, settings })).rejects.toThrowError(
+ IntegrationError
+ )
+ })
+
+ it('should successfully track event if proper parameters are provided', async () => {
+ const profile = { email: 'test@example.com', phone_number: '1234567890' }
+ const properties = { key: 'value' }
+ const metricName = 'Order Completed'
+ const value = 10
+
+ const requestBody = createRequestBody(properties, value, metricName, profile)
+
+ nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ timestamp: '2022-01-01T00:00:00.000Z'
+ })
+
+ const mapping = { profile, metric_name: metricName, properties, value }
+
+ await expect(testDestination.testAction('orderCompleted', { event, mapping, settings })).resolves.not.toThrowError()
+ })
+
+ it('should throw an error if the API request fails', async () => {
+ const profile = { email: 'test@example.com', phone_number: '1234567890' }
+ const properties = { key: 'value' }
+ const metricName = 'Order Completed'
+ const value = 10
+
+ const requestBody = createRequestBody(properties, value, metricName, profile)
+
+ nock(`${API_URL}`).post('/events/', requestBody).reply(500, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ timestamp: '2022-01-01T00:00:00.000Z'
+ })
+
+ const mapping = { profile, metric_name: metricName, properties, value }
+
+ await expect(testDestination.testAction('orderCompleted', { event, mapping, settings })).rejects.toThrowError(
+ 'Internal Server Error'
+ )
+ })
+
+ it('should successfully track event with products array', async () => {
+ const products = [
+ {
+ value: 10,
+ properties: { key: 'value' }
+ }
+ ]
+
+ const profile = { email: 'test@example.com', phone_number: '1234567890' }
+ const properties = { key: 'value' }
+ const metricName = 'Order Completed'
+ const value = 10
+
+ const event = createTestEvent({
+ type: 'track',
+ timestamp: '2022-01-01T00:00:00.000Z'
+ })
+
+ const mapping = {
+ profile,
+ metric_name: metricName,
+ properties,
+ value,
+ products: products
+ }
+
+ const requestBodyForEvent = createRequestBody(properties, value, metricName, profile)
+
+ nock(`${API_URL}`).post(`/events/`, requestBodyForEvent).reply(202, {})
+
+ const requestBodyForProduct = createRequestBody(
+ products[0].properties,
+ products[0].value,
+ 'Ordered Product',
+ profile
+ )
+
+ nock(`${API_URL}`).post(`/events/`, requestBodyForProduct).reply(200, {})
+
+ await expect(testDestination.testAction('orderCompleted', { event, mapping, settings })).resolves.not.toThrowError()
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..77f676c180
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/__tests__/snapshot.test.ts
@@ -0,0 +1,42 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'orderCompleted'
+const destinationSlug = 'Klaviyo'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/orderCompleted/generated-types.ts b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/generated-types.ts
new file mode 100644
index 0000000000..145dd8de6f
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/generated-types.ts
@@ -0,0 +1,54 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Properties of the profile that triggered this event.
+ */
+ profile: {
+ email?: string
+ phone_number?: string
+ other_properties?: {
+ [k: string]: unknown
+ }
+ }
+ /**
+ * Properties of this event.
+ */
+ properties: {
+ [k: string]: unknown
+ }
+ /**
+ * When this event occurred. By default, the time the request was received will be used.
+ * The time is truncated to the second. The time must be after the year 2000 and can only
+ * be up to 1 year in the future.
+ *
+ */
+ time?: string | number
+ /**
+ * A numeric value to associate with this event. For example, the dollar amount of a purchase.
+ */
+ value?: number
+ /**
+ * A unique identifier for an event. If the unique_id is repeated for the same
+ * profile and metric, only the first processed event will be recorded. If this is not
+ * present, this will use the time to the second. Using the default, this limits only one
+ * event per profile per second.
+ *
+ */
+ unique_id?: string
+ /**
+ * List of products purchased in the order.
+ */
+ products?: {
+ /**
+ * A numeric value to associate with this event. For example, the dollar amount of a purchase.
+ */
+ value?: number
+ /**
+ * Properties of this event.
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+ }[]
+}
diff --git a/packages/destination-actions/src/destinations/klaviyo/orderCompleted/index.ts b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/index.ts
new file mode 100644
index 0000000000..3feb8ca1be
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/orderCompleted/index.ts
@@ -0,0 +1,155 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { PayloadValidationError, RequestClient } from '@segment/actions-core'
+import { API_URL } from '../config'
+import { EventData } from '../types'
+
+const createEventData = (payload: Payload) => ({
+ data: {
+ type: 'event',
+ attributes: {
+ properties: { ...payload.properties },
+ time: payload.time,
+ value: payload.value,
+ metric: {
+ data: {
+ type: 'metric',
+ attributes: {
+ name: 'Order Completed'
+ }
+ }
+ },
+ profile: {
+ data: {
+ type: 'profile',
+ attributes: {
+ ...payload.profile
+ }
+ }
+ }
+ }
+ }
+})
+
+const sendProductRequests = async (payload: Payload, eventData: EventData, request: RequestClient) => {
+ if (payload.products && Array.isArray(payload.products)) {
+ const productPromises = payload?.products?.map((product) => {
+ eventData.data.attributes.properties = product.properties
+ eventData.data.attributes.value = product.value
+ eventData.data.attributes.metric.data.attributes.name = 'Ordered Product'
+
+ return request(`${API_URL}/events/`, {
+ method: 'POST',
+ json: eventData
+ })
+ })
+
+ await Promise.all(productPromises)
+ }
+}
+
+const action: ActionDefinition = {
+ title: 'Order Completed',
+ description: 'Order Completed Event action tracks users Order Completed events and associate it with their profile.',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ profile: {
+ label: 'Profile',
+ description: `Properties of the profile that triggered this event.`,
+ type: 'object',
+ properties: {
+ email: {
+ label: 'Email',
+ type: 'string'
+ },
+ phone_number: {
+ label: 'Phone Number',
+ type: 'string'
+ },
+ other_properties: {
+ label: 'Other Properties',
+ type: 'object'
+ }
+ },
+ required: true
+ },
+ properties: {
+ description: `Properties of this event.`,
+ label: 'Properties',
+ type: 'object',
+ default: {
+ '@path': '$.properties'
+ },
+ required: true
+ },
+ time: {
+ label: 'Time',
+ description: `When this event occurred. By default, the time the request was received will be used.
+ The time is truncated to the second. The time must be after the year 2000 and can only
+ be up to 1 year in the future.
+ `,
+ type: 'datetime',
+ default: {
+ '@path': '$.timestamp'
+ }
+ },
+ value: {
+ label: 'Value',
+ description: 'A numeric value to associate with this event. For example, the dollar amount of a purchase.',
+ type: 'number'
+ },
+ unique_id: {
+ label: 'Unique ID',
+ description: `A unique identifier for an event. If the unique_id is repeated for the same
+ profile and metric, only the first processed event will be recorded. If this is not
+ present, this will use the time to the second. Using the default, this limits only one
+ event per profile per second.
+ `,
+ type: 'string',
+ default: {
+ '@path': '$.messageId'
+ }
+ },
+ products: {
+ label: 'Products',
+ description: 'List of products purchased in the order.',
+ multiple: true,
+ type: 'object',
+ properties: {
+ value: {
+ label: 'Value',
+ description: 'A numeric value to associate with this event. For example, the dollar amount of a purchase.',
+ type: 'number'
+ },
+ properties: {
+ description: `Properties of this event.`,
+ label: 'Properties',
+ type: 'object'
+ }
+ }
+ }
+ },
+
+ perform: async (request, { payload }) => {
+ const { email, phone_number } = payload.profile
+
+ if (!email && !phone_number) {
+ throw new PayloadValidationError('One of Phone Number or Email is required.')
+ }
+
+ const eventData = createEventData(payload)
+
+ const event = await request(`${API_URL}/events/`, {
+ method: 'POST',
+ json: eventData
+ })
+
+ if (event.status == 202 && Array.isArray(payload.products)) {
+ await sendProductRequests(payload, eventData, request)
+ }
+ return event
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..fed3b35186
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,36 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Klaviyo's trackEvent destination action: all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "metric": Object {
+ "data": Object {
+ "attributes": Object {
+ "name": "]DD4LgSzT#hw(U]@J$a",
+ },
+ "type": "metric",
+ },
+ },
+ "profile": Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "so@uzwumiz.wf",
+ "other_properties": Object {
+ "testType": "]DD4LgSzT#hw(U]@J$a",
+ },
+ "phone_number": "]DD4LgSzT#hw(U]@J$a",
+ },
+ "type": "profile",
+ },
+ },
+ "properties": Object {
+ "testType": "]DD4LgSzT#hw(U]@J$a",
+ },
+ "time": "2021-02-01T00:00:00.000Z",
+ "value": 71505359625256.95,
+ },
+ "type": "event",
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/index.test.ts
new file mode 100644
index 0000000000..d47efbdc9c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/index.test.ts
@@ -0,0 +1,121 @@
+import nock from 'nock'
+import { IntegrationError, createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Definition from '../../index'
+import { API_URL } from '../../config'
+
+const testDestination = createTestIntegration(Definition)
+
+const apiKey = 'fake-api-key'
+
+export const settings = {
+ api_key: apiKey
+}
+
+describe('Track Event', () => {
+ it('should throw error if no email or phone_number is provided', async () => {
+ const event = createTestEvent({
+ type: 'track'
+ })
+ const mapping = { profile: {}, metric_name: 'fake-name', properties: {} }
+
+ await expect(testDestination.testAction('trackEvent', { event, mapping, settings })).rejects.toThrowError(
+ IntegrationError
+ )
+ })
+
+ it('should successfully track event if proper parameters are provided', async () => {
+ const requestBody = {
+ data: {
+ type: 'event',
+ attributes: {
+ properties: { key: 'value' },
+ time: '2022-01-01T00:00:00.000Z',
+ value: 10,
+ metric: {
+ data: {
+ type: 'metric',
+ attributes: {
+ name: 'event_name'
+ }
+ }
+ },
+ profile: {
+ data: {
+ type: 'profile',
+ attributes: {
+ email: 'test@example.com',
+ phone_number: '1234567890'
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nock(`${API_URL}`).post('/events/', requestBody).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ timestamp: '2022-01-01T00:00:00.000Z'
+ })
+
+ const mapping = {
+ profile: { email: 'test@example.com', phone_number: '1234567890' },
+ metric_name: 'event_name',
+ properties: { key: 'value' },
+ value: 10
+ }
+
+ await expect(
+ testDestination.testAction('trackEvent', { event, mapping, settings, useDefaultMappings: true })
+ ).resolves.not.toThrowError()
+ })
+
+ it('should throw an error if the API request fails', async () => {
+ const requestBody = {
+ data: {
+ type: 'event',
+ attributes: {
+ properties: { key: 'value' },
+ time: '2022-01-01T00:00:00.000Z',
+ value: 10,
+ metric: {
+ data: {
+ type: 'metric',
+ attributes: {
+ name: 'event_name'
+ }
+ }
+ },
+ profile: {
+ data: {
+ type: 'profile',
+ attributes: {
+ email: 'test@example.com',
+ phone_number: '1234567890'
+ }
+ }
+ }
+ }
+ }
+ }
+
+ nock(`${API_URL}`).post('/events/', requestBody).reply(500, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ timestamp: '2022-01-01T00:00:00.000Z'
+ })
+
+ const mapping = {
+ profile: { email: 'test@example.com', phone_number: '1234567890' },
+ metric_name: 'event_name',
+ properties: { key: 'value' },
+ value: 10
+ }
+
+ await expect(
+ testDestination.testAction('trackEvent', { event, mapping, settings, useDefaultMappings: true })
+ ).rejects.toThrowError('Internal Server Error')
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..1ba428e5f2
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/trackEvent/__tests__/snapshot.test.ts
@@ -0,0 +1,42 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'trackEvent'
+const destinationSlug = 'Klaviyo'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/trackEvent/generated-types.ts b/packages/destination-actions/src/destinations/klaviyo/trackEvent/generated-types.ts
new file mode 100644
index 0000000000..1fab8aed49
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/trackEvent/generated-types.ts
@@ -0,0 +1,43 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * Properties of the profile that triggered this event.
+ */
+ profile: {
+ email?: string
+ phone_number?: string
+ other_properties?: {
+ [k: string]: unknown
+ }
+ }
+ /**
+ * Name of the event. Must be less than 128 characters.
+ */
+ metric_name: string
+ /**
+ * Properties of this event.
+ */
+ properties: {
+ [k: string]: unknown
+ }
+ /**
+ * When this event occurred. By default, the time the request was received will be used.
+ * The time is truncated to the second. The time must be after the year 2000 and can only
+ * be up to 1 year in the future.
+ *
+ */
+ time?: string | number
+ /**
+ * A numeric value to associate with this event. For example, the dollar amount of a purchase.
+ */
+ value?: number
+ /**
+ * A unique identifier for an event. If the unique_id is repeated for the same
+ * profile and metric, only the first processed event will be recorded. If this is not
+ * present, this will use the time to the second. Using the default, this limits only one
+ * event per profile per second.
+ *
+ */
+ unique_id?: string
+}
diff --git a/packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts b/packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts
new file mode 100644
index 0000000000..4824f240b6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/trackEvent/index.ts
@@ -0,0 +1,121 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+import { PayloadValidationError } from '@segment/actions-core'
+import { API_URL } from '../config'
+
+const action: ActionDefinition = {
+ title: 'Track Event',
+ description: 'Track user events and associate it with their profile.',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ profile: {
+ label: 'Profile',
+ description: `Properties of the profile that triggered this event.`,
+ type: 'object',
+ properties: {
+ email: {
+ label: 'Email',
+ type: 'string'
+ },
+ phone_number: {
+ label: 'Phone Number',
+ type: 'string'
+ },
+ other_properties: {
+ label: 'Other Properties',
+ type: 'object'
+ }
+ },
+ required: true
+ },
+ metric_name: {
+ label: 'Metric Name',
+ description: 'Name of the event. Must be less than 128 characters.',
+ type: 'string',
+ default: {
+ '@path': '$.event'
+ },
+ required: true
+ },
+ properties: {
+ description: `Properties of this event.`,
+ label: 'Properties',
+ type: 'object',
+ default: {
+ '@path': '$.properties'
+ },
+ required: true
+ },
+ time: {
+ label: 'Time',
+ description: `When this event occurred. By default, the time the request was received will be used.
+ The time is truncated to the second. The time must be after the year 2000 and can only
+ be up to 1 year in the future.
+ `,
+ type: 'datetime',
+ default: {
+ '@path': '$.timestamp'
+ }
+ },
+ value: {
+ label: 'Value',
+ description: 'A numeric value to associate with this event. For example, the dollar amount of a purchase.',
+ type: 'number'
+ },
+ unique_id: {
+ label: 'Unique ID',
+ description: `A unique identifier for an event. If the unique_id is repeated for the same
+ profile and metric, only the first processed event will be recorded. If this is not
+ present, this will use the time to the second. Using the default, this limits only one
+ event per profile per second.
+ `,
+ type: 'string',
+ default: {
+ '@path': '$.messageId'
+ }
+ }
+ },
+ perform: (request, { payload }) => {
+ const { email, phone_number } = payload.profile
+
+ if (!email && !phone_number) {
+ throw new PayloadValidationError('One of Phone Number or Email is required.')
+ }
+
+ const eventData = {
+ data: {
+ type: 'event',
+ attributes: {
+ properties: { ...payload.properties },
+ time: payload.time,
+ value: payload.value,
+ metric: {
+ data: {
+ type: 'metric',
+ attributes: {
+ name: payload.metric_name
+ }
+ }
+ },
+ profile: {
+ data: {
+ type: 'profile',
+ attributes: {
+ ...payload.profile
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return request(`${API_URL}/events/`, {
+ method: 'POST',
+ json: eventData
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/klaviyo/types.ts b/packages/destination-actions/src/destinations/klaviyo/types.ts
new file mode 100644
index 0000000000..aaad24910a
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/types.ts
@@ -0,0 +1,64 @@
+import { HTTPError } from '@segment/actions-core'
+
+export class KlaviyoAPIError extends HTTPError {
+ response: Response & {
+ data: {
+ errors: Array<{
+ id: string
+ status: number
+ code: string
+ title: string
+ detail: string
+ source: {
+ pointer: string
+ }
+ meta: {
+ duplicate_profile_id: string
+ }
+ }>
+ }
+ content: string
+ }
+}
+
+export interface ProfileData {
+ data: {
+ type: string
+ id?: string
+ attributes: {
+ email?: string
+ external_id?: string
+ phone_number?: string
+ [key: string]: string | Record | undefined
+ }
+ }
+}
+
+export interface EventData {
+ data: {
+ type: string
+ attributes: {
+ properties?: object
+ time?: string | number
+ value?: number
+ metric: {
+ data: {
+ type: string
+ attributes: {
+ name?: string
+ }
+ }
+ }
+ profile: {
+ data: {
+ type: string
+ attributes: {
+ email?: string
+ phone_number?: string
+ other_properties?: object
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..2d458c5e74
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,32 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Klaviyo's upsertProfile destination action: all fields 1`] = `
+Object {
+ "data": Object {
+ "attributes": Object {
+ "email": "el@ocbidoj.gw",
+ "external_id": "56GUhWJiuibf",
+ "first_name": "56GUhWJiuibf",
+ "image": "56GUhWJiuibf",
+ "last_name": "56GUhWJiuibf",
+ "location": Object {
+ "address1": "56GUhWJiuibf",
+ "address2": "56GUhWJiuibf",
+ "city": "56GUhWJiuibf",
+ "country": "56GUhWJiuibf",
+ "latitude": "56GUhWJiuibf",
+ "longitude": "56GUhWJiuibf",
+ "region": "56GUhWJiuibf",
+ "zip": "56GUhWJiuibf",
+ },
+ "organization": "56GUhWJiuibf",
+ "phone_number": "56GUhWJiuibf",
+ "properties": Object {
+ "testType": "56GUhWJiuibf",
+ },
+ "title": "56GUhWJiuibf",
+ },
+ "type": "profile",
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/index.test.ts b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/index.test.ts
new file mode 100644
index 0000000000..0a9c9636bb
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/index.test.ts
@@ -0,0 +1,141 @@
+import nock from 'nock'
+import { IntegrationError, createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Definition from '../../index'
+import { API_URL } from '../../config'
+
+const testDestination = createTestIntegration(Definition)
+
+const apiKey = 'fake-api-key'
+
+export const settings = {
+ api_key: apiKey
+}
+
+describe('Upsert Profile', () => {
+ it('should throw error if no email, phone_number, or external_id is provided', async () => {
+ const event = createTestEvent({
+ type: 'track',
+ properties: {}
+ })
+
+ await expect(testDestination.testAction('upsertProfile', { event, settings })).rejects.toThrowError(
+ IntegrationError
+ )
+ })
+
+ it('should create a new profile if successful', async () => {
+ const requestBody = {
+ data: {
+ type: 'profile',
+ attributes: {
+ email: 'test@example.com',
+ first_name: 'John',
+ last_name: 'Doe',
+ location: {},
+ properties: {}
+ }
+ }
+ }
+
+ nock(`${API_URL}`).post('/profiles/', requestBody).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ userId: '123',
+ traits: {
+ email: 'test@example.com',
+ firstName: 'John',
+ lastName: 'Doe'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('upsertProfile', { event, settings, useDefaultMappings: true })
+ ).resolves.not.toThrowError()
+ })
+
+ it('should update an existing profile if duplicate is found', async () => {
+ const requestBody = {
+ data: {
+ type: 'profile',
+ attributes: {
+ email: 'test@example.com',
+ first_name: 'John',
+ last_name: 'Doe',
+ location: {},
+ properties: {}
+ }
+ }
+ }
+
+ const errorResponse = JSON.stringify({
+ errors: [
+ {
+ meta: {
+ duplicate_profile_id: '123'
+ }
+ }
+ ]
+ })
+
+ nock(`${API_URL}`).post('/profiles/', requestBody).reply(409, errorResponse)
+
+ const updateRequestBody = {
+ data: {
+ type: 'profile',
+ id: '123',
+ attributes: {
+ email: 'test@example.com',
+ first_name: 'John',
+ last_name: 'Doe',
+ location: {},
+ properties: {}
+ }
+ }
+ }
+ nock(`${API_URL}`).patch('/profiles/123', updateRequestBody).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ traits: {
+ email: 'test@example.com',
+ firstName: 'John',
+ lastName: 'Doe'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('upsertProfile', { event, settings, useDefaultMappings: true })
+ ).resolves.not.toThrowError()
+ })
+
+ it('should throw an error if the API request fails', async () => {
+ const requestBody = {
+ data: {
+ type: 'profile',
+ attributes: {
+ email: 'test@example.com',
+ first_name: 'John',
+ last_name: 'Doe',
+ location: {},
+ properties: {}
+ }
+ }
+ }
+
+ nock(`${API_URL}`).post('/profiles/', requestBody).reply(500, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ traits: {
+ email: 'test@example.com',
+ firstName: 'John',
+ lastName: 'Doe'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('upsertProfile', { event, settings, useDefaultMappings: true })
+ ).rejects.toThrowError('An error occurred while processing the request')
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..87817178b6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/__tests__/snapshot.test.ts
@@ -0,0 +1,42 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'upsertProfile'
+const destinationSlug = 'Klaviyo'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/generated-types.ts b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/generated-types.ts
index dc26ac3f3e..1de9efa3ed 100644
--- a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/generated-types.ts
+++ b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/generated-types.ts
@@ -2,7 +2,54 @@
export interface Payload {
/**
- * Placeholder
+ * Individual's email address. One of External ID, Phone Number and Email required.
*/
- placeholder?: string
+ email?: string
+ /**
+ * Individual's phone number in E.164 format. If SMS is not enabled and if you use Phone Number as identifier, then you have to provide one of Email or External ID.
+ */
+ phone_number?: string
+ /**
+ * A unique identifier used by customers to associate Klaviyo profiles with profiles in an external system. One of External ID, Phone Number and Email required.
+ */
+ external_id?: string
+ /**
+ * Individual's first name.
+ */
+ first_name?: string
+ /**
+ * Individual's last name.
+ */
+ last_name?: string
+ /**
+ * Name of the company or organization within the company for whom the individual works.
+ */
+ organization?: string
+ /**
+ * Individual's job title.
+ */
+ title?: string
+ /**
+ * URL pointing to the location of a profile image.
+ */
+ image?: string
+ /**
+ * Individual's address.
+ */
+ location?: {
+ address1?: string | null
+ address2?: string | null
+ city?: string | null
+ region?: string | null
+ zip?: string | null
+ latitude?: string | null
+ longitude?: string | null
+ country?: string | null
+ }
+ /**
+ * An object containing key/value pairs for any custom properties assigned to this profile.
+ */
+ properties?: {
+ [k: string]: unknown
+ }
}
diff --git a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/index.ts b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/index.ts
index bb1cb0717a..5bb6846c73 100644
--- a/packages/destination-actions/src/destinations/klaviyo/upsertProfile/index.ts
+++ b/packages/destination-actions/src/destinations/klaviyo/upsertProfile/index.ts
@@ -2,18 +2,171 @@ import type { ActionDefinition } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
+import { API_URL } from '../config'
+import { APIError, PayloadValidationError } from '@segment/actions-core'
+import { KlaviyoAPIError, ProfileData } from '../types'
+
const action: ActionDefinition = {
title: 'Upsert Profile',
description: 'Upsert user profile.',
+ defaultSubscription: 'type = "identify"',
fields: {
- placeholder: {
- label: 'Placeholder',
- description: 'Placeholder',
+ email: {
+ label: 'Email',
+ description: `Individual's email address. One of External ID, Phone Number and Email required.`,
+ type: 'string',
+ format: 'email',
+ default: { '@path': '$.traits.email' }
+ },
+ phone_number: {
+ label: 'Phone Number',
+ description: `Individual's phone number in E.164 format. If SMS is not enabled and if you use Phone Number as identifier, then you have to provide one of Email or External ID.`,
+ type: 'string',
+ default: { '@path': '$.context.traits.phone' }
+ },
+ external_id: {
+ label: 'External ID',
+ description: `A unique identifier used by customers to associate Klaviyo profiles with profiles in an external system. One of External ID, Phone Number and Email required.`,
type: 'string'
+ },
+ first_name: {
+ label: 'First Name',
+ description: `Individual's first name.`,
+ type: 'string',
+ default: { '@path': '$.traits.firstName' }
+ },
+ last_name: {
+ label: 'Last Name',
+ description: `Individual's last name.`,
+ type: 'string',
+ default: { '@path': '$.traits.lastName' }
+ },
+ organization: {
+ label: 'Organization',
+ description: `Name of the company or organization within the company for whom the individual works.`,
+ type: 'string',
+ default: { '@path': '$.traits.company.name' }
+ },
+ title: {
+ label: 'Title',
+ description: `Individual's job title.`,
+ type: 'string',
+ default: { '@path': '$.traits.title' }
+ },
+ image: {
+ label: 'Image',
+ description: `URL pointing to the location of a profile image.`,
+ type: 'string',
+ default: { '@path': '$.traits.avatar' }
+ },
+ location: {
+ label: 'Location',
+ description: `Individual's address.`,
+ type: 'object',
+ properties: {
+ address1: {
+ label: 'Address 1',
+ type: 'string',
+ allowNull: true
+ },
+ address2: {
+ label: 'Address 2',
+ type: 'string',
+ allowNull: true
+ },
+ city: {
+ label: 'City',
+ type: 'string',
+ allowNull: true
+ },
+ region: {
+ label: 'Region',
+ type: 'string',
+ allowNull: true
+ },
+ zip: {
+ label: 'ZIP',
+ type: 'string',
+ allowNull: true
+ },
+ latitude: {
+ label: 'Latitude',
+ type: 'string',
+ allowNull: true
+ },
+ longitude: {
+ label: 'Longitide',
+ type: 'string',
+ allowNull: true
+ },
+ country: {
+ label: 'Country',
+ type: 'string',
+ allowNull: true
+ }
+ },
+ default: {
+ city: { '@path': '$.traits.address.city' },
+ region: { '@path': '$.traits.address.state' },
+ zip: { '@path': '$.traits.address.postal_code' },
+ address1: { '@path': '$.traits.address.street' },
+ country: { '@path': '$.traits.address.country' }
+ }
+ },
+ properties: {
+ description: 'An object containing key/value pairs for any custom properties assigned to this profile.',
+ label: 'Properties',
+ type: 'object',
+ default: {
+ '@path': '$.properties'
+ }
}
},
- perform: () => {
- return undefined
+ perform: async (request, { payload }) => {
+ const { email, external_id, phone_number, ...otherAttributes } = payload
+
+ if (!email && !phone_number && !external_id) {
+ throw new PayloadValidationError('One of External ID, Phone Number and Email is required.')
+ }
+
+ const profileData: ProfileData = {
+ data: {
+ type: 'profile',
+ attributes: {
+ email,
+ external_id,
+ phone_number,
+ ...otherAttributes
+ }
+ }
+ }
+
+ try {
+ const profile = await request(`${API_URL}/profiles/`, {
+ method: 'POST',
+ json: profileData
+ })
+ return profile
+ } catch (error) {
+ const { response } = error as KlaviyoAPIError
+
+ if (response?.status === 409) {
+ const content = JSON.parse(response?.content)
+ const id = content?.errors[0]?.meta?.duplicate_profile_id
+
+ if (id) {
+ profileData.data.id = id
+
+ const profile = await request(`${API_URL}/profiles/${id}`, {
+ method: 'PATCH',
+ json: profileData
+ })
+ return profile
+ }
+ }
+
+ throw new APIError('An error occurred while processing the request', 400)
+ }
}
}
From 21df01727a6920224bcf1289ae9c63f069ce7d82 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 16 Oct 2023 14:19:49 +0200
Subject: [PATCH 030/389] updating initialize (#1648)
---
.../destinations/cdpresolution/src/index.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/browser-destinations/destinations/cdpresolution/src/index.ts b/packages/browser-destinations/destinations/cdpresolution/src/index.ts
index 6ae95119c4..c5cf2356f4 100644
--- a/packages/browser-destinations/destinations/cdpresolution/src/index.ts
+++ b/packages/browser-destinations/destinations/cdpresolution/src/index.ts
@@ -50,9 +50,9 @@ export const destination: BrowserDestinationDefinition
}
},
- initialize: async () => {
+ initialize: async (_, deps) => {
window.cdpResolution = {
- sync: (endpoint: string, clientIdentifier: string, anonymousId: string): void => {
+ sync: async (endpoint: string, clientIdentifier: string, anonymousId: string): Promise => {
let cdpcookieset = ''
const name = 'cdpresolutionset' + '='
const ca = document.cookie.split(';')
@@ -82,7 +82,7 @@ export const destination: BrowserDestinationDefinition
if (cdpcookieset == '') {
document.cookie = 'cdpresolutionset=true'
- void fetch(endpointUrl, { mode: 'no-cors' })
+ await deps.loadScript(endpointUrl)
return
}
}
From 96e67ffdde180aa66fad91b7bdaf99428b15c7e2 Mon Sep 17 00:00:00 2001
From: Jae Rhee <128410804+jae-rhee-tiktok@users.noreply.github.com>
Date: Mon, 16 Oct 2023 08:25:12 -0400
Subject: [PATCH 031/389] Tiktok pixel external (#1641)
* add event_id
* update package.json
* update test case with event_id
* update external id mapping
---------
Co-authored-by: Jaehyuk Rhee
Co-authored-by: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
---
.../destinations/tiktok-pixel/package.json | 2 +-
.../src/reportWebEvent/__tests__/index.test.ts | 12 +++++++++---
.../tiktok-pixel/src/reportWebEvent/index.ts | 3 ++-
.../destinations/tiktok-pixel/src/types.ts | 10 +++++++++-
4 files changed, 21 insertions(+), 6 deletions(-)
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/package.json b/packages/browser-destinations/destinations/tiktok-pixel/package.json
index e4ccfa3a94..4fd4c064d8 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/package.json
+++ b/packages/browser-destinations/destinations/tiktok-pixel/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-tiktok-pixel",
- "version": "1.11.0",
+ "version": "1.12.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/__tests__/index.test.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/__tests__/index.test.ts
index 43c0567a68..a7acd528c6 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/__tests__/index.test.ts
+++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/__tests__/index.test.ts
@@ -89,6 +89,7 @@ describe('TikTokPixel.reportWebEvent', () => {
messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
type: 'track',
anonymousId: 'anonymousId',
+ userId: 'userId',
event: 'Order Completed',
properties: {
products: [
@@ -125,7 +126,8 @@ describe('TikTokPixel.reportWebEvent', () => {
expect(mockTtp.identify).toHaveBeenCalledWith({
email: 'aaa@aaa.com',
- phone_number: '+12345678900'
+ phone_number: '+12345678900',
+ external_id: 'userId'
})
expect(mockTtp.track).toHaveBeenCalledWith(
'PlaceAnOrder',
@@ -209,6 +211,7 @@ describe('TikTokPixel.reportWebEvent', () => {
messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
type: 'track',
anonymousId: 'anonymousId',
+ userId: 'userId',
event: 'Product Added',
properties: {
product_id: '123',
@@ -235,7 +238,8 @@ describe('TikTokPixel.reportWebEvent', () => {
expect(mockTtp.identify).toHaveBeenCalledWith({
email: 'aaa@aaa.com',
- phone_number: '+12345678900'
+ phone_number: '+12345678900',
+ external_id: 'userId'
})
expect(mockTtp.track).toHaveBeenCalledWith(
'AddToCart',
@@ -316,6 +320,7 @@ describe('TikTokPixel.reportWebEvent', () => {
messageId: 'ajs-71f386523ee5dfa90c7d0fda28b6b5c6',
type: 'page',
anonymousId: 'anonymousId',
+ userId: 'userId',
properties: {
product_id: '123',
category: 'product',
@@ -341,7 +346,8 @@ describe('TikTokPixel.reportWebEvent', () => {
expect(mockTtp.identify).toHaveBeenCalledWith({
email: 'aaa@aaa.com',
- phone_number: '+12345678900'
+ phone_number: '+12345678900',
+ external_id: 'userId'
})
expect(mockTtp.track).toHaveBeenCalledWith(
'ViewContent',
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts
index 3c90c34f41..a6a5b404f5 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts
+++ b/packages/browser-destinations/destinations/tiktok-pixel/src/reportWebEvent/index.ts
@@ -136,7 +136,8 @@ const action: BrowserActionDefinition = {
if (payload.email || payload.phone_number) {
ttq.identify({
email: payload.email,
- phone_number: formatPhone(payload.phone_number)
+ phone_number: formatPhone(payload.phone_number),
+ external_id: payload.external_id
})
}
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts b/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts
index 4c7ff44891..c1ceacf601 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts
+++ b/packages/browser-destinations/destinations/tiktok-pixel/src/types.ts
@@ -1,6 +1,14 @@
export interface TikTokPixel {
page: () => void
- identify: ({ email, phone_number }: { email: string | undefined; phone_number: string | undefined }) => void
+ identify: ({
+ email,
+ phone_number,
+ external_id
+ }: {
+ email: string | undefined
+ phone_number: string | undefined
+ external_id: string | undefined
+ }) => void
track: (
event: string,
{
From c3b913f69a0a972bef4f45c6ee5d76b960155899 Mon Sep 17 00:00:00 2001
From: Sam <22425976+imsamdez@users.noreply.github.com>
Date: Mon, 16 Oct 2023 14:58:10 +0200
Subject: [PATCH 032/389] Jimo Browser Destination (#1626)
* Add Jimo Browser Destination
* Implement action sendUserData
* fix(Jimo/Global): init issues & add email to sendUserData payload
* fix(Tests): remove tests for now, not passing because of lottie
* fix(Jimo): PR changes
* fix(Jimo): PR changes
* fix(Jimo): PR changes
* fixing up things
* fix(Jimo): PR changes
* fix(Jimo): add tests
---------
Co-authored-by: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
---
.../destinations/jimo/README.md | 31 +++++++++
.../destinations/jimo/package.json | 24 +++++++
.../destinations/jimo/src/generated-types.ts | 12 ++++
.../destinations/jimo/src/index.ts | 63 +++++++++++++++++++
.../destinations/jimo/src/init-script.ts | 12 ++++
.../src/sendUserData/__tests__/index.test.ts | 50 +++++++++++++++
.../jimo/src/sendUserData/generated-types.ts | 12 ++++
.../jimo/src/sendUserData/index.ts | 45 +++++++++++++
.../destinations/jimo/src/types.ts | 3 +
.../destinations/jimo/tsconfig.json | 9 +++
.../destinations/ripe/src/index.ts | 4 +-
11 files changed, 263 insertions(+), 2 deletions(-)
create mode 100644 packages/browser-destinations/destinations/jimo/README.md
create mode 100644 packages/browser-destinations/destinations/jimo/package.json
create mode 100644 packages/browser-destinations/destinations/jimo/src/generated-types.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/index.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/init-script.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/sendUserData/__tests__/index.test.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/sendUserData/index.ts
create mode 100644 packages/browser-destinations/destinations/jimo/src/types.ts
create mode 100644 packages/browser-destinations/destinations/jimo/tsconfig.json
diff --git a/packages/browser-destinations/destinations/jimo/README.md b/packages/browser-destinations/destinations/jimo/README.md
new file mode 100644
index 0000000000..356ae0725b
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/README.md
@@ -0,0 +1,31 @@
+# @segment/analytics-browser-actions-jimo
+
+The Jimo browser action destination for use with @segment/analytics-next.
+
+## License
+
+MIT License
+
+Copyright (c) 2023 Segment
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+## Contributing
+
+All third party contributors acknowledge that any contributions they provide will be made under the same open source license that the open source project is provided under.
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
new file mode 100644
index 0000000000..84fbc19074
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -0,0 +1,24 @@
+{
+ "name": "@segment/analytics-browser-actions-jimo",
+ "version": "1.0.0",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/segmentio/action-destinations",
+ "directory": "packages/browser-destinations/destinations/jimo"
+ },
+ "main": "./dist/cjs",
+ "module": "./dist/esm",
+ "scripts": {
+ "build": "yarn build:esm && yarn build:cjs",
+ "build:cjs": "tsc --module commonjs --outDir ./dist/cjs",
+ "build:esm": "tsc --outDir ./dist/esm"
+ },
+ "typings": "./dist/esm",
+ "dependencies": {
+ "@segment/browser-destination-runtime": "^1.14.0"
+ },
+ "peerDependencies": {
+ "@segment/analytics-next": "*"
+ }
+}
diff --git a/packages/browser-destinations/destinations/jimo/src/generated-types.ts b/packages/browser-destinations/destinations/jimo/src/generated-types.ts
new file mode 100644
index 0000000000..77cee2434b
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/generated-types.ts
@@ -0,0 +1,12 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Id of the Jimo project. You can find it here: https://i.usejimo.com/settings/install/portal
+ */
+ projectId: string
+ /**
+ * Make sure Jimo is not initialized automatically after being added to your website. For more information, check out: https://help.usejimo.com/knowledge-base/for-developers/sdk-guides/manual-initialization
+ */
+ manualInit?: boolean
+}
diff --git a/packages/browser-destinations/destinations/jimo/src/index.ts b/packages/browser-destinations/destinations/jimo/src/index.ts
new file mode 100644
index 0000000000..6d48cd9be0
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/index.ts
@@ -0,0 +1,63 @@
+import { defaultValues } from '@segment/actions-core'
+import { browserDestination } from '@segment/browser-destination-runtime/shim'
+import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
+import type { Settings } from './generated-types'
+import { initScript } from './init-script'
+import sendUserData from './sendUserData'
+import { JimoSDK } from './types'
+
+declare global {
+ interface Window {
+ jimo: JimoSDK | never[]
+ JIMO_PROJECT_ID: string
+ JIMO_MANUAL_INIT: boolean
+ }
+}
+
+const ENDPOINT_UNDERCITY = 'https://undercity.usejimo.com/jimo-invader.js'
+
+export const destination: BrowserDestinationDefinition = {
+ name: 'Jimo',
+ slug: 'actions-jimo',
+ mode: 'device',
+ description: 'Load Jimo SDK and send user profile data to Jimo',
+
+ settings: {
+ projectId: {
+ description:
+ 'Id of the Jimo project. You can find the Project Id here: https://i.usejimo.com/settings/install/portal',
+ label: 'Id',
+ type: 'string',
+ required: true
+ },
+ manualInit: {
+ label: 'Initialize Jimo manually',
+ description:
+ 'Toggling to true will prevent Jimo from initializing automatically. For more information, check out: https://help.usejimo.com/knowledge-base/for-developers/sdk-guides/manual-initialization',
+ type: 'boolean',
+ required: false,
+ default: false
+ }
+ },
+ presets: [
+ {
+ name: 'Send User Data',
+ subscribe: 'type = "identify"',
+ partnerAction: 'sendUserData',
+ mapping: defaultValues(sendUserData.fields),
+ type: 'automatic'
+ }
+ ],
+ initialize: async ({ settings }, deps) => {
+ initScript(settings)
+
+ await deps.loadScript(`${ENDPOINT_UNDERCITY}`)
+
+ return window.jimo as JimoSDK
+ },
+ actions: {
+ sendUserData
+ }
+}
+
+export default browserDestination(destination)
diff --git a/packages/browser-destinations/destinations/jimo/src/init-script.ts b/packages/browser-destinations/destinations/jimo/src/init-script.ts
new file mode 100644
index 0000000000..ca345d03a0
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/init-script.ts
@@ -0,0 +1,12 @@
+import { Settings } from './generated-types'
+/* eslint-disable */
+// @ts-nocheck
+export function initScript(settings: Settings) {
+ if (window.jimo) {
+ return
+ }
+
+ window.jimo = []
+ window['JIMO_PROJECT_ID'] = settings.projectId
+ window['JIMO_MANUAL_INIT'] = settings.manualInit === true
+}
diff --git a/packages/browser-destinations/destinations/jimo/src/sendUserData/__tests__/index.test.ts b/packages/browser-destinations/destinations/jimo/src/sendUserData/__tests__/index.test.ts
new file mode 100644
index 0000000000..6ca0bc3736
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/sendUserData/__tests__/index.test.ts
@@ -0,0 +1,50 @@
+import { Analytics, Context } from '@segment/analytics-next'
+
+import sendUserData from '..'
+import { JimoSDK } from '../../types'
+import { Payload } from '../generated-types'
+
+describe('Jimo - Send User Data', () => {
+ test('user id', async () => {
+ const client = {
+ push: jest.fn()
+ } as any as JimoSDK
+
+ const context = new Context({
+ type: 'identify'
+ })
+
+ await sendUserData.perform(client as any as JimoSDK, {
+ settings: { projectId: 'unk' },
+ analytics: jest.fn() as any as Analytics,
+ context: context,
+ payload: {
+ userId: 'u1'
+ } as Payload
+ })
+
+ expect(client.push).toHaveBeenCalled()
+ expect(client.push).toHaveBeenCalledWith(['set', 'user:id', ['u1']])
+ })
+ test('user email', async () => {
+ const client = {
+ push: jest.fn()
+ } as any as JimoSDK
+
+ const context = new Context({
+ type: 'identify'
+ })
+
+ await sendUserData.perform(client as any as JimoSDK, {
+ settings: { projectId: 'unk' },
+ analytics: jest.fn() as any as Analytics,
+ context: context,
+ payload: {
+ email: 'foo@bar.com'
+ } as Payload
+ })
+
+ expect(client.push).toHaveBeenCalled()
+ expect(client.push).toHaveBeenCalledWith(['set', 'user:email', ['foo@bar.com']])
+ })
+})
diff --git a/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts b/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
new file mode 100644
index 0000000000..644f265bc6
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
@@ -0,0 +1,12 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The users's id provided by segment
+ */
+ userId?: string | null
+ /**
+ * The email of the user
+ */
+ email?: string | null
+}
diff --git a/packages/browser-destinations/destinations/jimo/src/sendUserData/index.ts b/packages/browser-destinations/destinations/jimo/src/sendUserData/index.ts
new file mode 100644
index 0000000000..54baaca688
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/sendUserData/index.ts
@@ -0,0 +1,45 @@
+import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types'
+import { JimoSDK } from 'src/types'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: BrowserActionDefinition = {
+ title: 'Send User Data',
+ description: 'Send user ID and email to Jimo',
+ platform: 'web',
+ fields: {
+ userId: {
+ label: 'User ID',
+ description: 'The unique user identifier',
+ type: 'string',
+ allowNull: true,
+ required: false,
+ default: {
+ '@path': '$.userId'
+ }
+ },
+ email: {
+ label: 'User email',
+ description: 'The email of the user',
+ type: 'string',
+ allowNull: true,
+ required: false,
+ default: {
+ '@path': '$.traits.email'
+ }
+ }
+ },
+ defaultSubscription: 'type = "identify"',
+ perform: (jimo, { payload }) => {
+ if (payload.userId != null) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ jimo.push(['set', 'user:id', [payload.userId]])
+ }
+ if (payload.email != null) {
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-call
+ jimo.push(['set', 'user:email', [payload.email]])
+ }
+ }
+}
+
+export default action
diff --git a/packages/browser-destinations/destinations/jimo/src/types.ts b/packages/browser-destinations/destinations/jimo/src/types.ts
new file mode 100644
index 0000000000..85ae190500
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/src/types.ts
@@ -0,0 +1,3 @@
+export interface JimoSDK {
+ push: (params: Array) => Promise
+}
diff --git a/packages/browser-destinations/destinations/jimo/tsconfig.json b/packages/browser-destinations/destinations/jimo/tsconfig.json
new file mode 100644
index 0000000000..c2a7897afd
--- /dev/null
+++ b/packages/browser-destinations/destinations/jimo/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "extends": "../../tsconfig.build.json",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "baseUrl": "."
+ },
+ "include": ["src"],
+ "exclude": ["dist", "**/__tests__"]
+}
diff --git a/packages/browser-destinations/destinations/ripe/src/index.ts b/packages/browser-destinations/destinations/ripe/src/index.ts
index 204cb69fb2..7f1c0f534f 100644
--- a/packages/browser-destinations/destinations/ripe/src/index.ts
+++ b/packages/browser-destinations/destinations/ripe/src/index.ts
@@ -1,6 +1,6 @@
-import type { Settings } from './generated-types'
-import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
import { browserDestination } from '@segment/browser-destination-runtime/shim'
+import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types'
+import type { Settings } from './generated-types'
import { RipeSDK } from './types'
import group from './group'
From 69b47336225d3b5b31115f78f179dcbdc7a0e88d Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 16 Oct 2023 15:00:05 +0200
Subject: [PATCH 033/389] Manually correcting package.json
Manually correcting package.json for new Web Destination
---
packages/browser-destinations/destinations/jimo/package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 84fbc19074..39f8011a50 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -17,8 +17,9 @@
"typings": "./dist/esm",
"dependencies": {
"@segment/browser-destination-runtime": "^1.14.0"
+
},
"peerDependencies": {
- "@segment/analytics-next": "*"
+ "@segment/analytics-next": ">=1.55.0"
}
}
From cf9e6332a2591a488ea9ede8661fc7d6cffe4584 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 16 Oct 2023 16:10:26 +0200
Subject: [PATCH 034/389] Updating Destination name to avoid clash
Updating Destination name to avoid clash with existing Destination name
---
packages/browser-destinations/destinations/jimo/src/index.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/browser-destinations/destinations/jimo/src/index.ts b/packages/browser-destinations/destinations/jimo/src/index.ts
index 6d48cd9be0..0ff78ce2ae 100644
--- a/packages/browser-destinations/destinations/jimo/src/index.ts
+++ b/packages/browser-destinations/destinations/jimo/src/index.ts
@@ -17,7 +17,7 @@ declare global {
const ENDPOINT_UNDERCITY = 'https://undercity.usejimo.com/jimo-invader.js'
export const destination: BrowserDestinationDefinition = {
- name: 'Jimo',
+ name: 'Jimo (Actions)',
slug: 'actions-jimo',
mode: 'device',
description: 'Load Jimo SDK and send user profile data to Jimo',
From 017e932680e85576d6a8bb86ba32ee442ad22f04 Mon Sep 17 00:00:00 2001
From: Varadarajan V <109586712+varadarajan-tw@users.noreply.github.com>
Date: Mon, 16 Oct 2023 20:15:55 +0530
Subject: [PATCH 035/389] Run SetConfiguration action before all actions
(#1652)
---
.../google-analytics-4-web/src/setConfigurationFields/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/browser-destinations/destinations/google-analytics-4-web/src/setConfigurationFields/index.ts b/packages/browser-destinations/destinations/google-analytics-4-web/src/setConfigurationFields/index.ts
index 92c2c93766..f220beac22 100644
--- a/packages/browser-destinations/destinations/google-analytics-4-web/src/setConfigurationFields/index.ts
+++ b/packages/browser-destinations/destinations/google-analytics-4-web/src/setConfigurationFields/index.ts
@@ -12,6 +12,7 @@ const action: BrowserActionDefinition = {
description: 'Set custom values for the GA4 configuration fields.',
platform: 'web',
defaultSubscription: 'type = "identify" or type = "page"',
+ lifecycleHook: 'before',
fields: {
user_id: user_id,
user_properties: user_properties,
From 32f98fd03f5561f33afc1303d9f4bc80571975b6 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 16 Oct 2023 16:54:39 +0200
Subject: [PATCH 036/389] Update package.json
Update jimo package.json to match other package.json files
---
.../browser-destinations/destinations/jimo/package.json | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 39f8011a50..9081190cf9 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -2,10 +2,9 @@
"name": "@segment/analytics-browser-actions-jimo",
"version": "1.0.0",
"license": "MIT",
- "repository": {
- "type": "git",
- "url": "https://github.com/segmentio/action-destinations",
- "directory": "packages/browser-destinations/destinations/jimo"
+ "publishConfig": {
+ "access": "public",
+ "registry": "https://registry.npmjs.org"
},
"main": "./dist/cjs",
"module": "./dist/esm",
From b9bc617bb9ae724ea76e452b9f580040926cb034 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Mon, 16 Oct 2023 16:56:25 +0200
Subject: [PATCH 037/389] registering jimo web Destination
registering jimo web Destination
---
packages/destinations-manifest/src/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destinations-manifest/src/index.ts b/packages/destinations-manifest/src/index.ts
index 648166a148..5632b40bfe 100644
--- a/packages/destinations-manifest/src/index.ts
+++ b/packages/destinations-manifest/src/index.ts
@@ -60,3 +60,4 @@ register('6501a5225aa338d11164cc0f', '@segment/analytics-browser-actions-rupt')
register('650c69e7f47d84b86c120b4c', '@segment/analytics-browser-actions-cdpresolution')
register('649adeaa719bd3f55fe81bef', '@segment/analytics-browser-actions-devrev')
register('651aac880f2c3b5a8736e0cc', '@segment/analytics-browser-hubble-web')
+register('652d4cf5e00c0147e6eaf5e7', '@segment/analytics-browser-actions-jimo')
From a3ad7ebb918a564231f59a22f0770635e6b57731 Mon Sep 17 00:00:00 2001
From: hvardhan-unth <117922634+hvardhan-unth@users.noreply.github.com>
Date: Tue, 17 Oct 2023 13:18:31 +0530
Subject: [PATCH 038/389] [Stratconn 3084] Scaffold linked in conversions api
(#1658)
* Scaffold new Linkedin Conversion destination
* Updated unit tests
* Update packages/destination-actions/src/destinations/linkedin-conversions/index.ts
* Update packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/index.ts
---------
Co-authored-by: Harsh Vardhan
Co-authored-by: Nick Aguilar
---
.../__snapshots__/snapshot.test.ts.snap | 5 ++
.../__tests__/index.test.ts | 50 +++++++++++
.../__tests__/snapshot.test.ts | 77 +++++++++++++++++
.../linkedin-conversions/api/index.ts | 17 ++++
.../linkedin-conversions/constants.ts | 3 +
.../linkedin-conversions/generated-types.ts | 3 +
.../linkedin-conversions/index.ts | 85 +++++++++++++++++++
.../__snapshots__/snapshot.test.ts.snap | 5 ++
.../streamConversion/__tests__/index.test.ts | 27 ++++++
.../__tests__/snapshot.test.ts | 75 ++++++++++++++++
.../streamConversion/generated-types.ts | 3 +
.../streamConversion/index.ts | 17 ++++
.../linkedin-conversions/types.ts | 29 +++++++
13 files changed, 396 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/api/index.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/constants.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/index.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/index.ts
create mode 100644 packages/destination-actions/src/destinations/linkedin-conversions/types.ts
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..c480333df6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,5 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-linkedin-conversions destination: streamConversion action - all fields 1`] = `Object {}`;
+
+exports[`Testing snapshot for actions-linkedin-conversions destination: streamConversion action - required fields 1`] = `Object {}`;
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/index.test.ts b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/index.test.ts
new file mode 100644
index 0000000000..a096339b17
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/index.test.ts
@@ -0,0 +1,50 @@
+import nock from 'nock'
+import { createTestIntegration } from '@segment/actions-core'
+import Definition from '../index'
+import { BASE_URL } from '../constants'
+
+const testDestination = createTestIntegration(Definition)
+
+const settings = {
+ oauth: {
+ access_token: '123',
+ refresh_token: '123'
+ }
+}
+
+describe('Linkedin Conversions Api', () => {
+ describe('testAuthentication', () => {
+ it('should validate authentication inputs', async () => {
+ const mockProfileResponse = {
+ id: '456'
+ }
+
+ // Validate that the user exists in LinkedIn.
+ nock(`${BASE_URL}/me`).get(/.*/).reply(200, mockProfileResponse)
+
+ await expect(testDestination.testAuthentication(settings)).resolves.not.toThrowError()
+ })
+
+ it('should throw an error if the user has not completed the oauth flow', async () => {
+ await expect(testDestination.testAuthentication({})).rejects.toThrowError(
+ 'Credentials are invalid: Please authenticate via Oauth before enabling the destination.'
+ )
+ })
+
+ it('should throw an error if the oauth token is invalid', async () => {
+ nock(`${BASE_URL}/me`).get(/.*/).reply(401)
+
+ await expect(testDestination.testAuthentication(settings)).rejects.toThrowError(
+ 'Credentials are invalid: Invalid LinkedIn Oauth access token. Please reauthenticate to retrieve a valid access token before enabling the destination.'
+ )
+ })
+
+ it('should throw the raw error from LinkedIn if the error is not handled elsewhere in the `testAuthentication` method', async () => {
+ nock(`${BASE_URL}/me`).get(/.*/).reply(500)
+
+ await expect(testDestination.testAuthentication(settings)).rejects.toThrowError(
+ 'Credentials are invalid: 500 Internal Server Error'
+ )
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..f49cb2be92
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/__tests__/snapshot.test.ts
@@ -0,0 +1,77 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-linkedin-conversions'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/api/index.ts b/packages/destination-actions/src/destinations/linkedin-conversions/api/index.ts
new file mode 100644
index 0000000000..8b39484285
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/api/index.ts
@@ -0,0 +1,17 @@
+import type { RequestClient, ModifiedResponse } from '@segment/actions-core'
+import { BASE_URL } from '../constants'
+import type { ProfileAPIResponse } from '../types'
+
+export class LinkedInConversions {
+ request: RequestClient
+
+ constructor(request: RequestClient) {
+ this.request = request
+ }
+
+ async getProfile(): Promise> {
+ return this.request(`${BASE_URL}/me`, {
+ method: 'GET'
+ })
+ }
+}
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/constants.ts b/packages/destination-actions/src/destinations/linkedin-conversions/constants.ts
new file mode 100644
index 0000000000..e2b8090047
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/constants.ts
@@ -0,0 +1,3 @@
+export const LINKEDIN_API_VERSION = '202309'
+export const BASE_URL = 'https://api.linkedin.com/rest'
+export const LINKEDIN_SOURCE_PLATFORM = 'SEGMENT'
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/generated-types.ts b/packages/destination-actions/src/destinations/linkedin-conversions/generated-types.ts
new file mode 100644
index 0000000000..4ab2786ec6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {}
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/index.ts b/packages/destination-actions/src/destinations/linkedin-conversions/index.ts
new file mode 100644
index 0000000000..5cf2aad008
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/index.ts
@@ -0,0 +1,85 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import { InvalidAuthenticationError, IntegrationError, ErrorCodes } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+import { LinkedInConversions } from './api'
+import type { LinkedInTestAuthenticationError, RefreshTokenResponse, LinkedInRefreshTokenError } from './types'
+import { LINKEDIN_API_VERSION } from './constants'
+
+import streamConversion from './streamConversion'
+
+const destination: DestinationDefinition = {
+ name: 'LinkedIn Conversions API',
+ slug: 'actions-linkedin-conversions',
+ mode: 'cloud',
+
+ authentication: {
+ scheme: 'oauth2',
+ fields: {},
+ testAuthentication: async (request, { auth }) => {
+ if (!auth?.accessToken) {
+ throw new InvalidAuthenticationError('Please authenticate via Oauth before enabling the destination.')
+ }
+
+ const linkedinApiClient: LinkedInConversions = new LinkedInConversions(request)
+
+ try {
+ // GET the current user's id from LinkedIn's profile API: https://learn.microsoft.com/en-us/linkedin/shared/integrations/people/profile-api?context=linkedin%2Fcompliance%2Fcontext&view=li-lms-unversioned&preserve-view=true#request
+ // We request `r_basicprofile` scope when a user oauths into LinkedIn, so we retrieve the "Basic Profile Fields": https://learn.microsoft.com/en-us/linkedin/shared/references/v2/profile/basic-profile
+ return await linkedinApiClient.getProfile()
+ } catch (e: any) {
+ const error = e as LinkedInTestAuthenticationError
+ if (error.message === 'Unauthorized') {
+ throw new Error(
+ 'Invalid LinkedIn Oauth access token. Please reauthenticate to retrieve a valid access token before enabling the destination.'
+ )
+ }
+ throw e
+ }
+ },
+ refreshAccessToken: async (request, { auth }) => {
+ let res
+
+ try {
+ res = await request('https://www.linkedin.com/oauth/v2/accessToken', {
+ method: 'POST',
+ body: new URLSearchParams({
+ refresh_token: auth.refreshToken,
+ client_id: auth.clientId,
+ client_secret: auth.clientSecret,
+ grant_type: 'refresh_token'
+ })
+ })
+ } catch (e: any) {
+ const error = e as LinkedInRefreshTokenError
+ if (error.response?.data?.error === 'invalid_grant') {
+ throw new IntegrationError(
+ `Invalid Authentication: Your refresh token is invalid or expired. Please re-authenticate to fetch a new refresh token.`,
+ ErrorCodes.REFRESH_TOKEN_EXPIRED,
+ 401
+ )
+ }
+
+ throw new IntegrationError(
+ `Failed to fetch a new access token. Reason: ${error.response?.data?.error}`,
+ ErrorCodes.OAUTH_REFRESH_FAILED,
+ 401
+ )
+ }
+
+ return { accessToken: res?.data?.access_token }
+ }
+ },
+ extendRequest({ auth }) {
+ return {
+ headers: {
+ authorization: `Bearer ${auth?.accessToken}`,
+ 'LinkedIn-Version': LINKEDIN_API_VERSION
+ }
+ }
+ },
+ actions: {
+ streamConversion
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..daa078d95f
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,5 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for LinkedinConversions's streamConversion destination action: all fields 1`] = `Object {}`;
+
+exports[`Testing snapshot for LinkedinConversions's streamConversion destination action: required fields 1`] = `Object {}`;
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/index.test.ts b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/index.test.ts
new file mode 100644
index 0000000000..1534e8be68
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/index.test.ts
@@ -0,0 +1,27 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+const event = createTestEvent({
+ event: 'Example Event',
+ type: 'track',
+ context: {
+ traits: {
+ email: 'testing@testing.com'
+ }
+ }
+})
+
+describe('LinkedinConversions.streamConversion', () => {
+ //This is an example unit test case, needs to update after developing streamConversion action
+ it('A sample unit case', async () => {
+ nock('https://example.com').post('/').reply(200, {})
+ await expect(
+ testDestination.testAction('sampleEvent', {
+ event
+ })
+ ).resolves.not.toThrowError()
+ })
+})
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..b74061f058
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/__tests__/snapshot.test.ts
@@ -0,0 +1,75 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'streamConversion'
+const destinationSlug = 'LinkedinConversions'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/generated-types.ts b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/generated-types.ts
new file mode 100644
index 0000000000..944d22b085
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {}
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/index.ts b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/index.ts
new file mode 100644
index 0000000000..5bfa08dfae
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/streamConversion/index.ts
@@ -0,0 +1,17 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Stream Conversion Event',
+ description: 'Directly streams conversion events to a specific conversion rule.',
+ fields: {},
+ perform: (request, data) => {
+ return request('https://example.com', {
+ method: 'post',
+ json: data.payload
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/linkedin-conversions/types.ts b/packages/destination-actions/src/destinations/linkedin-conversions/types.ts
new file mode 100644
index 0000000000..89977695a6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/linkedin-conversions/types.ts
@@ -0,0 +1,29 @@
+import { HTTPError } from '@segment/actions-core'
+
+export interface RefreshTokenResponse {
+ access_token: string
+ scope: string
+ expires_in: number
+ token_type: string
+}
+
+export interface ProfileAPIResponse {
+ id: string
+}
+
+export class LinkedInTestAuthenticationError extends HTTPError {
+ response: Response & {
+ data: {
+ message: string
+ }
+ }
+}
+
+export class LinkedInRefreshTokenError extends HTTPError {
+ response: Response & {
+ data: {
+ error: string
+ error_description: string
+ }
+ }
+}
From 5bdf323b4804c0c401c2ea8d5d20e4b8f1fd0137 Mon Sep 17 00:00:00 2001
From: Swaty Gupta <58588123+Swaty-G@users.noreply.github.com>
Date: Tue, 17 Oct 2023 03:15:01 -0700
Subject: [PATCH 039/389] CONMAN-697 (Fix typo for did_not_subscribe statuses)
(#1661)
* fix typo for did_not_subscribe statuses
* undo other changes
* rename label for subscription groups
* rename description
* rename description
---
.../segment-profiles/sendSubscription/index.ts | 2 +-
.../sendSubscription/subscription-properties.ts | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
index d17170c9e3..36820014e4 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/index.ts
@@ -41,7 +41,7 @@ interface SubscriptionStatusConfig {
const subscriptionStatusConfig: SubscriptionStatusConfig[] = [
{ status: 'SUBSCRIBED', matchingStatuses: ['true', 'subscribed'] },
{ status: 'UNSUBSCRIBED', matchingStatuses: ['false', 'unsubscribed'] },
- { status: 'DID-NOT-SUBSCRIBE', matchingStatuses: ['did-not-subscribe', 'did_not_subscribe'] }
+ { status: 'DID_NOT_SUBSCRIBE', matchingStatuses: ['did-not-subscribe', 'did_not_subscribe'] }
]
interface SupportedChannelsConfig {
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/subscription-properties.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/subscription-properties.ts
index 72aa998649..75d1acec07 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/subscription-properties.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/subscription-properties.ts
@@ -57,7 +57,7 @@ export const ios_push_token: InputField = {
export const email_subscription_status: InputField = {
label: 'Email Subscription Status',
description:
- 'Global status of the email subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Global status of the email subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'string',
allowNull: true
}
@@ -65,7 +65,7 @@ export const email_subscription_status: InputField = {
export const sms_subscription_status: InputField = {
label: 'SMS Subscription Status',
description:
- 'Global status of the SMS subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Global status of the SMS subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'string',
allowNull: true
}
@@ -73,7 +73,7 @@ export const sms_subscription_status: InputField = {
export const whatsapp_subscription_status: InputField = {
label: 'WhatsApp Subscription Status',
description:
- 'Global status of the WhatsApp subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Global status of the WhatsApp subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'string',
allowNull: true
}
@@ -81,7 +81,7 @@ export const whatsapp_subscription_status: InputField = {
export const android_push_subscription_status: InputField = {
label: 'Android Push Subscription Status',
description:
- 'Global status of the android push subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Global status of the android push subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'string',
allowNull: true
}
@@ -89,15 +89,15 @@ export const android_push_subscription_status: InputField = {
export const ios_push_subscription_status: InputField = {
label: 'Ios Push Subscription Status',
description:
- 'Global status of the ios push subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Global status of the ios push subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'string',
allowNull: true
}
export const subscription_groups: InputField = {
- label: 'Subscription Groups',
+ label: 'Email Subscription Groups',
description:
- 'Subscription status for the groups. Object containing group names as keys and statuses as values. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.',
+ 'Group Subscription statuses are supported for the email channel. This object contains group names as keys and statuses as values. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.',
type: 'object',
additionalProperties: true,
defaultObjectUI: 'keyvalue'
From 8db707965147f8cfbae98394b0fa71d302d26d7c Mon Sep 17 00:00:00 2001
From: hvardhan-unth <117922634+hvardhan-unth@users.noreply.github.com>
Date: Tue, 17 Oct 2023 15:48:26 +0530
Subject: [PATCH 040/389] Removed unwanted console (#1660)
Co-authored-by: Harsh Vardhan
---
.../segment-profiles/sendSubscription/__tests__/index.test.ts | 2 --
1 file changed, 2 deletions(-)
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
index 4433858629..3dfc69f004 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/__tests__/index.test.ts
@@ -244,8 +244,6 @@ describe('SegmentProfiles.sendSubscription', () => {
}
})
- console.log('edwuy: ', event)
-
const responses = await testDestination.testAction('sendSubscription', {
event,
mapping: defaultSubscriptionMapping,
From 4e38ff31a6e518efd86bbd2d606cdd45100ba760 Mon Sep 17 00:00:00 2001
From: Miguel Pavon Diaz <71112226+miguelpdiaz8@users.noreply.github.com>
Date: Tue, 17 Oct 2023 06:41:39 -0400
Subject: [PATCH 041/389] CHANNELS-850: Twilio/Sendgrid stats showing N/A
error_code for error in datadog (#1596)
* CHANNELS-850: Twilio/Sendgrid stats showing N/A error_code for errors in datadog
* Fix tests
* Remove unnecessary types
* Populate response status and code when is timeout error
* Few code cleaning
---
.../engage/utils/EngageActionPerformer.ts | 10 +++++++++-
.../src/destinations/engage/utils/ResponseError.ts | 14 ++++++++++----
2 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/packages/destination-actions/src/destinations/engage/utils/EngageActionPerformer.ts b/packages/destination-actions/src/destinations/engage/utils/EngageActionPerformer.ts
index d0c8ab283e..3ec91d3adb 100644
--- a/packages/destination-actions/src/destinations/engage/utils/EngageActionPerformer.ts
+++ b/packages/destination-actions/src/destinations/engage/utils/EngageActionPerformer.ts
@@ -69,7 +69,15 @@ export abstract class EngageActionPerformer
Date: Tue, 17 Oct 2023 06:58:07 -0400
Subject: [PATCH 042/389] [The Trade Desk CRM] Change getAudience method
(#1654)
* [The Trade Desk CRM] Fix getAudience method
* Add unit tests
* Address comments
---
.../__tests__/index.test.ts | 76 +++++++++++++++++++
.../the-trade-desk-crm/functions.ts | 31 ++++++++
.../destinations/the-trade-desk-crm/index.ts | 30 +++-----
3 files changed, 118 insertions(+), 19 deletions(-)
create mode 100644 packages/destination-actions/src/destinations/the-trade-desk-crm/__tests__/index.test.ts
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/__tests__/index.test.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/__tests__/index.test.ts
new file mode 100644
index 0000000000..4231014bce
--- /dev/null
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/__tests__/index.test.ts
@@ -0,0 +1,76 @@
+import nock from 'nock'
+import { createTestIntegration, IntegrationError } from '@segment/actions-core'
+import Destination from '../index'
+import { API_VERSION } from '../index'
+
+const testDestination = createTestIntegration(Destination)
+
+const createAudienceInput = {
+ settings: {
+ auth_token: 'AUTH_TOKEN',
+ advertiser_id: 'ADVERTISER_ID',
+ __segment_internal_engage_force_full_sync: true,
+ __segment_internal_engage_batch_sync: true
+ },
+ audienceName: '',
+ audienceSettings: {
+ region: 'US'
+ }
+}
+
+const getAudienceInput = {
+ settings: {
+ auth_token: 'AUTH_TOKEN',
+ advertiser_id: 'ADVERTISER_ID',
+ __segment_internal_engage_force_full_sync: true,
+ __segment_internal_engage_batch_sync: true
+ },
+ externalId: 'crm_data_id',
+ audienceSettings: {
+ region: 'US'
+ }
+}
+
+describe('The Trade Desk CRM', () => {
+ describe('createAudience', () => {
+ it('should fail if no audience name is set', async () => {
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('should create a new Trade Desk CRM Data Segment', async () => {
+ nock(`https://api.thetradedesk.com/${API_VERSION}/crmdata/segment`).post(/.*/).reply(200, {
+ CrmDataId: 'test_audience'
+ })
+
+ createAudienceInput.audienceName = 'The Super Mario Brothers Fans'
+ createAudienceInput.audienceSettings.region = 'US'
+
+ const r = await testDestination.createAudience(createAudienceInput)
+ expect(r).toEqual({ externalId: 'test_audience' })
+ })
+ })
+
+ describe('getAudience', () => {
+ it('should fail if Trade Desk replies with an error', async () => {
+ nock(`https://api.thetradedesk.com/${API_VERSION}/crmdata/segment/advertiser_id?pagingToken=paging_token`)
+ .get(/.*/)
+ .reply(400, { Segments: [], PagingToken: null })
+ await expect(testDestination.getAudience(getAudienceInput)).rejects.toThrowError()
+ })
+
+ it('should succeed when Segment External ID matches Data Segment in TikTok', async () => {
+ nock(`https://api.thetradedesk.com/${API_VERSION}/crmdata/segment/advertiser_id`)
+ .get(/.*/)
+ .reply(200, {
+ Segments: [{ SegmentName: 'not_test_audience', CrmDataId: 'crm_data_id' }],
+ PagingToken: 'paging_token'
+ })
+ nock(`https://api.thetradedesk.com/${API_VERSION}/crmdata/segment/advertiser_id?pagingToken=paging_token`)
+ .get(/.*/)
+ .reply(200, { Segments: [], PagingToken: null })
+
+ const r = await testDestination.getAudience(getAudienceInput)
+ expect(r).toEqual({ externalId: 'crm_data_id' })
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
index 2be8e4f460..12baddfda0 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
@@ -2,6 +2,7 @@ import { RequestClient, ModifiedResponse, PayloadValidationError } from '@segmen
import { Settings } from './generated-types'
import { Payload } from './syncAudience/generated-types'
import { createHash } from 'crypto'
+import { IntegrationError } from '@segment/actions-core'
import { sendEventToAWS } from './awsClient'
@@ -170,3 +171,33 @@ async function uploadCRMDataToDropEndpoint(request: RequestClient, endpoint: str
body: users
})
}
+
+export async function getAllDataSegments(request: RequestClient, advertiserId: string, authToken: string) {
+ const allDataSegments: Segments[] = []
+ // initial call to get first page
+ let response: ModifiedResponse = await request(`${BASE_URL}/crmdata/segment/${advertiserId}`, {
+ method: 'GET'
+ })
+
+ if (response.status != 200 || !response.data.Segments) {
+ throw new IntegrationError('Invalid response from get audience request', 'INVALID_RESPONSE', 400)
+ }
+ let segments = response.data.Segments
+ // pagingToken leads you to the next page
+ let pagingToken = response.data.PagingToken
+ // keep iterating through pages until the last empty page
+ while (segments.length > 0) {
+ allDataSegments.push(...segments)
+ response = await request(`${BASE_URL}/crmdata/segment/${advertiserId}?pagingToken=${pagingToken}`, {
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'TTD-Auth': authToken
+ }
+ })
+
+ segments = response.data.Segments
+ pagingToken = response.data.PagingToken
+ }
+ return allDataSegments
+}
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
index ffaeef132a..241afccfde 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/index.ts
@@ -1,9 +1,10 @@
import type { AudienceDestinationDefinition, ModifiedResponse } from '@segment/actions-core'
import type { Settings, AudienceSettings } from './generated-types'
import { IntegrationError } from '@segment/actions-core'
+import { getAllDataSegments } from './functions'
import syncAudience from './syncAudience'
-const API_VERSION = 'v3'
+export const API_VERSION = 'v3'
const BASE_URL = `https://api.thetradedesk.com/${API_VERSION}`
export interface CreateApiResponse {
@@ -120,33 +121,24 @@ const destination: AudienceDestinationDefinition = {
const advertiserId = getAudienceInput.settings.advertiser_id
const authToken = getAudienceInput.settings.auth_token
- const response: ModifiedResponse = await request(
- `${BASE_URL}/crmdata/segment/${advertiserId}/${crmDataId}`,
- {
- method: 'GET',
- headers: {
- 'Content-Type': 'application/json',
- 'TTD-Auth': authToken
- }
- }
- )
-
- if (response.status !== 200) {
- throw new IntegrationError('Invalid response from get audience request', 'INVALID_RESPONSE', 400)
- }
+ const allDataSegments = await getAllDataSegments(request, advertiserId, authToken)
- const externalId = response.data.CrmDataId
+ const segmentExists = allDataSegments.filter(function (segment: Segments) {
+ if (segment.CrmDataId == crmDataId) {
+ return segment
+ }
+ })
- if (externalId !== getAudienceInput.externalId) {
+ if (segmentExists.length != 1) {
throw new IntegrationError(
- "Unable to verify ownership over audience. Segment Audience ID doesn't match The Trade Desk's Audience ID.",
+ `No CRM Data Segment with Id ${crmDataId} found for advertiser ${advertiserId}`,
'INVALID_REQUEST_DATA',
400
)
}
return {
- externalId: externalId
+ externalId: crmDataId
}
}
},
From 3ad937da5ac065c7f92e8f6f313610a93d3c1490 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 14:04:41 +0200
Subject: [PATCH 043/389] Launchdarkly Audiences - keying off of audience_id
(#1659)
* adding audience_id field
* making traits_or_props field hidden
---
.../__tests__/__snapshots__/snapshot.test.ts.snap | 2 +-
.../__tests__/__snapshots__/snapshot.test.ts.snap | 4 ++--
.../syncAudience/__tests__/index.test.ts | 9 ++++++---
.../syncAudience/__tests__/snapshot.test.ts | 3 +++
.../syncAudience/custom-audience-operations.ts | 15 +++++++++++----
.../syncAudience/generated-types.ts | 4 ++++
.../launchdarkly-audiences/syncAudience/index.ts | 11 +++++++++++
7 files changed, 38 insertions(+), 10 deletions(-)
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/launchdarkly-audiences/__tests__/__snapshots__/snapshot.test.ts.snap
index e492d76c9f..e0b1a2ed35 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -4,7 +4,7 @@ exports[`Testing snapshot for actions-launchdarkly-audiences destination: syncAu
Object {
"batch": Array [
Object {
- "cohortId": "test_audience",
+ "cohortId": "uKRBKG",
"cohortName": "Test audience",
"userId": "uKRBKG",
"value": true,
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/__snapshots__/snapshot.test.ts.snap
index 7208f654bb..00e85df1c4 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -4,7 +4,7 @@ exports[`Testing snapshot for LaunchDarklyAudiences's syncAudience destination a
Object {
"batch": Array [
Object {
- "cohortId": "test_audience",
+ "cohortId": "ld_segment_audience_id",
"cohortName": "Test audience",
"userId": "&bUSudpNPsUWT",
"value": true,
@@ -38,7 +38,7 @@ exports[`Testing snapshot for LaunchDarklyAudiences's syncAudience destination a
Object {
"batch": Array [
Object {
- "cohortId": "test_audience",
+ "cohortId": "ld_segment_audience_id",
"cohortName": "Test audience",
"userId": "&bUSudpNPsUWT",
"value": false,
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/index.test.ts
index 3f8dec26dd..434cf766e1 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/index.test.ts
@@ -10,7 +10,8 @@ const goodTrackEvent = createTestEvent({
context: {
personas: {
computation_class: 'audience',
- computation_key: 'ld_segment_test'
+ computation_key: 'ld_segment_test',
+ computation_id: 'ld_segment_audience_id'
},
traits: {
email: 'test@email.com'
@@ -27,7 +28,8 @@ const goodIdentifyEvent = createTestEvent({
context: {
personas: {
computation_class: 'audience',
- computation_key: 'ld_segment_test'
+ computation_key: 'ld_segment_test',
+ computation_id: 'ld_segment_audience_id'
}
},
traits: {
@@ -40,7 +42,8 @@ const goodIdentifyEvent = createTestEvent({
const badEvent = createTestEvent({
context: {
personas: {
- computation_key: 'ld_segment_test'
+ computation_key: 'ld_segment_test',
+ computation_id: 'ld_segment_audience_id'
},
traits: {
email: 'test@email.com'
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/snapshot.test.ts
index fde8ba14bc..b8e6e36adf 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/snapshot.test.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/__tests__/snapshot.test.ts
@@ -13,11 +13,13 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
const action = destination.actions[actionSlug]
const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
eventData['segment_audience_key'] = 'test_audience'
+ eventData['segment_audience_id'] = 'ld_segment_audience_id'
eventData['segment_computation_action'] = 'audience'
eventData['traits_or_props'] = { [eventData['segment_audience_key']]: true }
setStaticDataForSnapshot(eventData, 'context_kind', 'customContextKind')
setStaticDataForSnapshot(eventData, 'context_key', 'user_id_only')
+ setStaticDataForSnapshot(eventData, 'context_id', 'ld_segment_audience_id')
setStaticDataForSnapshot(settingsData, 'clientId', 'environment-id')
setStaticDataForSnapshot(settingsData, 'apiKey', 'api-key')
@@ -50,6 +52,7 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
const action = destination.actions[actionSlug]
const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
eventData['segment_audience_key'] = 'test_audience'
+ eventData['segment_audience_id'] = 'ld_segment_audience_id'
eventData['segment_computation_action'] = 'audience'
eventData['traits_or_props'] = { [eventData['segment_audience_key']]: false }
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/custom-audience-operations.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/custom-audience-operations.ts
index 67d260274f..c70a6e7c39 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/custom-audience-operations.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/custom-audience-operations.ts
@@ -34,9 +34,14 @@ const snakeCaseToSentenceCase = (key: string) => {
* @param audienceId audience ID
* @param include include or exclude the context from LaunchDarkly's segment
*/
-const createContextForBatch = (contextKey: string, audienceId: string, audienceAction: AudienceAction) => ({
+const createContextForBatch = (
+ contextKey: string,
+ audienceKey: string,
+ audienceId: string,
+ audienceAction: AudienceAction
+) => ({
userId: contextKey,
- cohortName: snakeCaseToSentenceCase(audienceId),
+ cohortName: snakeCaseToSentenceCase(audienceKey),
cohortId: audienceId,
value: audienceAction === CONSTANTS.ADD ? true : false
})
@@ -78,7 +83,7 @@ const parseCustomAudienceBatches = (payload: Payload[], settings: Settings): Aud
const audienceMap = new Map()
for (const p of payload) {
- const audienceId = p.segment_audience_key
+ const audienceId = p.segment_audience_id
const contextKey = getContextKey(p)
let audienceBatch: AudienceBatch = {
@@ -97,7 +102,9 @@ const parseCustomAudienceBatches = (payload: Payload[], settings: Settings): Aud
audienceMap.set(audienceId, audienceBatch)
}
- audienceBatch.batch.push(createContextForBatch(contextKey, audienceId, p.audience_action as AudienceAction))
+ audienceBatch.batch.push(
+ createContextForBatch(contextKey, p.segment_audience_key, audienceId, p.audience_action as AudienceAction)
+ )
}
return Array.from(audienceMap.values())
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/generated-types.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/generated-types.ts
index 05e81e9c04..2cc64c90d7 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/generated-types.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/generated-types.ts
@@ -1,6 +1,10 @@
// Generated file. DO NOT MODIFY IT BY HAND.
export interface Payload {
+ /**
+ * Segment Audience ID to which user identifier should be added or removed
+ */
+ segment_audience_id: string
/**
* Segment Audience key to which user identifier should be added or removed
*/
diff --git a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
index 4b4ebe53dc..ba8e88d780 100644
--- a/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
+++ b/packages/destination-actions/src/destinations/launchdarkly-audiences/syncAudience/index.ts
@@ -10,6 +10,16 @@ const action: ActionDefinition = {
description: 'Sync Engage Audiences to LaunchDarkly segments',
defaultSubscription: 'type = "identify" or type = "track"',
fields: {
+ segment_audience_id: {
+ label: 'Audience ID',
+ description: 'Segment Audience ID to which user identifier should be added or removed',
+ type: 'string',
+ unsafe_hidden: true,
+ required: true,
+ default: {
+ '@path': '$.context.personas.computation_id'
+ }
+ },
segment_audience_key: {
label: 'Audience Key',
description: 'Segment Audience key to which user identifier should be added or removed',
@@ -89,6 +99,7 @@ const action: ActionDefinition = {
description: 'A computed object for track and identify events. This field should not need to be edited.',
type: 'object',
required: true,
+ unsafe_hidden: true,
default: {
'@if': {
exists: { '@path': '$.properties' },
From c134b53e7f1151973589a01d697cd2f2a5012d2d Mon Sep 17 00:00:00 2001
From: akalyuzhnyi <115689020+akalyuzhnyi@users.noreply.github.com>
Date: Tue, 17 Oct 2023 17:58:06 +0300
Subject: [PATCH 044/389] Action Destination for Kameleoon (#1644)
* init kameleoon destination
* fixing timestamp test issue
* fix after review
* added description and updated tests
* updated tests and added additional checking for apikey
---------
Co-authored-by: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
---
.../__snapshots__/snapshot.test.ts.snap | 26 +++++
.../kameleoon/__tests__/index.test.ts | 38 +++++++
.../kameleoon/__tests__/snapshot.test.ts | 81 +++++++++++++
.../destinations/kameleoon/generated-types.ts | 12 ++
.../src/destinations/kameleoon/index.ts | 82 ++++++++++++++
.../__snapshots__/snapshot.test.ts.snap | 26 +++++
.../logEvent/__tests__/index.test.ts | 106 ++++++++++++++++++
.../logEvent/__tests__/snapshot.test.ts | 79 +++++++++++++
.../kameleoon/logEvent/generated-types.ts | 36 ++++++
.../destinations/kameleoon/logEvent/index.ts | 103 +++++++++++++++++
.../src/destinations/kameleoon/properties.ts | 1 +
11 files changed, 590 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/kameleoon/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/kameleoon/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/index.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/logEvent/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/logEvent/index.ts
create mode 100644 packages/destination-actions/src/destinations/kameleoon/properties.ts
diff --git a/packages/destination-actions/src/destinations/kameleoon/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/kameleoon/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..b29c69aa5b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-kameleoon destination: logEvent action - all fields 1`] = `
+Object {
+ "context": Object {
+ "testType": "VA*d2uO)D#",
+ },
+ "event": "VA*d2uO)D#",
+ "messageId": "VA*d2uO)D#",
+ "properties": Object {
+ "kameleoonVisitorCode": "VA*d2uO)D#",
+ "testType": "VA*d2uO)D#",
+ },
+ "timestamp": Any,
+ "type": "VA*d2uO)D#",
+}
+`;
+
+exports[`Testing snapshot for actions-kameleoon destination: logEvent action - required fields 1`] = `
+Object {
+ "messageId": "VA*d2uO)D#",
+ "properties": Object {},
+ "timestamp": Any,
+ "type": "VA*d2uO)D#",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/kameleoon/__tests__/index.test.ts b/packages/destination-actions/src/destinations/kameleoon/__tests__/index.test.ts
new file mode 100644
index 0000000000..61f1134301
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/__tests__/index.test.ts
@@ -0,0 +1,38 @@
+import { createTestIntegration } from '@segment/actions-core'
+import nock from 'nock'
+import Definition from '../index'
+import type { Settings } from '../generated-types'
+import { BASE_URL } from '../properties'
+
+const CLIENT_ID = 'CLIENT_ID'
+const CLIENT_SECRET = 'CLIENT_SECRET'
+
+const testDestination = createTestIntegration(Definition)
+
+describe('Kameleoon', () => {
+ describe('testAuthentication', () => {
+ it('should validate cation inputs', async () => {
+ nock(BASE_URL + '/getapikey')
+ .get(/.*/)
+ .reply(200, {})
+
+ const apiKey = {
+ id: CLIENT_ID,
+ secret: CLIENT_SECRET
+ }
+ const authData: Settings = {
+ apiKey: Buffer.from(JSON.stringify(apiKey)).toString('base64'),
+ sitecode: '1q2w3e4r5t'
+ }
+
+ await expect(testDestination.testAuthentication(authData)).resolves.not.toThrowError()
+ })
+ it('should throw error for invalid sitecode', async () => {
+ const settings: Settings = {
+ apiKey: '',
+ sitecode: '1q2w3e4'
+ }
+ await expect(testDestination.testAuthentication(settings)).rejects.toThrowError()
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/kameleoon/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/kameleoon/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..4e6614fd8a
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/__tests__/snapshot.test.ts
@@ -0,0 +1,81 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-kameleoon'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot({
+ timestamp: expect.any(String)
+ })
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot({
+ timestamp: expect.any(String)
+ })
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/kameleoon/generated-types.ts b/packages/destination-actions/src/destinations/kameleoon/generated-types.ts
new file mode 100644
index 0000000000..9fa7e7fe04
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/generated-types.ts
@@ -0,0 +1,12 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Kameleoon API key. You can generate one using the link in the help doc (https://help.kameleoon.com/setting-up-segment/).
+ */
+ apiKey: string
+ /**
+ * Kameleoon project sitecode. You can find this project dashboard (https://help.kameleoon.com/question/how-do-i-find-my-site-id/).
+ */
+ sitecode: string
+}
diff --git a/packages/destination-actions/src/destinations/kameleoon/index.ts b/packages/destination-actions/src/destinations/kameleoon/index.ts
new file mode 100644
index 0000000000..440e58efe9
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/index.ts
@@ -0,0 +1,82 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import { defaultValues } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+
+import logEvent from './logEvent'
+import { BASE_URL } from './properties'
+
+const presets: DestinationDefinition['presets'] = [
+ {
+ name: 'Track Calls',
+ subscribe: 'type = "track"',
+ partnerAction: 'logEvent',
+ mapping: defaultValues(logEvent.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Page Calls',
+ subscribe: 'type = "page"',
+ partnerAction: 'logEvent',
+ mapping: defaultValues(logEvent.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Screen Calls',
+ subscribe: 'type = "screen"',
+ partnerAction: 'logEvent',
+ mapping: defaultValues(logEvent.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Identify Calls',
+ subscribe: 'type = "identify"',
+ partnerAction: 'logEvent',
+ mapping: defaultValues(logEvent.fields),
+ type: 'automatic'
+ }
+]
+
+const destination: DestinationDefinition = {
+ name: 'Actions Kameleoon',
+ slug: 'actions-kameleoon',
+ mode: 'cloud',
+ description: 'Send Segment events to Kameleoon',
+ authentication: {
+ scheme: 'custom',
+ fields: {
+ apiKey: {
+ label: 'API Key',
+ description:
+ 'Kameleoon API key. You can generate one using the link in the help doc (https://help.kameleoon.com/setting-up-segment/).',
+ type: 'password',
+ required: true
+ },
+ sitecode: {
+ label: 'Sitecode',
+ description:
+ 'Kameleoon project sitecode. You can find this project dashboard (https://help.kameleoon.com/question/how-do-i-find-my-site-id/).',
+ type: 'string',
+ required: true
+ }
+ },
+ testAuthentication: (request, { settings }) => {
+ if (settings.sitecode.toString().length !== 10) {
+ throw new Error('Invalid project sitecode. Please check your sitecode')
+ }
+
+ const apiKey = Object.entries(JSON.parse(Buffer.from(settings.apiKey, 'base64').toString('ascii')))
+ .map(([key, value]) => key + '=' + value)
+ .join('&')
+
+ return request(BASE_URL + '/getapikey?' + apiKey, {
+ method: 'GET'
+ })
+ }
+ },
+ presets,
+ actions: {
+ logEvent
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..47dfa6754e
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,26 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Kameleoon's logEvent destination action: all fields 1`] = `
+Object {
+ "context": Object {
+ "testType": "wNACk[QgaEuFPK",
+ },
+ "event": "wNACk[QgaEuFPK",
+ "messageId": "wNACk[QgaEuFPK",
+ "properties": Object {
+ "kameleoonVisitorCode": "wNACk[QgaEuFPK",
+ "testType": "wNACk[QgaEuFPK",
+ },
+ "timestamp": Any,
+ "type": "wNACk[QgaEuFPK",
+}
+`;
+
+exports[`Testing snapshot for Kameleoon's logEvent destination action: required fields 1`] = `
+Object {
+ "messageId": "wNACk[QgaEuFPK",
+ "properties": Object {},
+ "timestamp": Any,
+ "type": "wNACk[QgaEuFPK",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/index.test.ts
new file mode 100644
index 0000000000..e6f631d6c5
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/index.test.ts
@@ -0,0 +1,106 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+import { BASE_URL } from '../../properties'
+
+const SITE_CODE = 'mysitecode'
+const VISITOR_CODE = 'visitorCode'
+const CLIENT_ID = 'CLIENT_ID'
+const CLIENT_SECRET = 'CLIENT_SECRET'
+
+const testDestination = createTestIntegration(Destination)
+
+describe('Kameleoon.logEvent', () => {
+ it('should work', async () => {
+ nock(BASE_URL).post('').reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ timestamp: '2023-10-06T10:46:53.902Z',
+ properties: {
+ kameleoonVisitorCode: VISITOR_CODE
+ },
+ context: {
+ active: true,
+ app: {
+ name: 'InitechGlobal',
+ version: '545',
+ build: '3.0.1.545',
+ namespace: 'com.production.segment'
+ },
+ campaign: {
+ name: 'TPS Innovation Newsletter',
+ source: 'Newsletter',
+ medium: 'email',
+ term: 'tps reports',
+ content: 'image link'
+ },
+ device: {
+ id: 'B5372DB0-C21E-11E4-8DFC-AA07A5B093DB',
+ advertisingId: '7A3CBEA0-BDF5-11E4-8DFC-AA07A5B093DB',
+ adTrackingEnabled: true,
+ manufacturer: 'Apple',
+ model: 'iPhone7,2',
+ name: 'maguro',
+ type: 'ios'
+ },
+ ip: '8.8.8.8',
+ library: {
+ name: 'analytics.js',
+ version: '2.11.1'
+ },
+ locale: 'en-US',
+ location: {
+ city: 'San Francisco',
+ country: 'United States',
+ latitude: 40.2964197,
+ longitude: -76.9411617,
+ speed: 0
+ },
+ network: {
+ bluetooth: false,
+ carrier: 'T-Mobile US',
+ cellular: true,
+ wifi: false
+ },
+ os: {
+ name: 'iPhone OS',
+ version: '8.1.3'
+ },
+ page: {
+ path: '/academy/',
+ referrer: '',
+ search: '',
+ title: 'Analytics Academy',
+ url: 'https://segment.com/academy/'
+ },
+ screen: {
+ width: 320,
+ height: 568,
+ density: 2
+ },
+ groupId: '12345',
+ timezone: 'Europe/Amsterdam',
+ userAgent:
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
+ },
+ messageId: 'test-message-ikxq2j1u94'
+ })
+ const apiKey = {
+ id: CLIENT_ID,
+ secret: CLIENT_SECRET
+ }
+ const responses = await testDestination.testAction('logEvent', {
+ event,
+ settings: {
+ apiKey: Buffer.from(JSON.stringify(apiKey)).toString('base64'),
+ sitecode: SITE_CODE
+ },
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..52fac41aa2
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/logEvent/__tests__/snapshot.test.ts
@@ -0,0 +1,79 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'logEvent'
+const destinationSlug = 'Kameleoon'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot({
+ timestamp: expect.any(String)
+ })
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot({
+ timestamp: expect.any(String)
+ })
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/kameleoon/logEvent/generated-types.ts b/packages/destination-actions/src/destinations/kameleoon/logEvent/generated-types.ts
new file mode 100644
index 0000000000..0dfc6a0f75
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/logEvent/generated-types.ts
@@ -0,0 +1,36 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The event name
+ */
+ event?: string
+ /**
+ * The type of the event
+ */
+ type: string
+ /**
+ * Additional event Properties or user Traits to send with the event
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+ /**
+ * Kameleoon Visitor Code - a unique identifier for the user
+ */
+ kameleoonVisitorCode?: string
+ /**
+ * The timestamp of the event
+ */
+ timestamp: string
+ /**
+ * Context properties to send with the event
+ */
+ context?: {
+ [k: string]: unknown
+ }
+ /**
+ * The Segment messageId
+ */
+ messageId: string
+}
diff --git a/packages/destination-actions/src/destinations/kameleoon/logEvent/index.ts b/packages/destination-actions/src/destinations/kameleoon/logEvent/index.ts
new file mode 100644
index 0000000000..ac71864c0b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/logEvent/index.ts
@@ -0,0 +1,103 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import omit from 'lodash/omit'
+
+import { BASE_URL } from '../properties'
+
+const action: ActionDefinition = {
+ title: 'Log Event',
+ description: 'Send an event to Kameleoon',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ event: {
+ type: 'string',
+ required: false,
+ description: 'The event name',
+ label: 'Event Name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.event' },
+ then: { '@path': '$.event' },
+ else: { '@path': '$.name' }
+ }
+ }
+ },
+ type: {
+ label: 'Type',
+ type: 'string',
+ required: true,
+ description: 'The type of the event',
+ default: {
+ '@path': '$.type'
+ }
+ },
+ properties: {
+ type: 'object',
+ required: false,
+ description: 'Additional event Properties or user Traits to send with the event',
+ label: 'Event properties or user traits',
+ default: {
+ '@if': {
+ exists: { '@path': '$.properties' },
+ then: { '@path': '$.properties' },
+ else: { '@path': '$.traits' }
+ }
+ }
+ },
+ kameleoonVisitorCode: {
+ type: 'string',
+ required: false,
+ description: 'Kameleoon Visitor Code - a unique identifier for the user',
+ label: 'Kameleoon Visitor Code',
+ default: {
+ '@if': {
+ exists: { '@path': '$.properties.kameleoonVisitorCode' },
+ then: { '@path': '$.properties.kameleoonVisitorCode' },
+ else: { '@path': '$.traits.kameleoonVisitorCode' }
+ }
+ }
+ },
+ timestamp: {
+ type: 'string',
+ format: 'date-time',
+ required: true,
+ description: 'The timestamp of the event',
+ label: 'Timestamp',
+ default: { '@path': '$.timestamp' }
+ },
+ context: {
+ type: 'object',
+ required: false,
+ description: 'Context properties to send with the event',
+ label: 'Context properties',
+ default: { '@path': '$.context' }
+ },
+ messageId: {
+ type: 'string',
+ required: true,
+ description: 'The Segment messageId',
+ label: 'MessageId',
+ default: { '@path': '$.messageId' }
+ }
+ },
+ perform: (request, data) => {
+ const payload = {
+ ...omit(data.payload, ['kameleoonVisitorCode']),
+ properties: {
+ ...(data.payload.properties || {}),
+ kameleoonVisitorCode: data.payload.kameleoonVisitorCode
+ }
+ }
+ return request(BASE_URL, {
+ headers: {
+ authorization: `Basic ${data.settings.apiKey}`,
+ 'x-segment-settings': data.settings.sitecode
+ },
+ method: 'post',
+ json: payload
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/kameleoon/properties.ts b/packages/destination-actions/src/destinations/kameleoon/properties.ts
new file mode 100644
index 0000000000..2f5deba75d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/kameleoon/properties.ts
@@ -0,0 +1 @@
+export const BASE_URL = 'https://integrations.kameleoon.com/segmentio'
From 6a1ec26c2399ab86ae47982c1819c5f21ab50a93 Mon Sep 17 00:00:00 2001
From: Sonya Park <68977514+spjtls9@users.noreply.github.com>
Date: Tue, 17 Oct 2023 08:09:01 -0700
Subject: [PATCH 045/389] us parser fix + version fix (#1642)
---
.../mixpanel/alias/__tests__/index.test.ts | 4 +-
.../src/destinations/mixpanel/alias/index.ts | 2 +-
.../mixpanel/common/__test__/utils.test.ts | 54 +++++++++++++++++++
.../mixpanel/{ => common}/utils.ts | 37 +++++++------
.../groupIdentifyUser/__tests__/index.test.ts | 2 +-
.../mixpanel/groupIdentifyUser/index.ts | 8 +--
.../identifyUser/__tests__/index.test.ts | 18 ++++---
.../mixpanel/identifyUser/index.ts | 2 +-
.../src/destinations/mixpanel/index.ts | 2 +-
.../trackEvent/__tests__/index.test.ts | 2 +-
.../mixpanel/trackEvent/functions.ts | 2 +-
.../destinations/mixpanel/trackEvent/index.ts | 6 +--
.../trackPurchase/__tests__/index.test.ts | 12 ++---
.../mixpanel/trackPurchase/index.ts | 6 +--
14 files changed, 110 insertions(+), 47 deletions(-)
create mode 100644 packages/destination-actions/src/destinations/mixpanel/common/__test__/utils.test.ts
rename packages/destination-actions/src/destinations/mixpanel/{ => common}/utils.ts (76%)
diff --git a/packages/destination-actions/src/destinations/mixpanel/alias/__tests__/index.test.ts b/packages/destination-actions/src/destinations/mixpanel/alias/__tests__/index.test.ts
index dfb8aee100..9300b7fb61 100644
--- a/packages/destination-actions/src/destinations/mixpanel/alias/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/alias/__tests__/index.test.ts
@@ -1,7 +1,7 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
-import { ApiRegions } from '../../utils'
+import { ApiRegions } from '../../common/utils'
const testDestination = createTestIntegration(Destination)
const MIXPANEL_API_SECRET = 'test-api-key'
@@ -111,7 +111,7 @@ describe('Mixpanel.alias', () => {
settings: {
projectToken: MIXPANEL_PROJECT_TOKEN,
apiSecret: MIXPANEL_API_SECRET,
- sourceName: 'example segment source name',
+ sourceName: 'example segment source name'
}
})
expect(responses.length).toBe(1)
diff --git a/packages/destination-actions/src/destinations/mixpanel/alias/index.ts b/packages/destination-actions/src/destinations/mixpanel/alias/index.ts
index bc8f4a2279..e40b380284 100644
--- a/packages/destination-actions/src/destinations/mixpanel/alias/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/alias/index.ts
@@ -2,7 +2,7 @@ import type { ActionDefinition } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
-import { getApiServerUrl } from '../utils'
+import { getApiServerUrl } from '../common/utils'
const action: ActionDefinition = {
title: 'Alias',
diff --git a/packages/destination-actions/src/destinations/mixpanel/common/__test__/utils.test.ts b/packages/destination-actions/src/destinations/mixpanel/common/__test__/utils.test.ts
new file mode 100644
index 0000000000..75218a2292
--- /dev/null
+++ b/packages/destination-actions/src/destinations/mixpanel/common/__test__/utils.test.ts
@@ -0,0 +1,54 @@
+import { getBrowser, getBrowserVersion } from '../utils'
+
+const userAgentToBrowserTestCase = [
+ {
+ userAgent:
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36',
+ browser: 'Chrome',
+ version: '117.0.0.0'
+ },
+ {
+ userAgent:
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 14_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Safari/605.1.15',
+ browser: 'Safari',
+ version: '17.0'
+ },
+ {
+ userAgent:
+ 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1',
+ browser: 'Mobile Safari',
+ version: '17.0'
+ },
+ {
+ userAgent:
+ 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.0.0 Safari/537.36 Edg/117.0.2045.60',
+ browser: 'Microsoft Edge',
+ version: '117.0.2045.60'
+ }
+]
+
+describe('Mixpanel Browser Utility Functions', () => {
+ describe('getBrowser', () => {
+ userAgentToBrowserTestCase.forEach((test) => {
+ it(`should parse well-formed userAgent: ${test.browser}`, () => {
+ expect(getBrowser(test.userAgent)).toEqual(test.browser)
+ })
+ })
+
+ it(`return empty string for unknown browser`, () => {
+ expect(getBrowser(`Non-existent userAgent`)).toEqual(``)
+ })
+ })
+
+ describe('getVersion', () => {
+ userAgentToBrowserTestCase.forEach((test) => {
+ it(`should parse well-formed userAgent: ${test.browser}`, () => {
+ expect(getBrowserVersion(test.userAgent)).toEqual(test.version)
+ })
+ })
+
+ it(`return undefined for unknown browser`, () => {
+ expect(getBrowserVersion(`unknown userAgent Version/118.0`)).toBeUndefined()
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/mixpanel/utils.ts b/packages/destination-actions/src/destinations/mixpanel/common/utils.ts
similarity index 76%
rename from packages/destination-actions/src/destinations/mixpanel/utils.ts
rename to packages/destination-actions/src/destinations/mixpanel/common/utils.ts
index 53c8c2f28a..5063aad50b 100644
--- a/packages/destination-actions/src/destinations/mixpanel/utils.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/common/utils.ts
@@ -45,6 +45,9 @@ export function getBrowser(userAgent: string): string {
} else if (userAgent.includes('FxiOS')) {
return 'Firefox iOS'
} else if (userAgent.includes('Safari')) {
+ if (userAgent.includes('iPhone')) {
+ return `Mobile Safari`
+ }
return 'Safari'
} else if (userAgent.includes('Android')) {
return 'Android Mobile'
@@ -63,23 +66,24 @@ export function getBrowser(userAgent: string): string {
export function getBrowserVersion(userAgent: string) {
const browser = getBrowser(userAgent)
+
const versionRegexs: { [browser: string]: RegExp } = {
- 'Internet Explorer Mobile': /rv:(\d+(\.\d+)?)/,
- 'Microsoft Edge': /Edge?\/(\d+(\.\d+)?)/,
- Chrome: /Chrome\/(\d+(\.\d+)?)/,
- 'Chrome iOS': /CriOS\/(\d+(\.\d+)?)/,
- 'UC Browser': /(UCBrowser|UCWEB)\/(\d+(\.\d+)?)/,
- Safari: /Version\/(\d+(\.\d+)?)/,
- 'Mobile Safari': /Version\/(\d+(\.\d+)?)/,
- Opera: /(Opera|OPR)\/(\d+(\.\d+)?)/,
- Firefox: /Firefox\/(\d+(\.\d+)?)/,
- 'Firefox iOS': /FxiOS\/(\d+(\.\d+)?)/,
- Konqueror: /Konqueror:(\d+(\.\d+)?)/,
- BlackBerry: /BlackBerry (\d+(\.\d+)?)/,
- 'Android Mobile': /android\s(\d+(\.\d+)?)/,
- 'Samsung Internet': /SamsungBrowser\/(\d+(\.\d+)?)/,
- 'Internet Explorer': /(rv:|MSIE )(\d+(\.\d+)?)/,
- Mozilla: /rv:(\d+(\.\d+)?)/
+ 'Internet Explorer Mobile': /rv:(\d+(\.\d+)+)/,
+ 'Microsoft Edge': /Edge?\/(\d+(\.\d+)+)/,
+ Chrome: /Chrome\/(\d+(\.\d+)+)/,
+ 'Chrome iOS': /CriOS\/(\d+(\.\d+)+)/,
+ 'UC Browser': /(UCBrowser|UCWEB)\/(\d+(\.\d+)+)/,
+ Safari: /Version\/(\d+(\.\d+)+)/,
+ 'Mobile Safari': /Version\/(\d+(\.\d+)+)/,
+ Opera: /(Opera|OPR)\/(\d+(\.\d+)+)/,
+ Firefox: /Firefox\/(\d+(\.\d+)+)/,
+ 'Firefox iOS': /FxiOS\/(\d+(\.\d+)+)/,
+ Konqueror: /Konqueror:(\d+(\.\d+)+)/,
+ BlackBerry: /BlackBerry (\d+(\.\d+)+)/,
+ 'Android Mobile': /android\s(\d+(\.\d+)+)/,
+ 'Samsung Internet': /SamsungBrowser\/(\d+(\.\d+)+)/,
+ 'Internet Explorer': /(rv:|MSIE )(\d+(\.\d+)+)/,
+ Mozilla: /rv:(\d+(\.\d+)+)/
}
const regex = versionRegexs[browser]
if (!regex) return regex
@@ -87,6 +91,7 @@ export function getBrowserVersion(userAgent: string) {
if (!matches) {
return undefined
}
+
return matches[matches.length - 2]
}
diff --git a/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/__tests__/index.test.ts b/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/__tests__/index.test.ts
index 907992f273..742ba45c6d 100644
--- a/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/__tests__/index.test.ts
@@ -1,7 +1,7 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
-import { ApiRegions } from '../../utils'
+import { ApiRegions } from '../../common/utils'
const testDestination = createTestIntegration(Destination)
const MIXPANEL_API_SECRET = 'test-api-key'
diff --git a/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/index.ts b/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/index.ts
index 1002aa3081..b1635dbde6 100644
--- a/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/groupIdentifyUser/index.ts
@@ -1,6 +1,6 @@
import { ActionDefinition, IntegrationError, omit } from '@segment/actions-core'
import type { Settings } from '../generated-types'
-import { getApiServerUrl } from '../utils'
+import { getApiServerUrl } from '../common/utils'
import type { Payload } from './generated-types'
const action: ActionDefinition = {
@@ -48,16 +48,16 @@ const action: ActionDefinition = {
const traits = {
...omit(payload.traits, ['name']),
- $name: payload.traits.name // transform to Mixpanel reserved property
+ $name: payload.traits.name // transform to Mixpanel reserved property
}
const data = {
$token: settings.projectToken,
$group_key: group_key,
$group_id: group_id,
- $set: traits,
+ $set: traits
}
- return request(`${ getApiServerUrl(settings.apiRegion) }/groups`, {
+ return request(`${getApiServerUrl(settings.apiRegion)}/groups`, {
method: 'post',
body: new URLSearchParams({ data: JSON.stringify(data) })
})
diff --git a/packages/destination-actions/src/destinations/mixpanel/identifyUser/__tests__/index.test.ts b/packages/destination-actions/src/destinations/mixpanel/identifyUser/__tests__/index.test.ts
index 47c0fddcd3..97ba7a649a 100644
--- a/packages/destination-actions/src/destinations/mixpanel/identifyUser/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/identifyUser/__tests__/index.test.ts
@@ -1,7 +1,7 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
-import { ApiRegions } from '../../utils'
+import { ApiRegions } from '../../common/utils'
const testDestination = createTestIntegration(Destination)
const MIXPANEL_API_SECRET = 'test-api-key'
@@ -11,7 +11,8 @@ const timestamp = '2021-08-17T15:21:15.449Z'
describe('Mixpanel.identifyUser', () => {
it('should validate action fields', async () => {
const event = createTestEvent({
- timestamp, traits: {
+ timestamp,
+ traits: {
abc: '123',
created: '2022-10-12T00:00:00.000Z',
email: 'joe@mixpanel.com',
@@ -19,7 +20,7 @@ describe('Mixpanel.identifyUser', () => {
lastName: 'Doe',
username: 'Joe Doe',
phone: '12345678',
- name: 'Joe',
+ name: 'Joe'
}
})
@@ -75,20 +76,23 @@ describe('Mixpanel.identifyUser', () => {
it('name should automatically be derived from the firstName and lastName traits if they are defined.', async () => {
const event = createTestEvent({
- timestamp, traits: {
+ timestamp,
+ traits: {
firstName: 'Joe',
lastName: 'Doe'
}
})
const event2 = createTestEvent({
- timestamp, traits: {
+ timestamp,
+ traits: {
firstName: 'Joe'
}
})
const event3 = createTestEvent({
- timestamp, traits: {
+ timestamp,
+ traits: {
lastName: 'Doe'
}
})
@@ -270,7 +274,7 @@ describe('Mixpanel.identifyUser', () => {
settings: {
projectToken: MIXPANEL_PROJECT_TOKEN,
apiSecret: MIXPANEL_API_SECRET,
- sourceName: 'example segment source name',
+ sourceName: 'example segment source name'
}
})
expect(responses.length).toBe(2)
diff --git a/packages/destination-actions/src/destinations/mixpanel/identifyUser/index.ts b/packages/destination-actions/src/destinations/mixpanel/identifyUser/index.ts
index 109c48457b..4e86ec46db 100644
--- a/packages/destination-actions/src/destinations/mixpanel/identifyUser/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/identifyUser/index.ts
@@ -2,7 +2,7 @@ import { ActionDefinition, IntegrationError, omit } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
-import { getApiServerUrl, getConcatenatedName } from '../utils'
+import { getApiServerUrl, getConcatenatedName } from '../common/utils'
import { MixpanelEngageProperties, MixpanelEngageSet } from '../mixpanel-types'
const action: ActionDefinition = {
diff --git a/packages/destination-actions/src/destinations/mixpanel/index.ts b/packages/destination-actions/src/destinations/mixpanel/index.ts
index 319e805220..8d0681b47c 100644
--- a/packages/destination-actions/src/destinations/mixpanel/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/index.ts
@@ -7,7 +7,7 @@ import identifyUser from './identifyUser'
import groupIdentifyUser from './groupIdentifyUser'
import alias from './alias'
-import { ApiRegions, StrictMode } from './utils'
+import { ApiRegions, StrictMode } from './common/utils'
import trackPurchase from './trackPurchase'
diff --git a/packages/destination-actions/src/destinations/mixpanel/trackEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/mixpanel/trackEvent/__tests__/index.test.ts
index 510f45dfe9..1fa99ed9d3 100644
--- a/packages/destination-actions/src/destinations/mixpanel/trackEvent/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/trackEvent/__tests__/index.test.ts
@@ -1,7 +1,7 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration } from '@segment/actions-core'
import Destination from '../../index'
-import { ApiRegions, StrictMode } from '../../utils'
+import { ApiRegions, StrictMode } from '../../common/utils'
const testDestination = createTestIntegration(Destination)
const MIXPANEL_API_SECRET = 'test-api-key'
diff --git a/packages/destination-actions/src/destinations/mixpanel/trackEvent/functions.ts b/packages/destination-actions/src/destinations/mixpanel/trackEvent/functions.ts
index 6cd3ef60e9..f175949209 100644
--- a/packages/destination-actions/src/destinations/mixpanel/trackEvent/functions.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/trackEvent/functions.ts
@@ -3,7 +3,7 @@ import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import dayjs from '../../../lib/dayjs'
import { MixpanelEventProperties } from '../mixpanel-types'
-import { getBrowser, getBrowserVersion, cheapGuid } from '../utils'
+import { getBrowser, getBrowserVersion, cheapGuid } from '../common/utils'
const mixpanelReservedProperties = ['time', 'id', '$anon_id', 'distinct_id', '$group_id', '$insert_id', '$user_id']
diff --git a/packages/destination-actions/src/destinations/mixpanel/trackEvent/index.ts b/packages/destination-actions/src/destinations/mixpanel/trackEvent/index.ts
index 1445bb1ee3..ceb473230d 100644
--- a/packages/destination-actions/src/destinations/mixpanel/trackEvent/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/trackEvent/index.ts
@@ -2,7 +2,7 @@ import { ActionDefinition, RequestClient } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { MixpanelEvent } from '../mixpanel-types'
-import { getApiServerUrl } from '../utils'
+import { getApiServerUrl } from '../common/utils'
import { getEventProperties } from './functions'
import { eventProperties } from '../mixpanel-properties'
@@ -19,11 +19,11 @@ const getEventFromPayload = (payload: Payload, settings: Settings): MixpanelEven
const processData = async (request: RequestClient, settings: Settings, payload: Payload[]) => {
const events = payload.map((value) => getEventFromPayload(value, settings))
- return request(`${ getApiServerUrl(settings.apiRegion) }/import?strict=${ settings.strictMode ?? `1` }`, {
+ return request(`${getApiServerUrl(settings.apiRegion)}/import?strict=${settings.strictMode ?? `1`}`, {
method: 'post',
json: events,
headers: {
- authorization: `Basic ${ Buffer.from(`${ settings.apiSecret }:`).toString('base64') }`
+ authorization: `Basic ${Buffer.from(`${settings.apiSecret}:`).toString('base64')}`
}
})
}
diff --git a/packages/destination-actions/src/destinations/mixpanel/trackPurchase/__tests__/index.test.ts b/packages/destination-actions/src/destinations/mixpanel/trackPurchase/__tests__/index.test.ts
index c9551e97fc..005a8653ea 100644
--- a/packages/destination-actions/src/destinations/mixpanel/trackPurchase/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/trackPurchase/__tests__/index.test.ts
@@ -1,7 +1,7 @@
import nock from 'nock'
import { createTestEvent, createTestIntegration, omit } from '@segment/actions-core'
import Destination from '../../index'
-import { ApiRegions, StrictMode } from '../../utils'
+import { ApiRegions, StrictMode } from '../../common/utils'
import { SegmentEvent } from '@segment/actions-core'
const testDestination = createTestIntegration(Destination)
@@ -285,7 +285,7 @@ describe('Mixpanel.trackPurchase', () => {
id: 'abc123',
distinct_id: 'abc123',
$device_id: 'anon-2134',
- $browser: 'Safari',
+ $browser: 'Mobile Safari',
$current_url: 'https://segment.com/academy/',
$insert_id: '112c2a3c-7242-4327-9090-48a89de6a4110',
$lib_version: '2.11.1',
@@ -337,7 +337,7 @@ describe('Mixpanel.trackPurchase', () => {
id: 'abc123',
distinct_id: 'abc123',
$device_id: 'anon-2134',
- $browser: 'Safari',
+ $browser: 'Mobile Safari',
$current_url: 'https://segment.com/academy/',
$insert_id: '0112c2a3c-7242-4327-9090-48a89de6a4110',
$lib_version: '2.11.1',
@@ -369,7 +369,7 @@ describe('Mixpanel.trackPurchase', () => {
id: 'abc123',
distinct_id: 'abc123',
$device_id: 'anon-2134',
- $browser: 'Safari',
+ $browser: 'Mobile Safari',
$current_url: 'https://segment.com/academy/',
$insert_id: '1112c2a3c-7242-4327-9090-48a89de6a4110',
$lib_version: '2.11.1',
@@ -407,7 +407,7 @@ describe('Mixpanel.trackPurchase', () => {
expect(responses.length).toBe(1)
expect(responses[0].status).toBe(200)
expect(responses[0].options.body).toMatchInlineSnapshot(
- `"[{\\"event\\":\\"Order Completed\\",\\"properties\\":{\\"time\\":1629213675449,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"affiliation\\":\\"Super Online Store\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"coupon\\":\\"Mixpanel Day\\",\\"currency\\":\\"USD\\",\\"products\\":[{\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"price\\":19,\\"position\\":1,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"brand\\":\\"Unknown\\",\\"category\\":\\"Games\\",\\"variant\\":\\"Black\\",\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"},{\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2,\\"category\\":\\"Games\\",\\"custom\\":\\"xyz\\"}],\\"revenue\\":5.99,\\"shipping\\":1.5,\\"tax\\":3,\\"total\\":24.48}}]"`
+ `"[{\\"event\\":\\"Order Completed\\",\\"properties\\":{\\"time\\":1629213675449,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Mobile Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"affiliation\\":\\"Super Online Store\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"coupon\\":\\"Mixpanel Day\\",\\"currency\\":\\"USD\\",\\"products\\":[{\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"price\\":19,\\"position\\":1,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"brand\\":\\"Unknown\\",\\"category\\":\\"Games\\",\\"variant\\":\\"Black\\",\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"},{\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2,\\"category\\":\\"Games\\",\\"custom\\":\\"xyz\\"}],\\"revenue\\":5.99,\\"shipping\\":1.5,\\"tax\\":3,\\"total\\":24.48}}]"`
)
})
@@ -424,7 +424,7 @@ describe('Mixpanel.trackPurchase', () => {
expect(responses.length).toBe(1)
expect(responses[0].status).toBe(200)
expect(responses[0].options.body).toMatchInlineSnapshot(
- `"[{\\"event\\":\\"Order Completed\\",\\"properties\\":{\\"time\\":1629213675449,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"affiliation\\":\\"Super Online Store\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"coupon\\":\\"Mixpanel Day\\",\\"currency\\":\\"USD\\",\\"products\\":[{\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"price\\":19,\\"position\\":1,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"brand\\":\\"Unknown\\",\\"category\\":\\"Games\\",\\"variant\\":\\"Black\\",\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"},{\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2,\\"category\\":\\"Games\\",\\"custom\\":\\"xyz\\"}],\\"revenue\\":5.99,\\"shipping\\":1.5,\\"tax\\":3,\\"total\\":24.48}},{\\"event\\":\\"Product Purchased\\",\\"properties\\":{\\"time\\":1629213675448,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"0112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"category\\":\\"Games\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"brand\\":\\"Unknown\\",\\"variant\\":\\"Black\\",\\"price\\":19,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"position\\":1,\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"}},{\\"event\\":\\"Product Purchased\\",\\"properties\\":{\\"time\\":1629213675447,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"1112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"category\\":\\"Games\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2}}]"`
+ `"[{\\"event\\":\\"Order Completed\\",\\"properties\\":{\\"time\\":1629213675449,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Mobile Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"affiliation\\":\\"Super Online Store\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"coupon\\":\\"Mixpanel Day\\",\\"currency\\":\\"USD\\",\\"products\\":[{\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"price\\":19,\\"position\\":1,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"brand\\":\\"Unknown\\",\\"category\\":\\"Games\\",\\"variant\\":\\"Black\\",\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"},{\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2,\\"category\\":\\"Games\\",\\"custom\\":\\"xyz\\"}],\\"revenue\\":5.99,\\"shipping\\":1.5,\\"tax\\":3,\\"total\\":24.48}},{\\"event\\":\\"Product Purchased\\",\\"properties\\":{\\"time\\":1629213675448,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Mobile Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"0112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"product_id\\":\\"507f1f77bcf86cd799439011\\",\\"sku\\":\\"45790-32\\",\\"category\\":\\"Games\\",\\"name\\":\\"Monopoly: 3rd Edition\\",\\"brand\\":\\"Unknown\\",\\"variant\\":\\"Black\\",\\"price\\":19,\\"quantity\\":2,\\"coupon\\":\\"MOUNTAIN\\",\\"position\\":1,\\"url\\":\\"https://www.example.com/product/path\\",\\"image_url\\":\\"https://www.example.com/product/path.jpg\\"}},{\\"event\\":\\"Product Purchased\\",\\"properties\\":{\\"time\\":1629213675447,\\"ip\\":\\"8.8.8.8\\",\\"id\\":\\"abc123\\",\\"$anon_id\\":\\"anon-2134\\",\\"distinct_id\\":\\"abc123\\",\\"$browser\\":\\"Mobile Safari\\",\\"$browser_version\\":\\"9.0\\",\\"$current_url\\":\\"https://segment.com/academy/\\",\\"$device_id\\":\\"anon-2134\\",\\"$identified_id\\":\\"abc123\\",\\"$insert_id\\":\\"1112c2a3c-7242-4327-9090-48a89de6a4110\\",\\"$lib_version\\":\\"2.11.1\\",\\"$locale\\":\\"en-US\\",\\"$source\\":\\"segment\\",\\"$user_id\\":\\"abc123\\",\\"mp_country_code\\":\\"United States\\",\\"mp_lib\\":\\"Segment Actions: analytics.js\\",\\"timezone\\":\\"Europe/Amsterdam\\",\\"event_original_name\\":\\"Order Completed\\",\\"order_id\\":\\"order-id-123\\",\\"checkout_id\\":\\"checkout-id-123\\",\\"product_id\\":\\"505bd76785ebb509fc183733\\",\\"sku\\":\\"46493-32\\",\\"category\\":\\"Games\\",\\"name\\":\\"Uno Card Game\\",\\"price\\":3,\\"position\\":2}}]"`
)
})
})
diff --git a/packages/destination-actions/src/destinations/mixpanel/trackPurchase/index.ts b/packages/destination-actions/src/destinations/mixpanel/trackPurchase/index.ts
index 8d7831c411..f2564b8923 100644
--- a/packages/destination-actions/src/destinations/mixpanel/trackPurchase/index.ts
+++ b/packages/destination-actions/src/destinations/mixpanel/trackPurchase/index.ts
@@ -2,7 +2,7 @@ import { ActionDefinition, RequestClient, omit } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { MixpanelEvent } from '../mixpanel-types'
-import { getApiServerUrl, cheapGuid } from '../utils'
+import { getApiServerUrl, cheapGuid } from '../common/utils'
import { getEventProperties } from '../trackEvent/functions'
import { eventProperties, productsProperties } from '../mixpanel-properties'
import dayjs from '../../../lib/dayjs'
@@ -51,11 +51,11 @@ const getPurchaseEventsFromPayload = (payload: Payload, settings: Settings): Mix
const processData = async (request: RequestClient, settings: Settings, payload: Payload[]) => {
const events = payload.map((value) => getPurchaseEventsFromPayload(value, settings)).flat()
- return request(`${ getApiServerUrl(settings.apiRegion) }/import?strict=${ settings.strictMode ?? `1` }`, {
+ return request(`${getApiServerUrl(settings.apiRegion)}/import?strict=${settings.strictMode ?? `1`}`, {
method: 'post',
json: events,
headers: {
- authorization: `Basic ${ Buffer.from(`${ settings.apiSecret }:`).toString('base64') }`
+ authorization: `Basic ${Buffer.from(`${settings.apiSecret}:`).toString('base64')}`
}
})
}
From 5feda9bd7f0c27ae3a270e2b320d942ff7f9b66e Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 17:16:51 +0200
Subject: [PATCH 046/389] Registering Kameleoon integration
---
packages/destination-actions/src/destinations/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index 335c13c8f5..5cbdc916aa 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -132,6 +132,7 @@ register('650bdf1a62fb34ef0a8058e1', './klaviyo')
register('6512d7f86bdccc3829fc4ac3', './optimizely-data-platform')
register('651c1db19de92d8e595ff55d', './hyperengage')
register('65256052ac030f823df6c1a5', './trackey')
+register('652ea51a327a62b351aa12c0', './kameleoon')
function register(id: MetadataId, destinationPath: string) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
From 556910aa6f4f464eede00a2ecf1e59d05e28e7f9 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 16:31:44 +0100
Subject: [PATCH 047/389] Publish
- @segment/actions-shared@1.66.0
- @segment/browser-destination-runtime@1.15.0
- @segment/actions-core@3.84.0
- @segment/action-destinations@3.222.0
- @segment/destination-subscriptions@3.29.0
- @segment/destinations-manifest@1.24.0
- @segment/analytics-browser-actions-adobe-target@1.16.0
- @segment/analytics-browser-actions-amplitude-plugins@1.16.0
- @segment/analytics-browser-actions-braze-cloud-plugins@1.19.0
- @segment/analytics-browser-actions-braze@1.19.0
- @segment/analytics-browser-actions-cdpresolution@1.3.0
- @segment/analytics-browser-actions-commandbar@1.16.0
- @segment/analytics-browser-actions-devrev@1.3.0
- @segment/analytics-browser-actions-friendbuy@1.16.0
- @segment/analytics-browser-actions-fullstory@1.17.0
- @segment/analytics-browser-actions-google-analytics-4@1.20.0
- @segment/analytics-browser-actions-google-campaign-manager@1.6.0
- @segment/analytics-browser-actions-heap@1.16.0
- @segment/analytics-browser-hubble-web@1.2.0
- @segment/analytics-browser-actions-hubspot@1.16.0
- @segment/analytics-browser-actions-intercom@1.16.0
- @segment/analytics-browser-actions-iterate@1.16.0
- @segment/analytics-browser-actions-jimo@1.1.0
- @segment/analytics-browser-actions-koala@1.16.0
- @segment/analytics-browser-actions-logrocket@1.16.0
- @segment/analytics-browser-actions-pendo-web-actions@1.4.0
- @segment/analytics-browser-actions-playerzero@1.16.0
- @segment/analytics-browser-actions-ripe@1.16.0
- @segment/analytics-browser-actions-rupt@1.5.0
- @segment/analytics-browser-actions-screeb@1.16.0
- @segment/analytics-browser-actions-utils@1.16.0
- @segment/analytics-browser-actions-sprig@1.16.0
- @segment/analytics-browser-actions-stackadapt@1.16.0
- @segment/analytics-browser-actions-tiktok-pixel@1.13.0
- @segment/analytics-browser-actions-upollo@1.16.0
- @segment/analytics-browser-actions-userpilot@1.16.0
- @segment/analytics-browser-actions-vwo@1.17.0
- @segment/analytics-browser-actions-wiseops@1.16.0
---
packages/actions-shared/package.json | 4 +-
.../browser-destination-runtime/package.json | 4 +-
.../destinations/adobe-target/package.json | 4 +-
.../amplitude-plugins/package.json | 4 +-
.../braze-cloud-plugins/package.json | 6 +-
.../destinations/braze/package.json | 6 +-
.../destinations/cdpresolution/package.json | 4 +-
.../destinations/commandbar/package.json | 6 +-
.../destinations/devrev/package.json | 4 +-
.../destinations/friendbuy/package.json | 8 +--
.../destinations/fullstory/package.json | 6 +-
.../google-analytics-4-web/package.json | 6 +-
.../google-campaign-manager/package.json | 4 +-
.../destinations/heap/package.json | 6 +-
.../destinations/hubble-web/package.json | 6 +-
.../destinations/hubspot-web/package.json | 6 +-
.../destinations/intercom/package.json | 8 +--
.../destinations/iterate/package.json | 6 +-
.../destinations/jimo/package.json | 5 +-
.../destinations/koala/package.json | 6 +-
.../destinations/logrocket/package.json | 6 +-
.../pendo-web-actions/package.json | 4 +-
.../destinations/playerzero-web/package.json | 6 +-
.../destinations/ripe/package.json | 6 +-
.../destinations/rupt/package.json | 6 +-
.../destinations/screeb/package.json | 6 +-
.../segment-utilities-web/package.json | 4 +-
.../destinations/sprig-web/package.json | 6 +-
.../destinations/stackadapt/package.json | 6 +-
.../destinations/tiktok-pixel/package.json | 6 +-
.../destinations/upollo/package.json | 6 +-
.../destinations/userpilot/package.json | 6 +-
.../destinations/vwo/package.json | 6 +-
.../destinations/wisepops/package.json | 6 +-
packages/core/package.json | 4 +-
packages/destination-actions/package.json | 6 +-
.../destination-subscriptions/package.json | 2 +-
packages/destinations-manifest/package.json | 64 +++++++++----------
38 files changed, 132 insertions(+), 133 deletions(-)
diff --git a/packages/actions-shared/package.json b/packages/actions-shared/package.json
index 1cf8cd6f70..7f47b06e70 100644
--- a/packages/actions-shared/package.json
+++ b/packages/actions-shared/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-shared",
"description": "Shared destination action methods and definitions.",
- "version": "1.65.0",
+ "version": "1.66.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -37,7 +37,7 @@
},
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
- "@segment/actions-core": "^3.83.0",
+ "@segment/actions-core": "^3.84.0",
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
"escape-goat": "^3",
diff --git a/packages/browser-destination-runtime/package.json b/packages/browser-destination-runtime/package.json
index d48a2f58ee..b469454709 100644
--- a/packages/browser-destination-runtime/package.json
+++ b/packages/browser-destination-runtime/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/browser-destination-runtime",
- "version": "1.14.0",
+ "version": "1.15.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -62,7 +62,7 @@
}
},
"dependencies": {
- "@segment/actions-core": "^3.83.0"
+ "@segment/actions-core": "^3.84.0"
},
"devDependencies": {
"@segment/analytics-next": "*"
diff --git a/packages/browser-destinations/destinations/adobe-target/package.json b/packages/browser-destinations/destinations/adobe-target/package.json
index 78b0f2144f..599bdd839d 100644
--- a/packages/browser-destinations/destinations/adobe-target/package.json
+++ b/packages/browser-destinations/destinations/adobe-target/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-adobe-target",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,7 +16,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/amplitude-plugins/package.json b/packages/browser-destinations/destinations/amplitude-plugins/package.json
index 5090f61975..a0f9f36868 100644
--- a/packages/browser-destinations/destinations/amplitude-plugins/package.json
+++ b/packages/browser-destinations/destinations/amplitude-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-amplitude-plugins",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
index 63cc0d9550..e7b860d812 100644
--- a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
+++ b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze-cloud-plugins",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/analytics-browser-actions-braze": "^1.18.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/analytics-browser-actions-braze": "^1.19.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze/package.json b/packages/browser-destinations/destinations/braze/package.json
index 4aec1bcfc0..37704d5ed0 100644
--- a/packages/browser-destinations/destinations/braze/package.json
+++ b/packages/browser-destinations/destinations/braze/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -35,8 +35,8 @@
"dependencies": {
"@braze/web-sdk": "npm:@braze/web-sdk@^4.1.0",
"@braze/web-sdk-v3": "npm:@braze/web-sdk@^3.5.1",
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/cdpresolution/package.json b/packages/browser-destinations/destinations/cdpresolution/package.json
index a47bef769e..33a8550675 100644
--- a/packages/browser-destinations/destinations/cdpresolution/package.json
+++ b/packages/browser-destinations/destinations/cdpresolution/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-cdpresolution",
- "version": "1.2.0",
+ "version": "1.3.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/commandbar/package.json b/packages/browser-destinations/destinations/commandbar/package.json
index 45394db32c..4d93f6b286 100644
--- a/packages/browser-destinations/destinations/commandbar/package.json
+++ b/packages/browser-destinations/destinations/commandbar/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-commandbar",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/devrev/package.json b/packages/browser-destinations/destinations/devrev/package.json
index d834e446b1..650007e90c 100644
--- a/packages/browser-destinations/destinations/devrev/package.json
+++ b/packages/browser-destinations/destinations/devrev/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-devrev",
- "version": "1.2.0",
+ "version": "1.3.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/friendbuy/package.json b/packages/browser-destinations/destinations/friendbuy/package.json
index 94f6853bb6..f10c6292e0 100644
--- a/packages/browser-destinations/destinations/friendbuy/package.json
+++ b/packages/browser-destinations/destinations/friendbuy/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-friendbuy",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/actions-shared": "^1.65.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/actions-shared": "^1.66.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/fullstory/package.json b/packages/browser-destinations/destinations/fullstory/package.json
index 53a147afa9..5af981ea04 100644
--- a/packages/browser-destinations/destinations/fullstory/package.json
+++ b/packages/browser-destinations/destinations/fullstory/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-fullstory",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,8 +16,8 @@
"typings": "./dist/esm",
"dependencies": {
"@fullstory/browser": "^1.4.9",
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-analytics-4-web/package.json b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
index 1f3bca6926..ec5c7778b9 100644
--- a/packages/browser-destinations/destinations/google-analytics-4-web/package.json
+++ b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-analytics-4",
- "version": "1.19.0",
+ "version": "1.20.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-campaign-manager/package.json b/packages/browser-destinations/destinations/google-campaign-manager/package.json
index fb15e83df2..d70fb50da5 100644
--- a/packages/browser-destinations/destinations/google-campaign-manager/package.json
+++ b/packages/browser-destinations/destinations/google-campaign-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-campaign-manager",
- "version": "1.5.0",
+ "version": "1.6.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/heap/package.json b/packages/browser-destinations/destinations/heap/package.json
index b0a57ed43d..475bd51d0e 100644
--- a/packages/browser-destinations/destinations/heap/package.json
+++ b/packages/browser-destinations/destinations/heap/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-heap",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubble-web/package.json b/packages/browser-destinations/destinations/hubble-web/package.json
index 73641f6d06..ebf13a78fb 100644
--- a/packages/browser-destinations/destinations/hubble-web/package.json
+++ b/packages/browser-destinations/destinations/hubble-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-hubble-web",
- "version": "1.1.0",
+ "version": "1.2.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.4.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubspot-web/package.json b/packages/browser-destinations/destinations/hubspot-web/package.json
index c8342cebb0..598adb37a8 100644
--- a/packages/browser-destinations/destinations/hubspot-web/package.json
+++ b/packages/browser-destinations/destinations/hubspot-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-hubspot",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/intercom/package.json b/packages/browser-destinations/destinations/intercom/package.json
index b8420e4ff9..13efedfc87 100644
--- a/packages/browser-destinations/destinations/intercom/package.json
+++ b/packages/browser-destinations/destinations/intercom/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-intercom",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/actions-shared": "^1.65.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/actions-shared": "^1.66.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/iterate/package.json b/packages/browser-destinations/destinations/iterate/package.json
index fd2254f2dd..e008f62b67 100644
--- a/packages/browser-destinations/destinations/iterate/package.json
+++ b/packages/browser-destinations/destinations/iterate/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-iterate",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 9081190cf9..315a84510b 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-jimo",
- "version": "1.0.0",
+ "version": "1.1.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
-
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/koala/package.json b/packages/browser-destinations/destinations/koala/package.json
index 30ea2eaf20..7d4852ef27 100644
--- a/packages/browser-destinations/destinations/koala/package.json
+++ b/packages/browser-destinations/destinations/koala/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-koala",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/logrocket/package.json b/packages/browser-destinations/destinations/logrocket/package.json
index 72b47c5061..b401b179e4 100644
--- a/packages/browser-destinations/destinations/logrocket/package.json
+++ b/packages/browser-destinations/destinations/logrocket/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-logrocket",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0",
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0",
"logrocket": "^3.0.1"
},
"peerDependencies": {
diff --git a/packages/browser-destinations/destinations/pendo-web-actions/package.json b/packages/browser-destinations/destinations/pendo-web-actions/package.json
index 2a5bca0b2a..c27446d85a 100644
--- a/packages/browser-destinations/destinations/pendo-web-actions/package.json
+++ b/packages/browser-destinations/destinations/pendo-web-actions/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-pendo-web-actions",
- "version": "1.3.0",
+ "version": "1.4.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/playerzero-web/package.json b/packages/browser-destinations/destinations/playerzero-web/package.json
index e9f55a9ebc..6c1f4e69ed 100644
--- a/packages/browser-destinations/destinations/playerzero-web/package.json
+++ b/packages/browser-destinations/destinations/playerzero-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-playerzero",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/ripe/package.json b/packages/browser-destinations/destinations/ripe/package.json
index de56a05def..9374a556b4 100644
--- a/packages/browser-destinations/destinations/ripe/package.json
+++ b/packages/browser-destinations/destinations/ripe/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-ripe",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/rupt/package.json b/packages/browser-destinations/destinations/rupt/package.json
index e4c2b59b53..f68a593530 100644
--- a/packages/browser-destinations/destinations/rupt/package.json
+++ b/packages/browser-destinations/destinations/rupt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-rupt",
- "version": "1.4.0",
+ "version": "1.5.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/screeb/package.json b/packages/browser-destinations/destinations/screeb/package.json
index 92787ef5ae..6dc468cfa2 100644
--- a/packages/browser-destinations/destinations/screeb/package.json
+++ b/packages/browser-destinations/destinations/screeb/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-screeb",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/segment-utilities-web/package.json b/packages/browser-destinations/destinations/segment-utilities-web/package.json
index 4aa8d99d71..ab8674d7fa 100644
--- a/packages/browser-destinations/destinations/segment-utilities-web/package.json
+++ b/packages/browser-destinations/destinations/segment-utilities-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-utils",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/sprig-web/package.json b/packages/browser-destinations/destinations/sprig-web/package.json
index 1a44035571..4a502b2693 100644
--- a/packages/browser-destinations/destinations/sprig-web/package.json
+++ b/packages/browser-destinations/destinations/sprig-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-sprig",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/stackadapt/package.json b/packages/browser-destinations/destinations/stackadapt/package.json
index 9c9932b17d..f04308043a 100644
--- a/packages/browser-destinations/destinations/stackadapt/package.json
+++ b/packages/browser-destinations/destinations/stackadapt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-stackadapt",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/package.json b/packages/browser-destinations/destinations/tiktok-pixel/package.json
index 4fd4c064d8..4f89e65576 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/package.json
+++ b/packages/browser-destinations/destinations/tiktok-pixel/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-tiktok-pixel",
- "version": "1.12.0",
+ "version": "1.13.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/upollo/package.json b/packages/browser-destinations/destinations/upollo/package.json
index 8592d59b9e..0a11df2541 100644
--- a/packages/browser-destinations/destinations/upollo/package.json
+++ b/packages/browser-destinations/destinations/upollo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-upollo",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/userpilot/package.json b/packages/browser-destinations/destinations/userpilot/package.json
index ba33314c80..01a241bf61 100644
--- a/packages/browser-destinations/destinations/userpilot/package.json
+++ b/packages/browser-destinations/destinations/userpilot/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-userpilot",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/vwo/package.json b/packages/browser-destinations/destinations/vwo/package.json
index d7914cffdd..12fcb39a42 100644
--- a/packages/browser-destinations/destinations/vwo/package.json
+++ b/packages/browser-destinations/destinations/vwo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-vwo",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/wisepops/package.json b/packages/browser-destinations/destinations/wisepops/package.json
index ff7ed4f1fc..5cad6b24a6 100644
--- a/packages/browser-destinations/destinations/wisepops/package.json
+++ b/packages/browser-destinations/destinations/wisepops/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-wiseops",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.83.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/actions-core": "^3.84.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/core/package.json b/packages/core/package.json
index 9b6eccbbc5..b01c84b998 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-core",
"description": "Core runtime for Destinations Actions.",
- "version": "3.83.0",
+ "version": "3.84.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/fab-5-engine",
@@ -82,7 +82,7 @@
"@lukeed/uuid": "^2.0.0",
"@segment/action-emitters": "^1.1.2",
"@segment/ajv-human-errors": "^2.11.3",
- "@segment/destination-subscriptions": "^3.28.3",
+ "@segment/destination-subscriptions": "^3.29.0",
"@types/node": "^18.11.15",
"abort-controller": "^3.0.0",
"aggregate-error": "^3.1.0",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 49c77ba175..71188c1026 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.221.0",
+ "version": "3.222.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -40,8 +40,8 @@
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
"@segment/a1-notation": "^2.1.4",
- "@segment/actions-core": "^3.83.0",
- "@segment/actions-shared": "^1.65.0",
+ "@segment/actions-core": "^3.84.0",
+ "@segment/actions-shared": "^1.66.0",
"@types/node": "^18.11.15",
"ajv-formats": "^2.1.1",
"aws4": "^1.12.0",
diff --git a/packages/destination-subscriptions/package.json b/packages/destination-subscriptions/package.json
index 38c20ab368..4b3993e185 100644
--- a/packages/destination-subscriptions/package.json
+++ b/packages/destination-subscriptions/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destination-subscriptions",
- "version": "3.28.3",
+ "version": "3.29.0",
"description": "Validate event payload using subscription AST",
"license": "MIT",
"repository": {
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index 9fcd425a04..72fae94baa 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destinations-manifest",
- "version": "1.23.0",
+ "version": "1.24.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
@@ -12,37 +12,37 @@
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
"dependencies": {
- "@segment/analytics-browser-actions-adobe-target": "^1.15.0",
- "@segment/analytics-browser-actions-amplitude-plugins": "^1.15.0",
- "@segment/analytics-browser-actions-braze": "^1.18.0",
- "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.18.0",
- "@segment/analytics-browser-actions-cdpresolution": "^1.2.0",
- "@segment/analytics-browser-actions-commandbar": "^1.15.0",
- "@segment/analytics-browser-actions-devrev": "^1.2.0",
- "@segment/analytics-browser-actions-friendbuy": "^1.15.0",
- "@segment/analytics-browser-actions-fullstory": "^1.16.0",
- "@segment/analytics-browser-actions-google-analytics-4": "^1.19.0",
- "@segment/analytics-browser-actions-google-campaign-manager": "^1.5.0",
- "@segment/analytics-browser-actions-heap": "^1.15.0",
- "@segment/analytics-browser-actions-hubspot": "^1.15.0",
- "@segment/analytics-browser-actions-intercom": "^1.15.0",
- "@segment/analytics-browser-actions-iterate": "^1.15.0",
- "@segment/analytics-browser-actions-koala": "^1.15.0",
- "@segment/analytics-browser-actions-logrocket": "^1.15.0",
- "@segment/analytics-browser-actions-pendo-web-actions": "^1.3.0",
- "@segment/analytics-browser-actions-playerzero": "^1.15.0",
- "@segment/analytics-browser-actions-ripe": "^1.15.0",
+ "@segment/analytics-browser-actions-adobe-target": "^1.16.0",
+ "@segment/analytics-browser-actions-amplitude-plugins": "^1.16.0",
+ "@segment/analytics-browser-actions-braze": "^1.19.0",
+ "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.19.0",
+ "@segment/analytics-browser-actions-cdpresolution": "^1.3.0",
+ "@segment/analytics-browser-actions-commandbar": "^1.16.0",
+ "@segment/analytics-browser-actions-devrev": "^1.3.0",
+ "@segment/analytics-browser-actions-friendbuy": "^1.16.0",
+ "@segment/analytics-browser-actions-fullstory": "^1.17.0",
+ "@segment/analytics-browser-actions-google-analytics-4": "^1.20.0",
+ "@segment/analytics-browser-actions-google-campaign-manager": "^1.6.0",
+ "@segment/analytics-browser-actions-heap": "^1.16.0",
+ "@segment/analytics-browser-actions-hubspot": "^1.16.0",
+ "@segment/analytics-browser-actions-intercom": "^1.16.0",
+ "@segment/analytics-browser-actions-iterate": "^1.16.0",
+ "@segment/analytics-browser-actions-koala": "^1.16.0",
+ "@segment/analytics-browser-actions-logrocket": "^1.16.0",
+ "@segment/analytics-browser-actions-pendo-web-actions": "^1.4.0",
+ "@segment/analytics-browser-actions-playerzero": "^1.16.0",
+ "@segment/analytics-browser-actions-ripe": "^1.16.0",
"@segment/analytics-browser-actions-sabil": "^1.6.0",
- "@segment/analytics-browser-actions-screeb": "^1.15.0",
- "@segment/analytics-browser-actions-sprig": "^1.15.0",
- "@segment/analytics-browser-actions-stackadapt": "^1.15.0",
- "@segment/analytics-browser-actions-tiktok-pixel": "^1.11.0",
- "@segment/analytics-browser-actions-upollo": "^1.15.0",
- "@segment/analytics-browser-actions-userpilot": "^1.15.0",
- "@segment/analytics-browser-actions-utils": "^1.15.0",
- "@segment/analytics-browser-actions-vwo": "^1.16.0",
- "@segment/analytics-browser-actions-wiseops": "^1.15.0",
- "@segment/analytics-browser-hubble-web": "^1.1.0",
- "@segment/browser-destination-runtime": "^1.14.0"
+ "@segment/analytics-browser-actions-screeb": "^1.16.0",
+ "@segment/analytics-browser-actions-sprig": "^1.16.0",
+ "@segment/analytics-browser-actions-stackadapt": "^1.16.0",
+ "@segment/analytics-browser-actions-tiktok-pixel": "^1.13.0",
+ "@segment/analytics-browser-actions-upollo": "^1.16.0",
+ "@segment/analytics-browser-actions-userpilot": "^1.16.0",
+ "@segment/analytics-browser-actions-utils": "^1.16.0",
+ "@segment/analytics-browser-actions-vwo": "^1.17.0",
+ "@segment/analytics-browser-actions-wiseops": "^1.16.0",
+ "@segment/analytics-browser-hubble-web": "^1.2.0",
+ "@segment/browser-destination-runtime": "^1.15.0"
}
}
From ad472eb2a9dce64499e1c5e7a44126d5ad254154 Mon Sep 17 00:00:00 2001
From: Varadarajan V <109586712+varadarajan-tw@users.noreply.github.com>
Date: Tue, 17 Oct 2023 21:14:41 +0530
Subject: [PATCH 048/389] [Jimo][Segment Profiles] Add missing generated types
(#1664)
---
.../destinations/jimo/src/generated-types.ts | 4 ++--
.../jimo/src/sendUserData/generated-types.ts | 2 +-
.../sendSubscription/generated-types.ts | 12 ++++++------
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/packages/browser-destinations/destinations/jimo/src/generated-types.ts b/packages/browser-destinations/destinations/jimo/src/generated-types.ts
index 77cee2434b..9809f5f4d1 100644
--- a/packages/browser-destinations/destinations/jimo/src/generated-types.ts
+++ b/packages/browser-destinations/destinations/jimo/src/generated-types.ts
@@ -2,11 +2,11 @@
export interface Settings {
/**
- * Id of the Jimo project. You can find it here: https://i.usejimo.com/settings/install/portal
+ * Id of the Jimo project. You can find the Project Id here: https://i.usejimo.com/settings/install/portal
*/
projectId: string
/**
- * Make sure Jimo is not initialized automatically after being added to your website. For more information, check out: https://help.usejimo.com/knowledge-base/for-developers/sdk-guides/manual-initialization
+ * Toggling to true will prevent Jimo from initializing automatically. For more information, check out: https://help.usejimo.com/knowledge-base/for-developers/sdk-guides/manual-initialization
*/
manualInit?: boolean
}
diff --git a/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts b/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
index 644f265bc6..fe84a55690 100644
--- a/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
+++ b/packages/browser-destinations/destinations/jimo/src/sendUserData/generated-types.ts
@@ -2,7 +2,7 @@
export interface Payload {
/**
- * The users's id provided by segment
+ * The unique user identifier
*/
userId?: string | null
/**
diff --git a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
index f3863b13d8..0e89615675 100644
--- a/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
+++ b/packages/destination-actions/src/destinations/segment-profiles/sendSubscription/generated-types.ts
@@ -18,11 +18,11 @@ export interface Payload {
*/
email?: string
/**
- * Global status of the email subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Global status of the email subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
email_subscription_status?: string | null
/**
- * Subscription status for the groups. Object containing group names as keys and statuses as values. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Group Subscription statuses are supported for the email channel. This object contains group names as keys and statuses as values. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
subscription_groups?: {
[k: string]: unknown
@@ -32,11 +32,11 @@ export interface Payload {
*/
phone?: string
/**
- * Global status of the SMS subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Global status of the SMS subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
sms_subscription_status?: string | null
/**
- * Global status of the WhatsApp subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Global status of the WhatsApp subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
whatsapp_subscription_status?: string | null
/**
@@ -44,7 +44,7 @@ export interface Payload {
*/
android_push_token?: string
/**
- * Global status of the android push subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Global status of the android push subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
android_push_subscription_status?: string | null
/**
@@ -52,7 +52,7 @@ export interface Payload {
*/
ios_push_token?: string
/**
- * Global status of the ios push subscription. True is subscribed, false is unsubscribed and did-not-subscribe is did-not-subscribe.
+ * Global status of the ios push subscription. True is subscribed, false is unsubscribed, and did_not_subscribe is did_not_subscribe.
*/
ios_push_subscription_status?: string | null
/**
From dad2713403d1bd8cbf4cef68c48a07069b1282eb Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 16:45:41 +0100
Subject: [PATCH 049/389] Publish
- @segment/action-destinations@3.223.0
- @segment/analytics-browser-actions-jimo@1.2.0
---
packages/browser-destinations/destinations/jimo/package.json | 2 +-
packages/destination-actions/package.json | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 315a84510b..633f1d6ead 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-jimo",
- "version": "1.1.0",
+ "version": "1.2.0",
"license": "MIT",
"publishConfig": {
"access": "public",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index 71188c1026..aa97fb3015 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.222.0",
+ "version": "3.223.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
From 9faf896690611794819af69b1ffd7bcfcd0f4a08 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 17:47:53 +0200
Subject: [PATCH 050/389] Committing change to core to force new Publish
---
packages/core/src/errors.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/core/src/errors.ts b/packages/core/src/errors.ts
index 07638a9c16..b9ea1b8c93 100644
--- a/packages/core/src/errors.ts
+++ b/packages/core/src/errors.ts
@@ -13,7 +13,7 @@ export class IntegrationError extends CustomError {
/**
* @param message - a human-friendly message to display to users
* @param code - error code/reason
- * @param status - http status code (e.g. 400).
+ * @param status - http status code (e.g. 400)
* - 4xx errors are not automatically retried, except for 408, 423, 429
* - 5xx are automatically retried, except for 501
*/
From 784dd2d6f1d4d871361217add07929fd49c45b5a Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 16:48:39 +0100
Subject: [PATCH 051/389] Publish
- @segment/actions-shared@1.67.0
- @segment/browser-destination-runtime@1.16.0
- @segment/actions-core@3.85.0
- @segment/action-destinations@3.224.0
- @segment/destinations-manifest@1.25.0
- @segment/analytics-browser-actions-adobe-target@1.17.0
- @segment/analytics-browser-actions-amplitude-plugins@1.17.0
- @segment/analytics-browser-actions-braze-cloud-plugins@1.20.0
- @segment/analytics-browser-actions-braze@1.20.0
- @segment/analytics-browser-actions-cdpresolution@1.4.0
- @segment/analytics-browser-actions-commandbar@1.17.0
- @segment/analytics-browser-actions-devrev@1.4.0
- @segment/analytics-browser-actions-friendbuy@1.17.0
- @segment/analytics-browser-actions-fullstory@1.18.0
- @segment/analytics-browser-actions-google-analytics-4@1.21.0
- @segment/analytics-browser-actions-google-campaign-manager@1.7.0
- @segment/analytics-browser-actions-heap@1.17.0
- @segment/analytics-browser-hubble-web@1.3.0
- @segment/analytics-browser-actions-hubspot@1.17.0
- @segment/analytics-browser-actions-intercom@1.17.0
- @segment/analytics-browser-actions-iterate@1.17.0
- @segment/analytics-browser-actions-jimo@1.3.0
- @segment/analytics-browser-actions-koala@1.17.0
- @segment/analytics-browser-actions-logrocket@1.17.0
- @segment/analytics-browser-actions-pendo-web-actions@1.5.0
- @segment/analytics-browser-actions-playerzero@1.17.0
- @segment/analytics-browser-actions-ripe@1.17.0
- @segment/analytics-browser-actions-rupt@1.6.0
- @segment/analytics-browser-actions-screeb@1.17.0
- @segment/analytics-browser-actions-utils@1.17.0
- @segment/analytics-browser-actions-sprig@1.17.0
- @segment/analytics-browser-actions-stackadapt@1.17.0
- @segment/analytics-browser-actions-tiktok-pixel@1.14.0
- @segment/analytics-browser-actions-upollo@1.17.0
- @segment/analytics-browser-actions-userpilot@1.17.0
- @segment/analytics-browser-actions-vwo@1.18.0
- @segment/analytics-browser-actions-wiseops@1.17.0
---
packages/actions-shared/package.json | 4 +-
.../browser-destination-runtime/package.json | 4 +-
.../destinations/adobe-target/package.json | 4 +-
.../amplitude-plugins/package.json | 4 +-
.../braze-cloud-plugins/package.json | 6 +-
.../destinations/braze/package.json | 6 +-
.../destinations/cdpresolution/package.json | 4 +-
.../destinations/commandbar/package.json | 6 +-
.../destinations/devrev/package.json | 4 +-
.../destinations/friendbuy/package.json | 8 +--
.../destinations/fullstory/package.json | 6 +-
.../google-analytics-4-web/package.json | 6 +-
.../google-campaign-manager/package.json | 4 +-
.../destinations/heap/package.json | 6 +-
.../destinations/hubble-web/package.json | 6 +-
.../destinations/hubspot-web/package.json | 6 +-
.../destinations/intercom/package.json | 8 +--
.../destinations/iterate/package.json | 6 +-
.../destinations/jimo/package.json | 4 +-
.../destinations/koala/package.json | 6 +-
.../destinations/logrocket/package.json | 6 +-
.../pendo-web-actions/package.json | 4 +-
.../destinations/playerzero-web/package.json | 6 +-
.../destinations/ripe/package.json | 6 +-
.../destinations/rupt/package.json | 6 +-
.../destinations/screeb/package.json | 6 +-
.../segment-utilities-web/package.json | 4 +-
.../destinations/sprig-web/package.json | 6 +-
.../destinations/stackadapt/package.json | 6 +-
.../destinations/tiktok-pixel/package.json | 6 +-
.../destinations/upollo/package.json | 6 +-
.../destinations/userpilot/package.json | 6 +-
.../destinations/vwo/package.json | 6 +-
.../destinations/wisepops/package.json | 6 +-
packages/core/package.json | 2 +-
packages/destination-actions/package.json | 6 +-
packages/destinations-manifest/package.json | 64 +++++++++----------
37 files changed, 130 insertions(+), 130 deletions(-)
diff --git a/packages/actions-shared/package.json b/packages/actions-shared/package.json
index 7f47b06e70..9b9dc63b20 100644
--- a/packages/actions-shared/package.json
+++ b/packages/actions-shared/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-shared",
"description": "Shared destination action methods and definitions.",
- "version": "1.66.0",
+ "version": "1.67.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -37,7 +37,7 @@
},
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
- "@segment/actions-core": "^3.84.0",
+ "@segment/actions-core": "^3.85.0",
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
"escape-goat": "^3",
diff --git a/packages/browser-destination-runtime/package.json b/packages/browser-destination-runtime/package.json
index b469454709..78730483eb 100644
--- a/packages/browser-destination-runtime/package.json
+++ b/packages/browser-destination-runtime/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/browser-destination-runtime",
- "version": "1.15.0",
+ "version": "1.16.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -62,7 +62,7 @@
}
},
"dependencies": {
- "@segment/actions-core": "^3.84.0"
+ "@segment/actions-core": "^3.85.0"
},
"devDependencies": {
"@segment/analytics-next": "*"
diff --git a/packages/browser-destinations/destinations/adobe-target/package.json b/packages/browser-destinations/destinations/adobe-target/package.json
index 599bdd839d..8221e7ce09 100644
--- a/packages/browser-destinations/destinations/adobe-target/package.json
+++ b/packages/browser-destinations/destinations/adobe-target/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-adobe-target",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,7 +16,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/amplitude-plugins/package.json b/packages/browser-destinations/destinations/amplitude-plugins/package.json
index a0f9f36868..230a6eb673 100644
--- a/packages/browser-destinations/destinations/amplitude-plugins/package.json
+++ b/packages/browser-destinations/destinations/amplitude-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-amplitude-plugins",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
index e7b860d812..70d4b9018a 100644
--- a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
+++ b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze-cloud-plugins",
- "version": "1.19.0",
+ "version": "1.20.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/analytics-browser-actions-braze": "^1.19.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/analytics-browser-actions-braze": "^1.20.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze/package.json b/packages/browser-destinations/destinations/braze/package.json
index 37704d5ed0..8c94fde2e7 100644
--- a/packages/browser-destinations/destinations/braze/package.json
+++ b/packages/browser-destinations/destinations/braze/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze",
- "version": "1.19.0",
+ "version": "1.20.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -35,8 +35,8 @@
"dependencies": {
"@braze/web-sdk": "npm:@braze/web-sdk@^4.1.0",
"@braze/web-sdk-v3": "npm:@braze/web-sdk@^3.5.1",
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/cdpresolution/package.json b/packages/browser-destinations/destinations/cdpresolution/package.json
index 33a8550675..1ce7d15f78 100644
--- a/packages/browser-destinations/destinations/cdpresolution/package.json
+++ b/packages/browser-destinations/destinations/cdpresolution/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-cdpresolution",
- "version": "1.3.0",
+ "version": "1.4.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/commandbar/package.json b/packages/browser-destinations/destinations/commandbar/package.json
index 4d93f6b286..986dea4c9a 100644
--- a/packages/browser-destinations/destinations/commandbar/package.json
+++ b/packages/browser-destinations/destinations/commandbar/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-commandbar",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/devrev/package.json b/packages/browser-destinations/destinations/devrev/package.json
index 650007e90c..07882e7f30 100644
--- a/packages/browser-destinations/destinations/devrev/package.json
+++ b/packages/browser-destinations/destinations/devrev/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-devrev",
- "version": "1.3.0",
+ "version": "1.4.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/friendbuy/package.json b/packages/browser-destinations/destinations/friendbuy/package.json
index f10c6292e0..1f73444c66 100644
--- a/packages/browser-destinations/destinations/friendbuy/package.json
+++ b/packages/browser-destinations/destinations/friendbuy/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-friendbuy",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/actions-shared": "^1.66.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/actions-shared": "^1.67.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/fullstory/package.json b/packages/browser-destinations/destinations/fullstory/package.json
index 5af981ea04..7ba47de1f6 100644
--- a/packages/browser-destinations/destinations/fullstory/package.json
+++ b/packages/browser-destinations/destinations/fullstory/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-fullstory",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,8 +16,8 @@
"typings": "./dist/esm",
"dependencies": {
"@fullstory/browser": "^1.4.9",
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-analytics-4-web/package.json b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
index ec5c7778b9..b5a9c93549 100644
--- a/packages/browser-destinations/destinations/google-analytics-4-web/package.json
+++ b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-analytics-4",
- "version": "1.20.0",
+ "version": "1.21.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-campaign-manager/package.json b/packages/browser-destinations/destinations/google-campaign-manager/package.json
index d70fb50da5..d137088c5d 100644
--- a/packages/browser-destinations/destinations/google-campaign-manager/package.json
+++ b/packages/browser-destinations/destinations/google-campaign-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-campaign-manager",
- "version": "1.6.0",
+ "version": "1.7.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/heap/package.json b/packages/browser-destinations/destinations/heap/package.json
index 475bd51d0e..2d6880667b 100644
--- a/packages/browser-destinations/destinations/heap/package.json
+++ b/packages/browser-destinations/destinations/heap/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-heap",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubble-web/package.json b/packages/browser-destinations/destinations/hubble-web/package.json
index ebf13a78fb..de88530de1 100644
--- a/packages/browser-destinations/destinations/hubble-web/package.json
+++ b/packages/browser-destinations/destinations/hubble-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-hubble-web",
- "version": "1.2.0",
+ "version": "1.3.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubspot-web/package.json b/packages/browser-destinations/destinations/hubspot-web/package.json
index 598adb37a8..b191afa969 100644
--- a/packages/browser-destinations/destinations/hubspot-web/package.json
+++ b/packages/browser-destinations/destinations/hubspot-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-hubspot",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/intercom/package.json b/packages/browser-destinations/destinations/intercom/package.json
index 13efedfc87..ff51f987e8 100644
--- a/packages/browser-destinations/destinations/intercom/package.json
+++ b/packages/browser-destinations/destinations/intercom/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-intercom",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/actions-shared": "^1.66.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/actions-shared": "^1.67.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/iterate/package.json b/packages/browser-destinations/destinations/iterate/package.json
index e008f62b67..5645039ff2 100644
--- a/packages/browser-destinations/destinations/iterate/package.json
+++ b/packages/browser-destinations/destinations/iterate/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-iterate",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 633f1d6ead..98b692fd4b 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-jimo",
- "version": "1.2.0",
+ "version": "1.3.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/koala/package.json b/packages/browser-destinations/destinations/koala/package.json
index 7d4852ef27..eb3641367a 100644
--- a/packages/browser-destinations/destinations/koala/package.json
+++ b/packages/browser-destinations/destinations/koala/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-koala",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/logrocket/package.json b/packages/browser-destinations/destinations/logrocket/package.json
index b401b179e4..40e9cf2468 100644
--- a/packages/browser-destinations/destinations/logrocket/package.json
+++ b/packages/browser-destinations/destinations/logrocket/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-logrocket",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0",
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0",
"logrocket": "^3.0.1"
},
"peerDependencies": {
diff --git a/packages/browser-destinations/destinations/pendo-web-actions/package.json b/packages/browser-destinations/destinations/pendo-web-actions/package.json
index c27446d85a..2a72f8b4fb 100644
--- a/packages/browser-destinations/destinations/pendo-web-actions/package.json
+++ b/packages/browser-destinations/destinations/pendo-web-actions/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-pendo-web-actions",
- "version": "1.4.0",
+ "version": "1.5.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/playerzero-web/package.json b/packages/browser-destinations/destinations/playerzero-web/package.json
index 6c1f4e69ed..019d3b877f 100644
--- a/packages/browser-destinations/destinations/playerzero-web/package.json
+++ b/packages/browser-destinations/destinations/playerzero-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-playerzero",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/ripe/package.json b/packages/browser-destinations/destinations/ripe/package.json
index 9374a556b4..bcd5156b5c 100644
--- a/packages/browser-destinations/destinations/ripe/package.json
+++ b/packages/browser-destinations/destinations/ripe/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-ripe",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/rupt/package.json b/packages/browser-destinations/destinations/rupt/package.json
index f68a593530..8c45a53b82 100644
--- a/packages/browser-destinations/destinations/rupt/package.json
+++ b/packages/browser-destinations/destinations/rupt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-rupt",
- "version": "1.5.0",
+ "version": "1.6.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/screeb/package.json b/packages/browser-destinations/destinations/screeb/package.json
index 6dc468cfa2..4e22c6b011 100644
--- a/packages/browser-destinations/destinations/screeb/package.json
+++ b/packages/browser-destinations/destinations/screeb/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-screeb",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/segment-utilities-web/package.json b/packages/browser-destinations/destinations/segment-utilities-web/package.json
index ab8674d7fa..34157d501d 100644
--- a/packages/browser-destinations/destinations/segment-utilities-web/package.json
+++ b/packages/browser-destinations/destinations/segment-utilities-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-utils",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/sprig-web/package.json b/packages/browser-destinations/destinations/sprig-web/package.json
index 4a502b2693..239f5dc144 100644
--- a/packages/browser-destinations/destinations/sprig-web/package.json
+++ b/packages/browser-destinations/destinations/sprig-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-sprig",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/stackadapt/package.json b/packages/browser-destinations/destinations/stackadapt/package.json
index f04308043a..e0f55ae8c5 100644
--- a/packages/browser-destinations/destinations/stackadapt/package.json
+++ b/packages/browser-destinations/destinations/stackadapt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-stackadapt",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/package.json b/packages/browser-destinations/destinations/tiktok-pixel/package.json
index 4f89e65576..ed5edf6bc0 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/package.json
+++ b/packages/browser-destinations/destinations/tiktok-pixel/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-tiktok-pixel",
- "version": "1.13.0",
+ "version": "1.14.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/upollo/package.json b/packages/browser-destinations/destinations/upollo/package.json
index 0a11df2541..6ffd3c489a 100644
--- a/packages/browser-destinations/destinations/upollo/package.json
+++ b/packages/browser-destinations/destinations/upollo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-upollo",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/userpilot/package.json b/packages/browser-destinations/destinations/userpilot/package.json
index 01a241bf61..f889d1961e 100644
--- a/packages/browser-destinations/destinations/userpilot/package.json
+++ b/packages/browser-destinations/destinations/userpilot/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-userpilot",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/vwo/package.json b/packages/browser-destinations/destinations/vwo/package.json
index 12fcb39a42..ff1042c5c5 100644
--- a/packages/browser-destinations/destinations/vwo/package.json
+++ b/packages/browser-destinations/destinations/vwo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-vwo",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/wisepops/package.json b/packages/browser-destinations/destinations/wisepops/package.json
index 5cad6b24a6..b3e9590dc0 100644
--- a/packages/browser-destinations/destinations/wisepops/package.json
+++ b/packages/browser-destinations/destinations/wisepops/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-wiseops",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.84.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/actions-core": "^3.85.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/core/package.json b/packages/core/package.json
index b01c84b998..94493878a8 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-core",
"description": "Core runtime for Destinations Actions.",
- "version": "3.84.0",
+ "version": "3.85.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/fab-5-engine",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index aa97fb3015..b149e641b2 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.223.0",
+ "version": "3.224.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -40,8 +40,8 @@
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
"@segment/a1-notation": "^2.1.4",
- "@segment/actions-core": "^3.84.0",
- "@segment/actions-shared": "^1.66.0",
+ "@segment/actions-core": "^3.85.0",
+ "@segment/actions-shared": "^1.67.0",
"@types/node": "^18.11.15",
"ajv-formats": "^2.1.1",
"aws4": "^1.12.0",
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index 72fae94baa..6d12705295 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destinations-manifest",
- "version": "1.24.0",
+ "version": "1.25.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
@@ -12,37 +12,37 @@
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
"dependencies": {
- "@segment/analytics-browser-actions-adobe-target": "^1.16.0",
- "@segment/analytics-browser-actions-amplitude-plugins": "^1.16.0",
- "@segment/analytics-browser-actions-braze": "^1.19.0",
- "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.19.0",
- "@segment/analytics-browser-actions-cdpresolution": "^1.3.0",
- "@segment/analytics-browser-actions-commandbar": "^1.16.0",
- "@segment/analytics-browser-actions-devrev": "^1.3.0",
- "@segment/analytics-browser-actions-friendbuy": "^1.16.0",
- "@segment/analytics-browser-actions-fullstory": "^1.17.0",
- "@segment/analytics-browser-actions-google-analytics-4": "^1.20.0",
- "@segment/analytics-browser-actions-google-campaign-manager": "^1.6.0",
- "@segment/analytics-browser-actions-heap": "^1.16.0",
- "@segment/analytics-browser-actions-hubspot": "^1.16.0",
- "@segment/analytics-browser-actions-intercom": "^1.16.0",
- "@segment/analytics-browser-actions-iterate": "^1.16.0",
- "@segment/analytics-browser-actions-koala": "^1.16.0",
- "@segment/analytics-browser-actions-logrocket": "^1.16.0",
- "@segment/analytics-browser-actions-pendo-web-actions": "^1.4.0",
- "@segment/analytics-browser-actions-playerzero": "^1.16.0",
- "@segment/analytics-browser-actions-ripe": "^1.16.0",
+ "@segment/analytics-browser-actions-adobe-target": "^1.17.0",
+ "@segment/analytics-browser-actions-amplitude-plugins": "^1.17.0",
+ "@segment/analytics-browser-actions-braze": "^1.20.0",
+ "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.20.0",
+ "@segment/analytics-browser-actions-cdpresolution": "^1.4.0",
+ "@segment/analytics-browser-actions-commandbar": "^1.17.0",
+ "@segment/analytics-browser-actions-devrev": "^1.4.0",
+ "@segment/analytics-browser-actions-friendbuy": "^1.17.0",
+ "@segment/analytics-browser-actions-fullstory": "^1.18.0",
+ "@segment/analytics-browser-actions-google-analytics-4": "^1.21.0",
+ "@segment/analytics-browser-actions-google-campaign-manager": "^1.7.0",
+ "@segment/analytics-browser-actions-heap": "^1.17.0",
+ "@segment/analytics-browser-actions-hubspot": "^1.17.0",
+ "@segment/analytics-browser-actions-intercom": "^1.17.0",
+ "@segment/analytics-browser-actions-iterate": "^1.17.0",
+ "@segment/analytics-browser-actions-koala": "^1.17.0",
+ "@segment/analytics-browser-actions-logrocket": "^1.17.0",
+ "@segment/analytics-browser-actions-pendo-web-actions": "^1.5.0",
+ "@segment/analytics-browser-actions-playerzero": "^1.17.0",
+ "@segment/analytics-browser-actions-ripe": "^1.17.0",
"@segment/analytics-browser-actions-sabil": "^1.6.0",
- "@segment/analytics-browser-actions-screeb": "^1.16.0",
- "@segment/analytics-browser-actions-sprig": "^1.16.0",
- "@segment/analytics-browser-actions-stackadapt": "^1.16.0",
- "@segment/analytics-browser-actions-tiktok-pixel": "^1.13.0",
- "@segment/analytics-browser-actions-upollo": "^1.16.0",
- "@segment/analytics-browser-actions-userpilot": "^1.16.0",
- "@segment/analytics-browser-actions-utils": "^1.16.0",
- "@segment/analytics-browser-actions-vwo": "^1.17.0",
- "@segment/analytics-browser-actions-wiseops": "^1.16.0",
- "@segment/analytics-browser-hubble-web": "^1.2.0",
- "@segment/browser-destination-runtime": "^1.15.0"
+ "@segment/analytics-browser-actions-screeb": "^1.17.0",
+ "@segment/analytics-browser-actions-sprig": "^1.17.0",
+ "@segment/analytics-browser-actions-stackadapt": "^1.17.0",
+ "@segment/analytics-browser-actions-tiktok-pixel": "^1.14.0",
+ "@segment/analytics-browser-actions-upollo": "^1.17.0",
+ "@segment/analytics-browser-actions-userpilot": "^1.17.0",
+ "@segment/analytics-browser-actions-utils": "^1.17.0",
+ "@segment/analytics-browser-actions-vwo": "^1.18.0",
+ "@segment/analytics-browser-actions-wiseops": "^1.17.0",
+ "@segment/analytics-browser-hubble-web": "^1.3.0",
+ "@segment/browser-destination-runtime": "^1.16.0"
}
}
From 17f86e824a3dc58df8fc159d74f22124fb6832a0 Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 18:20:57 +0200
Subject: [PATCH 052/389] Change to force new publish of
destination-subscriptions
---
packages/destination-subscriptions/src/get.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/destination-subscriptions/src/get.ts b/packages/destination-subscriptions/src/get.ts
index b15f030df0..5355cb9229 100644
--- a/packages/destination-subscriptions/src/get.ts
+++ b/packages/destination-subscriptions/src/get.ts
@@ -8,7 +8,7 @@ export function get(
path: string | string[],
defValue?: Default
): T | undefined | Default {
- // If path is not defined or it has false value
+ // If path is not defined or it has false value.
if (!path) return defValue
// Check if path is string or array. Regex : ensure that we do not have '.' and brackets.
From 4eba9a78ed6e60ef12d126c79068eb7203177347 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 17 Oct 2023 17:22:13 +0100
Subject: [PATCH 053/389] Publish
- @segment/actions-shared@1.68.0
- @segment/browser-destination-runtime@1.17.0
- @segment/actions-core@3.86.0
- @segment/action-destinations@3.225.0
- @segment/destination-subscriptions@3.30.0
- @segment/destinations-manifest@1.26.0
- @segment/analytics-browser-actions-adobe-target@1.18.0
- @segment/analytics-browser-actions-amplitude-plugins@1.18.0
- @segment/analytics-browser-actions-braze-cloud-plugins@1.21.0
- @segment/analytics-browser-actions-braze@1.21.0
- @segment/analytics-browser-actions-cdpresolution@1.5.0
- @segment/analytics-browser-actions-commandbar@1.18.0
- @segment/analytics-browser-actions-devrev@1.5.0
- @segment/analytics-browser-actions-friendbuy@1.18.0
- @segment/analytics-browser-actions-fullstory@1.19.0
- @segment/analytics-browser-actions-google-analytics-4@1.22.0
- @segment/analytics-browser-actions-google-campaign-manager@1.8.0
- @segment/analytics-browser-actions-heap@1.18.0
- @segment/analytics-browser-hubble-web@1.4.0
- @segment/analytics-browser-actions-hubspot@1.18.0
- @segment/analytics-browser-actions-intercom@1.18.0
- @segment/analytics-browser-actions-iterate@1.18.0
- @segment/analytics-browser-actions-jimo@1.4.0
- @segment/analytics-browser-actions-koala@1.18.0
- @segment/analytics-browser-actions-logrocket@1.18.0
- @segment/analytics-browser-actions-pendo-web-actions@1.6.0
- @segment/analytics-browser-actions-playerzero@1.18.0
- @segment/analytics-browser-actions-ripe@1.18.0
- @segment/analytics-browser-actions-rupt@1.7.0
- @segment/analytics-browser-actions-screeb@1.18.0
- @segment/analytics-browser-actions-utils@1.18.0
- @segment/analytics-browser-actions-sprig@1.18.0
- @segment/analytics-browser-actions-stackadapt@1.18.0
- @segment/analytics-browser-actions-tiktok-pixel@1.15.0
- @segment/analytics-browser-actions-upollo@1.18.0
- @segment/analytics-browser-actions-userpilot@1.18.0
- @segment/analytics-browser-actions-vwo@1.19.0
- @segment/analytics-browser-actions-wiseops@1.18.0
---
packages/actions-shared/package.json | 4 +-
.../browser-destination-runtime/package.json | 4 +-
.../destinations/adobe-target/package.json | 4 +-
.../amplitude-plugins/package.json | 4 +-
.../braze-cloud-plugins/package.json | 6 +-
.../destinations/braze/package.json | 6 +-
.../destinations/cdpresolution/package.json | 4 +-
.../destinations/commandbar/package.json | 6 +-
.../destinations/devrev/package.json | 4 +-
.../destinations/friendbuy/package.json | 8 +--
.../destinations/fullstory/package.json | 6 +-
.../google-analytics-4-web/package.json | 6 +-
.../google-campaign-manager/package.json | 4 +-
.../destinations/heap/package.json | 6 +-
.../destinations/hubble-web/package.json | 6 +-
.../destinations/hubspot-web/package.json | 6 +-
.../destinations/intercom/package.json | 8 +--
.../destinations/iterate/package.json | 6 +-
.../destinations/jimo/package.json | 4 +-
.../destinations/koala/package.json | 6 +-
.../destinations/logrocket/package.json | 6 +-
.../pendo-web-actions/package.json | 4 +-
.../destinations/playerzero-web/package.json | 6 +-
.../destinations/ripe/package.json | 6 +-
.../destinations/rupt/package.json | 6 +-
.../destinations/screeb/package.json | 6 +-
.../segment-utilities-web/package.json | 4 +-
.../destinations/sprig-web/package.json | 6 +-
.../destinations/stackadapt/package.json | 6 +-
.../destinations/tiktok-pixel/package.json | 6 +-
.../destinations/upollo/package.json | 6 +-
.../destinations/userpilot/package.json | 6 +-
.../destinations/vwo/package.json | 6 +-
.../destinations/wisepops/package.json | 6 +-
packages/core/package.json | 4 +-
packages/destination-actions/package.json | 6 +-
.../destination-subscriptions/package.json | 2 +-
packages/destinations-manifest/package.json | 64 +++++++++----------
38 files changed, 132 insertions(+), 132 deletions(-)
diff --git a/packages/actions-shared/package.json b/packages/actions-shared/package.json
index 9b9dc63b20..76da8f403b 100644
--- a/packages/actions-shared/package.json
+++ b/packages/actions-shared/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-shared",
"description": "Shared destination action methods and definitions.",
- "version": "1.67.0",
+ "version": "1.68.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -37,7 +37,7 @@
},
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
- "@segment/actions-core": "^3.85.0",
+ "@segment/actions-core": "^3.86.0",
"cheerio": "^1.0.0-rc.10",
"dayjs": "^1.10.7",
"escape-goat": "^3",
diff --git a/packages/browser-destination-runtime/package.json b/packages/browser-destination-runtime/package.json
index 78730483eb..d3ee67b499 100644
--- a/packages/browser-destination-runtime/package.json
+++ b/packages/browser-destination-runtime/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/browser-destination-runtime",
- "version": "1.16.0",
+ "version": "1.17.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -62,7 +62,7 @@
}
},
"dependencies": {
- "@segment/actions-core": "^3.85.0"
+ "@segment/actions-core": "^3.86.0"
},
"devDependencies": {
"@segment/analytics-next": "*"
diff --git a/packages/browser-destinations/destinations/adobe-target/package.json b/packages/browser-destinations/destinations/adobe-target/package.json
index 8221e7ce09..c7b813b4ab 100644
--- a/packages/browser-destinations/destinations/adobe-target/package.json
+++ b/packages/browser-destinations/destinations/adobe-target/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-adobe-target",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,7 +16,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/amplitude-plugins/package.json b/packages/browser-destinations/destinations/amplitude-plugins/package.json
index 230a6eb673..116d057c8e 100644
--- a/packages/browser-destinations/destinations/amplitude-plugins/package.json
+++ b/packages/browser-destinations/destinations/amplitude-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-amplitude-plugins",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
index 70d4b9018a..f6aaee0c50 100644
--- a/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
+++ b/packages/browser-destinations/destinations/braze-cloud-plugins/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze-cloud-plugins",
- "version": "1.20.0",
+ "version": "1.21.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/analytics-browser-actions-braze": "^1.20.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/analytics-browser-actions-braze": "^1.21.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/braze/package.json b/packages/browser-destinations/destinations/braze/package.json
index 8c94fde2e7..2fc4ad7787 100644
--- a/packages/browser-destinations/destinations/braze/package.json
+++ b/packages/browser-destinations/destinations/braze/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-braze",
- "version": "1.20.0",
+ "version": "1.21.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -35,8 +35,8 @@
"dependencies": {
"@braze/web-sdk": "npm:@braze/web-sdk@^4.1.0",
"@braze/web-sdk-v3": "npm:@braze/web-sdk@^3.5.1",
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/cdpresolution/package.json b/packages/browser-destinations/destinations/cdpresolution/package.json
index 1ce7d15f78..0fc52ad048 100644
--- a/packages/browser-destinations/destinations/cdpresolution/package.json
+++ b/packages/browser-destinations/destinations/cdpresolution/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-cdpresolution",
- "version": "1.4.0",
+ "version": "1.5.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/commandbar/package.json b/packages/browser-destinations/destinations/commandbar/package.json
index 986dea4c9a..a45df9db7a 100644
--- a/packages/browser-destinations/destinations/commandbar/package.json
+++ b/packages/browser-destinations/destinations/commandbar/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-commandbar",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/devrev/package.json b/packages/browser-destinations/destinations/devrev/package.json
index 07882e7f30..1ba39886f6 100644
--- a/packages/browser-destinations/destinations/devrev/package.json
+++ b/packages/browser-destinations/destinations/devrev/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-devrev",
- "version": "1.4.0",
+ "version": "1.5.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/friendbuy/package.json b/packages/browser-destinations/destinations/friendbuy/package.json
index 1f73444c66..a6febc1606 100644
--- a/packages/browser-destinations/destinations/friendbuy/package.json
+++ b/packages/browser-destinations/destinations/friendbuy/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-friendbuy",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/actions-shared": "^1.67.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/actions-shared": "^1.68.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/fullstory/package.json b/packages/browser-destinations/destinations/fullstory/package.json
index 7ba47de1f6..ea90aef39b 100644
--- a/packages/browser-destinations/destinations/fullstory/package.json
+++ b/packages/browser-destinations/destinations/fullstory/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-fullstory",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -16,8 +16,8 @@
"typings": "./dist/esm",
"dependencies": {
"@fullstory/browser": "^1.4.9",
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-analytics-4-web/package.json b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
index b5a9c93549..fb127d0324 100644
--- a/packages/browser-destinations/destinations/google-analytics-4-web/package.json
+++ b/packages/browser-destinations/destinations/google-analytics-4-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-analytics-4",
- "version": "1.21.0",
+ "version": "1.22.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/google-campaign-manager/package.json b/packages/browser-destinations/destinations/google-campaign-manager/package.json
index d137088c5d..3d1df5087d 100644
--- a/packages/browser-destinations/destinations/google-campaign-manager/package.json
+++ b/packages/browser-destinations/destinations/google-campaign-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-google-campaign-manager",
- "version": "1.7.0",
+ "version": "1.8.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/heap/package.json b/packages/browser-destinations/destinations/heap/package.json
index 2d6880667b..b0696b6bc6 100644
--- a/packages/browser-destinations/destinations/heap/package.json
+++ b/packages/browser-destinations/destinations/heap/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-heap",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubble-web/package.json b/packages/browser-destinations/destinations/hubble-web/package.json
index de88530de1..d9cbb13586 100644
--- a/packages/browser-destinations/destinations/hubble-web/package.json
+++ b/packages/browser-destinations/destinations/hubble-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-hubble-web",
- "version": "1.3.0",
+ "version": "1.4.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/hubspot-web/package.json b/packages/browser-destinations/destinations/hubspot-web/package.json
index b191afa969..9e5cf8fab1 100644
--- a/packages/browser-destinations/destinations/hubspot-web/package.json
+++ b/packages/browser-destinations/destinations/hubspot-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-hubspot",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/intercom/package.json b/packages/browser-destinations/destinations/intercom/package.json
index ff51f987e8..4ba500a49c 100644
--- a/packages/browser-destinations/destinations/intercom/package.json
+++ b/packages/browser-destinations/destinations/intercom/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-intercom",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,9 +15,9 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/actions-shared": "^1.67.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/actions-shared": "^1.68.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/iterate/package.json b/packages/browser-destinations/destinations/iterate/package.json
index 5645039ff2..7f7b4cc59f 100644
--- a/packages/browser-destinations/destinations/iterate/package.json
+++ b/packages/browser-destinations/destinations/iterate/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-iterate",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/jimo/package.json b/packages/browser-destinations/destinations/jimo/package.json
index 98b692fd4b..227988dbd0 100644
--- a/packages/browser-destinations/destinations/jimo/package.json
+++ b/packages/browser-destinations/destinations/jimo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-jimo",
- "version": "1.3.0",
+ "version": "1.4.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/koala/package.json b/packages/browser-destinations/destinations/koala/package.json
index eb3641367a..2cc4b38e7e 100644
--- a/packages/browser-destinations/destinations/koala/package.json
+++ b/packages/browser-destinations/destinations/koala/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-koala",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/logrocket/package.json b/packages/browser-destinations/destinations/logrocket/package.json
index 40e9cf2468..f925b34ab6 100644
--- a/packages/browser-destinations/destinations/logrocket/package.json
+++ b/packages/browser-destinations/destinations/logrocket/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-logrocket",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0",
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0",
"logrocket": "^3.0.1"
},
"peerDependencies": {
diff --git a/packages/browser-destinations/destinations/pendo-web-actions/package.json b/packages/browser-destinations/destinations/pendo-web-actions/package.json
index 2a72f8b4fb..c28f7cf099 100644
--- a/packages/browser-destinations/destinations/pendo-web-actions/package.json
+++ b/packages/browser-destinations/destinations/pendo-web-actions/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-pendo-web-actions",
- "version": "1.5.0",
+ "version": "1.6.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/playerzero-web/package.json b/packages/browser-destinations/destinations/playerzero-web/package.json
index 019d3b877f..cb4bb3e274 100644
--- a/packages/browser-destinations/destinations/playerzero-web/package.json
+++ b/packages/browser-destinations/destinations/playerzero-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-playerzero",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/ripe/package.json b/packages/browser-destinations/destinations/ripe/package.json
index bcd5156b5c..1e73411b95 100644
--- a/packages/browser-destinations/destinations/ripe/package.json
+++ b/packages/browser-destinations/destinations/ripe/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-ripe",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/rupt/package.json b/packages/browser-destinations/destinations/rupt/package.json
index 8c45a53b82..b48fbc9d28 100644
--- a/packages/browser-destinations/destinations/rupt/package.json
+++ b/packages/browser-destinations/destinations/rupt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-rupt",
- "version": "1.6.0",
+ "version": "1.7.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/screeb/package.json b/packages/browser-destinations/destinations/screeb/package.json
index 4e22c6b011..d4eacc5f07 100644
--- a/packages/browser-destinations/destinations/screeb/package.json
+++ b/packages/browser-destinations/destinations/screeb/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-screeb",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/segment-utilities-web/package.json b/packages/browser-destinations/destinations/segment-utilities-web/package.json
index 34157d501d..d9ab50f45f 100644
--- a/packages/browser-destinations/destinations/segment-utilities-web/package.json
+++ b/packages/browser-destinations/destinations/segment-utilities-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-utils",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,7 +15,7 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/sprig-web/package.json b/packages/browser-destinations/destinations/sprig-web/package.json
index 239f5dc144..bc121bf876 100644
--- a/packages/browser-destinations/destinations/sprig-web/package.json
+++ b/packages/browser-destinations/destinations/sprig-web/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-sprig",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/stackadapt/package.json b/packages/browser-destinations/destinations/stackadapt/package.json
index e0f55ae8c5..c395f908bc 100644
--- a/packages/browser-destinations/destinations/stackadapt/package.json
+++ b/packages/browser-destinations/destinations/stackadapt/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-stackadapt",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/tiktok-pixel/package.json b/packages/browser-destinations/destinations/tiktok-pixel/package.json
index ed5edf6bc0..960fb3b7ba 100644
--- a/packages/browser-destinations/destinations/tiktok-pixel/package.json
+++ b/packages/browser-destinations/destinations/tiktok-pixel/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-tiktok-pixel",
- "version": "1.14.0",
+ "version": "1.15.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/upollo/package.json b/packages/browser-destinations/destinations/upollo/package.json
index 6ffd3c489a..e86240195b 100644
--- a/packages/browser-destinations/destinations/upollo/package.json
+++ b/packages/browser-destinations/destinations/upollo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-upollo",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/userpilot/package.json b/packages/browser-destinations/destinations/userpilot/package.json
index f889d1961e..ad2fcbbc51 100644
--- a/packages/browser-destinations/destinations/userpilot/package.json
+++ b/packages/browser-destinations/destinations/userpilot/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-userpilot",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/vwo/package.json b/packages/browser-destinations/destinations/vwo/package.json
index ff1042c5c5..de09ea930b 100644
--- a/packages/browser-destinations/destinations/vwo/package.json
+++ b/packages/browser-destinations/destinations/vwo/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-vwo",
- "version": "1.18.0",
+ "version": "1.19.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/browser-destinations/destinations/wisepops/package.json b/packages/browser-destinations/destinations/wisepops/package.json
index b3e9590dc0..75244f9ab8 100644
--- a/packages/browser-destinations/destinations/wisepops/package.json
+++ b/packages/browser-destinations/destinations/wisepops/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/analytics-browser-actions-wiseops",
- "version": "1.17.0",
+ "version": "1.18.0",
"license": "MIT",
"publishConfig": {
"access": "public",
@@ -15,8 +15,8 @@
},
"typings": "./dist/esm",
"dependencies": {
- "@segment/actions-core": "^3.85.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/actions-core": "^3.86.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
},
"peerDependencies": {
"@segment/analytics-next": ">=1.55.0"
diff --git a/packages/core/package.json b/packages/core/package.json
index 94493878a8..94d9013a46 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/actions-core",
"description": "Core runtime for Destinations Actions.",
- "version": "3.85.0",
+ "version": "3.86.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/fab-5-engine",
@@ -82,7 +82,7 @@
"@lukeed/uuid": "^2.0.0",
"@segment/action-emitters": "^1.1.2",
"@segment/ajv-human-errors": "^2.11.3",
- "@segment/destination-subscriptions": "^3.29.0",
+ "@segment/destination-subscriptions": "^3.30.0",
"@types/node": "^18.11.15",
"abort-controller": "^3.0.0",
"aggregate-error": "^3.1.0",
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index b149e641b2..a62c587ccf 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.224.0",
+ "version": "3.225.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
@@ -40,8 +40,8 @@
"dependencies": {
"@amplitude/ua-parser-js": "^0.7.25",
"@segment/a1-notation": "^2.1.4",
- "@segment/actions-core": "^3.85.0",
- "@segment/actions-shared": "^1.67.0",
+ "@segment/actions-core": "^3.86.0",
+ "@segment/actions-shared": "^1.68.0",
"@types/node": "^18.11.15",
"ajv-formats": "^2.1.1",
"aws4": "^1.12.0",
diff --git a/packages/destination-subscriptions/package.json b/packages/destination-subscriptions/package.json
index 4b3993e185..6ad3a829e1 100644
--- a/packages/destination-subscriptions/package.json
+++ b/packages/destination-subscriptions/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destination-subscriptions",
- "version": "3.29.0",
+ "version": "3.30.0",
"description": "Validate event payload using subscription AST",
"license": "MIT",
"repository": {
diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json
index 6d12705295..7495403962 100644
--- a/packages/destinations-manifest/package.json
+++ b/packages/destinations-manifest/package.json
@@ -1,6 +1,6 @@
{
"name": "@segment/destinations-manifest",
- "version": "1.25.0",
+ "version": "1.26.0",
"publishConfig": {
"access": "public",
"registry": "https://registry.npmjs.org"
@@ -12,37 +12,37 @@
"main": "./dist/index.js",
"typings": "./dist/index.d.ts",
"dependencies": {
- "@segment/analytics-browser-actions-adobe-target": "^1.17.0",
- "@segment/analytics-browser-actions-amplitude-plugins": "^1.17.0",
- "@segment/analytics-browser-actions-braze": "^1.20.0",
- "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.20.0",
- "@segment/analytics-browser-actions-cdpresolution": "^1.4.0",
- "@segment/analytics-browser-actions-commandbar": "^1.17.0",
- "@segment/analytics-browser-actions-devrev": "^1.4.0",
- "@segment/analytics-browser-actions-friendbuy": "^1.17.0",
- "@segment/analytics-browser-actions-fullstory": "^1.18.0",
- "@segment/analytics-browser-actions-google-analytics-4": "^1.21.0",
- "@segment/analytics-browser-actions-google-campaign-manager": "^1.7.0",
- "@segment/analytics-browser-actions-heap": "^1.17.0",
- "@segment/analytics-browser-actions-hubspot": "^1.17.0",
- "@segment/analytics-browser-actions-intercom": "^1.17.0",
- "@segment/analytics-browser-actions-iterate": "^1.17.0",
- "@segment/analytics-browser-actions-koala": "^1.17.0",
- "@segment/analytics-browser-actions-logrocket": "^1.17.0",
- "@segment/analytics-browser-actions-pendo-web-actions": "^1.5.0",
- "@segment/analytics-browser-actions-playerzero": "^1.17.0",
- "@segment/analytics-browser-actions-ripe": "^1.17.0",
+ "@segment/analytics-browser-actions-adobe-target": "^1.18.0",
+ "@segment/analytics-browser-actions-amplitude-plugins": "^1.18.0",
+ "@segment/analytics-browser-actions-braze": "^1.21.0",
+ "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.21.0",
+ "@segment/analytics-browser-actions-cdpresolution": "^1.5.0",
+ "@segment/analytics-browser-actions-commandbar": "^1.18.0",
+ "@segment/analytics-browser-actions-devrev": "^1.5.0",
+ "@segment/analytics-browser-actions-friendbuy": "^1.18.0",
+ "@segment/analytics-browser-actions-fullstory": "^1.19.0",
+ "@segment/analytics-browser-actions-google-analytics-4": "^1.22.0",
+ "@segment/analytics-browser-actions-google-campaign-manager": "^1.8.0",
+ "@segment/analytics-browser-actions-heap": "^1.18.0",
+ "@segment/analytics-browser-actions-hubspot": "^1.18.0",
+ "@segment/analytics-browser-actions-intercom": "^1.18.0",
+ "@segment/analytics-browser-actions-iterate": "^1.18.0",
+ "@segment/analytics-browser-actions-koala": "^1.18.0",
+ "@segment/analytics-browser-actions-logrocket": "^1.18.0",
+ "@segment/analytics-browser-actions-pendo-web-actions": "^1.6.0",
+ "@segment/analytics-browser-actions-playerzero": "^1.18.0",
+ "@segment/analytics-browser-actions-ripe": "^1.18.0",
"@segment/analytics-browser-actions-sabil": "^1.6.0",
- "@segment/analytics-browser-actions-screeb": "^1.17.0",
- "@segment/analytics-browser-actions-sprig": "^1.17.0",
- "@segment/analytics-browser-actions-stackadapt": "^1.17.0",
- "@segment/analytics-browser-actions-tiktok-pixel": "^1.14.0",
- "@segment/analytics-browser-actions-upollo": "^1.17.0",
- "@segment/analytics-browser-actions-userpilot": "^1.17.0",
- "@segment/analytics-browser-actions-utils": "^1.17.0",
- "@segment/analytics-browser-actions-vwo": "^1.18.0",
- "@segment/analytics-browser-actions-wiseops": "^1.17.0",
- "@segment/analytics-browser-hubble-web": "^1.3.0",
- "@segment/browser-destination-runtime": "^1.16.0"
+ "@segment/analytics-browser-actions-screeb": "^1.18.0",
+ "@segment/analytics-browser-actions-sprig": "^1.18.0",
+ "@segment/analytics-browser-actions-stackadapt": "^1.18.0",
+ "@segment/analytics-browser-actions-tiktok-pixel": "^1.15.0",
+ "@segment/analytics-browser-actions-upollo": "^1.18.0",
+ "@segment/analytics-browser-actions-userpilot": "^1.18.0",
+ "@segment/analytics-browser-actions-utils": "^1.18.0",
+ "@segment/analytics-browser-actions-vwo": "^1.19.0",
+ "@segment/analytics-browser-actions-wiseops": "^1.18.0",
+ "@segment/analytics-browser-hubble-web": "^1.4.0",
+ "@segment/browser-destination-runtime": "^1.17.0"
}
}
From a8bfc846248087a3b4b609a4d1be05e63c342dc7 Mon Sep 17 00:00:00 2001
From: hvardhan-unth <117922634+hvardhan-unth@users.noreply.github.com>
Date: Wed, 18 Oct 2023 14:05:12 +0530
Subject: [PATCH 054/389] Register Linkedin conversions API (#1662)
* Resgister linkedin conversions API
* Removed unwanted lint changes
---------
Co-authored-by: Harsh Vardhan
---
packages/destination-actions/src/destinations/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index 5cbdc916aa..bd661f06ca 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -132,6 +132,7 @@ register('650bdf1a62fb34ef0a8058e1', './klaviyo')
register('6512d7f86bdccc3829fc4ac3', './optimizely-data-platform')
register('651c1db19de92d8e595ff55d', './hyperengage')
register('65256052ac030f823df6c1a5', './trackey')
+register('652e765dbea0a2319209d193', './linkedin-conversions')
register('652ea51a327a62b351aa12c0', './kameleoon')
function register(id: MetadataId, destinationPath: string) {
From 46d42f1a2d3059d33818314051e77dc607cf2f67 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mar=C3=ADn=20Alcaraz?=
Date: Wed, 18 Oct 2023 11:38:50 -0700
Subject: [PATCH 055/389] Add actions-display-video-360 (#1646)
---
.../display-video-360/__tests__/index.test.ts | 5 +++++
.../addToAudience/__tests__/index.test.ts | 5 +++++
.../addToAudience/generated-types.ts | 3 +++
.../display-video-360/addToAudience/index.ts | 14 ++++++++++++++
.../display-video-360/generated-types.ts | 3 +++
.../destinations/display-video-360/index.ts | 18 ++++++++++++++++++
.../removeFromAudience/__tests__/index.test.ts | 5 +++++
.../removeFromAudience/generated-types.ts | 3 +++
.../removeFromAudience/index.ts | 14 ++++++++++++++
9 files changed, 70 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/addToAudience/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/index.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/removeFromAudience/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/removeFromAudience/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
diff --git a/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts b/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
new file mode 100644
index 0000000000..d08b980f5c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('Display Video 360', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/__tests__/index.test.ts
new file mode 100644
index 0000000000..122f8754d3
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('DisplayVideo360.addToAudience', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts
new file mode 100644
index 0000000000..944d22b085
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {}
diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
new file mode 100644
index 0000000000..074149ed2f
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
@@ -0,0 +1,14 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Add to Audience',
+ description: '',
+ fields: {},
+ perform: () => {
+ return
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/display-video-360/generated-types.ts b/packages/destination-actions/src/destinations/display-video-360/generated-types.ts
new file mode 100644
index 0000000000..4ab2786ec6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {}
diff --git a/packages/destination-actions/src/destinations/display-video-360/index.ts b/packages/destination-actions/src/destinations/display-video-360/index.ts
new file mode 100644
index 0000000000..455024ccbd
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/index.ts
@@ -0,0 +1,18 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+
+import addToAudience from './addToAudience'
+
+import removeFromAudience from './removeFromAudience'
+
+const destination: DestinationDefinition = {
+ name: 'Display and Video 360 (Actions)',
+ slug: 'actions-display-video-360',
+ mode: 'cloud',
+ actions: {
+ addToAudience,
+ removeFromAudience
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/__tests__/index.test.ts
new file mode 100644
index 0000000000..9410097145
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('DisplayVideo360.removeFromAudience', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/generated-types.ts b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/generated-types.ts
new file mode 100644
index 0000000000..944d22b085
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {}
diff --git a/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
new file mode 100644
index 0000000000..fd8e2c4be9
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
@@ -0,0 +1,14 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Remove from Audience',
+ description: '',
+ fields: {},
+ perform: () => {
+ return
+ }
+}
+
+export default action
From 70d152684690a95f5c33a29eb705731218203b13 Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Wed, 18 Oct 2023 14:39:58 -0400
Subject: [PATCH 056/389] TikTok and Trade Desk changes (#1666)
* Change TikTok statsclient name
* Add headers to Trade Desk request
---
.../src/destinations/the-trade-desk-crm/functions.ts | 6 +++++-
.../src/destinations/tiktok-audiences/addUser/index.ts | 4 ++--
.../src/destinations/tiktok-audiences/removeUser/index.ts | 4 ++--
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
index 12baddfda0..6a487f84b1 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
@@ -176,7 +176,11 @@ export async function getAllDataSegments(request: RequestClient, advertiserId: s
const allDataSegments: Segments[] = []
// initial call to get first page
let response: ModifiedResponse = await request(`${BASE_URL}/crmdata/segment/${advertiserId}`, {
- method: 'GET'
+ method: 'GET',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'TTD-Auth': authToken
+ }
})
if (response.status != 200 || !response.data.Segments) {
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
index 195191192a..444c236f46 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/addUser/index.ts
@@ -75,11 +75,11 @@ const action: ActionDefinition = {
}
},
perform: async (request, { settings, payload, statsContext }) => {
- statsContext?.statsClient?.incr('addUser', 1, statsContext?.tags)
+ statsContext?.statsClient?.incr('addUserLegacy', 1, statsContext?.tags)
return processPayload(request, settings, [payload], 'add')
},
performBatch: async (request, { settings, payload, statsContext }) => {
- statsContext?.statsClient?.incr('addUser', 1, statsContext?.tags)
+ statsContext?.statsClient?.incr('addUserLegacy', 1, statsContext?.tags)
return processPayload(request, settings, payload, 'add')
}
}
diff --git a/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts b/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
index 2138a8c5d4..131ef737da 100644
--- a/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
+++ b/packages/destination-actions/src/destinations/tiktok-audiences/removeUser/index.ts
@@ -74,11 +74,11 @@ const action: ActionDefinition = {
}
},
perform: async (request, { settings, payload, statsContext }) => {
- statsContext?.statsClient?.incr('removeUser', 1, statsContext?.tags)
+ statsContext?.statsClient?.incr('removeUserLegacy', 1, statsContext?.tags)
return processPayload(request, settings, [payload], 'delete')
},
performBatch: async (request, { settings, payload, statsContext }) => {
- statsContext?.statsClient?.incr('removeUser', 1, statsContext?.tags)
+ statsContext?.statsClient?.incr('removeUserLegacy', 1, statsContext?.tags)
return processPayload(request, settings, payload, 'delete')
}
}
From 83ee2b69f434172b5c541baa75ea37b823c990d3 Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Wed, 18 Oct 2023 14:40:11 -0400
Subject: [PATCH 057/389] Scaffold Marketo Static Lists (#1665)
* Scaffold destination and actions
* Fix name
---
.../__tests__/index.test.ts | 5 +++
.../addToList/__tests__/index.test.ts | 5 +++
.../addToList/generated-types.ts | 3 ++
.../marketo-static-lists/addToList/index.ts | 14 +++++++++
.../marketo-static-lists/generated-types.ts | 3 ++
.../marketo-static-lists/index.ts | 31 +++++++++++++++++++
.../removeFromList/__tests__/index.test.ts | 5 +++
.../removeFromList/generated-types.ts | 3 ++
.../removeFromList/index.ts | 14 +++++++++
9 files changed, 83 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/addToList/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/addToList/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/index.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/__tests__/index.test.ts b/packages/destination-actions/src/destinations/marketo-static-lists/__tests__/index.test.ts
new file mode 100644
index 0000000000..559600c98b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('Marketo Static Lists', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/addToList/__tests__/index.test.ts b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/__tests__/index.test.ts
new file mode 100644
index 0000000000..8fd9916a85
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('MarketoStaticLists.addToList', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/addToList/generated-types.ts b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/generated-types.ts
new file mode 100644
index 0000000000..944d22b085
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {}
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
new file mode 100644
index 0000000000..cfe1d696c6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
@@ -0,0 +1,14 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Add to List',
+ description: '',
+ fields: {},
+ perform: () => {
+ return
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/generated-types.ts b/packages/destination-actions/src/destinations/marketo-static-lists/generated-types.ts
new file mode 100644
index 0000000000..4ab2786ec6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {}
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/index.ts b/packages/destination-actions/src/destinations/marketo-static-lists/index.ts
new file mode 100644
index 0000000000..7782cfbdc4
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/index.ts
@@ -0,0 +1,31 @@
+import type { AudienceDestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+
+import addToList from './addToList'
+import removeFromList from './removeFromList'
+
+const destination: AudienceDestinationDefinition = {
+ name: 'Marketo Static Lists (Actions)',
+ slug: 'actions-marketo-static-lists',
+ mode: 'cloud',
+
+ authentication: {
+ scheme: 'oauth2',
+ fields: {}
+ },
+
+ audienceFields: {},
+
+ audienceConfig: {
+ mode: {
+ type: 'synced', // Indicates that the audience is synced on some schedule; update as necessary
+ full_audience_sync: false // If true, we send the entire audience. If false, we just send the delta.
+ }
+ },
+ actions: {
+ addToList,
+ removeFromList
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/__tests__/index.test.ts b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/__tests__/index.test.ts
new file mode 100644
index 0000000000..8fd9916a85
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/__tests__/index.test.ts
@@ -0,0 +1,5 @@
+describe('MarketoStaticLists.addToList', () => {
+ it('is a placeholder for an actual test', () => {
+ expect(true).toBe(true)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/generated-types.ts b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/generated-types.ts
new file mode 100644
index 0000000000..944d22b085
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/generated-types.ts
@@ -0,0 +1,3 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {}
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
new file mode 100644
index 0000000000..54326ca2a4
--- /dev/null
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
@@ -0,0 +1,14 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Remove from List',
+ description: '',
+ fields: {},
+ perform: () => {
+ return
+ }
+}
+
+export default action
From c6dc88a7c09fe6c3fc3b62539048fe76cac1826f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mar=C3=ADn=20Alcaraz?=
Date: Wed, 18 Oct 2023 15:54:05 -0700
Subject: [PATCH 058/389] Register DV360 and Marketo Static Lists (#1668)
---
.../src/destinations/display-video-360/addToAudience/index.ts | 2 +-
.../destinations/display-video-360/removeFromAudience/index.ts | 2 +-
packages/destination-actions/src/destinations/index.ts | 2 ++
.../src/destinations/marketo-static-lists/addToList/index.ts | 2 +-
.../destinations/marketo-static-lists/removeFromList/index.ts | 2 +-
5 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
index 074149ed2f..ea890cabef 100644
--- a/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
+++ b/packages/destination-actions/src/destinations/display-video-360/addToAudience/index.ts
@@ -4,7 +4,7 @@ import type { Payload } from './generated-types'
const action: ActionDefinition = {
title: 'Add to Audience',
- description: '',
+ description: 'Add users into an audience',
fields: {},
perform: () => {
return
diff --git a/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
index fd8e2c4be9..f1baa478e0 100644
--- a/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
+++ b/packages/destination-actions/src/destinations/display-video-360/removeFromAudience/index.ts
@@ -4,7 +4,7 @@ import type { Payload } from './generated-types'
const action: ActionDefinition = {
title: 'Remove from Audience',
- description: '',
+ description: 'Remove users from an audience',
fields: {},
perform: () => {
return
diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts
index bd661f06ca..d075a45f1b 100644
--- a/packages/destination-actions/src/destinations/index.ts
+++ b/packages/destination-actions/src/destinations/index.ts
@@ -134,6 +134,8 @@ register('651c1db19de92d8e595ff55d', './hyperengage')
register('65256052ac030f823df6c1a5', './trackey')
register('652e765dbea0a2319209d193', './linkedin-conversions')
register('652ea51a327a62b351aa12c0', './kameleoon')
+register('65302a514ce4a2f0f14cd426', './marketo-static-lists')
+register('65302a3acb309a8a3d5593f2', './display-video-360')
function register(id: MetadataId, destinationPath: string) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
index cfe1d696c6..eaf01527dc 100644
--- a/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/addToList/index.ts
@@ -4,7 +4,7 @@ import type { Payload } from './generated-types'
const action: ActionDefinition = {
title: 'Add to List',
- description: '',
+ description: 'Add users into a list',
fields: {},
perform: () => {
return
diff --git a/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
index 54326ca2a4..9868e4d568 100644
--- a/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
+++ b/packages/destination-actions/src/destinations/marketo-static-lists/removeFromList/index.ts
@@ -4,7 +4,7 @@ import type { Payload } from './generated-types'
const action: ActionDefinition = {
title: 'Remove from List',
- description: '',
+ description: 'Remove users from a list',
fields: {},
perform: () => {
return
From 0a45cbaac2b1932938e37e9047151c7b0fd12d35 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mar=C3=ADn=20Alcaraz?=
Date: Wed, 18 Oct 2023 15:59:09 -0700
Subject: [PATCH 059/389] Publish
- @segment/action-destinations@3.226.0
---
packages/destination-actions/package.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json
index a62c587ccf..7792e24b42 100644
--- a/packages/destination-actions/package.json
+++ b/packages/destination-actions/package.json
@@ -1,7 +1,7 @@
{
"name": "@segment/action-destinations",
"description": "Destination Actions engine and definitions.",
- "version": "3.225.0",
+ "version": "3.226.0",
"repository": {
"type": "git",
"url": "https://github.com/segmentio/action-destinations",
From 8fd7ab6a6b50d669ca6e074b6917f92ff79745e1 Mon Sep 17 00:00:00 2001
From: Thomas Gilbert <64277654+tcgilbert@users.noreply.github.com>
Date: Thu, 19 Oct 2023 09:35:42 -0400
Subject: [PATCH 060/389] Update docs (#1667)
* update oauth section and remove mention of slack workspace
* update first sentence of oauth section
---
CONTRIBUTING.md | 2 +-
docs/authentication.md | 19 +++++++++++--------
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 40b75bb09c..ddce3cbbd4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -36,7 +36,7 @@ Before continuing, please make sure to read our [Code of Conduct](./CODE_OF_COND
3. Spec out the integration. If you want some guidance, you can use this [template](https://docs.google.com/document/d/1dIJxYge9N700U9Nhawapy25WMD8pUuey72S5qo3uejA/edit#heading=h.92w309fjzhti), which will prompt you to think about: whether you want to build a cloud-mode or device-mode destination, the method of authentication, the settings, and the Actions and default Field Mappings that you want to build.
-4. Join the Segment Partners Slack workspace. We’ll send you an invite. The **#dev-center-pilot** channel is the space for questions - partners can share their advice with each other, and the Segment team is there to answer any tricky questions.
+4. If you have any questions during the build process, please contact us at partner-support@segment.com.
## Build your integration
diff --git a/docs/authentication.md b/docs/authentication.md
index cd53517165..65dd4d9866 100644
--- a/docs/authentication.md
+++ b/docs/authentication.md
@@ -98,20 +98,25 @@ const destination = {
}
```
-## OAuth2 Authentication Scheme
+## OAuth 2.0 Managed Authentication Scheme
-_oauth authentication is not generally available to external partners as part of Developer Center Pilot. Please contact Segment team if you require it._
+OAuth 2.0 Managed Authentication scheme is the model to be used for destination APIs which support [OAuth 2.0](https://oauth.net/2/). You’ll be able to define a `refreshAccessToken` function if you want the framework to refresh expired tokens.
-OAuth2 Authentication scheme is the model to be used for destination APIs which support [OAuth 2.0](https://oauth.net/2/). You’ll be able to define a `refreshAccessToken` function if you want the framework to refresh expired tokens.
+You will have a new `auth` object available in `extendRequest` and `refreshAccessToken` which will surface your destination’s accessToken, refreshToken, clientId and clientSecret (these last two only available in `refreshAccessToken`). Most destination APIs expect the access token to be used as part of the authorization header in every request. You can use `extendRequest` to define that header.
-You will have a new `auth` object available in `extendRequest` and `refreshAccessToken` which will surface your destination’s accessToken, refreshToken, clientId and clientSecret (these last two only available in `refreshAccessToken`).
+Once your Actions code is deployed and you've received an invitation to manage the destination within our developer portal, you can then provide Segment with the following OAuth parameters.
-Most destination APIs expect the access token to be used as part of the authorization header in every request. You can use `extendRequest` to define that header.
+- Client ID
+- Client Secret
+- Authorization server URL
+ - Specify where to send users to authenticate with your API.
+- Access token server URL
+ - Enter the API endpoint URL where Segment sends the approval code on user redirect.
```
authentication: {
- scheme: 'oauth2',
+ scheme: 'oauth-managed',
fields: {
subdomain: {
type: 'string',
@@ -148,8 +153,6 @@ authentication: {
}
```
-**Note:** OAuth directly depends on the oauth providers available in Segment's internal OAuth Service. Please contact Segment if you require OAuth for your destination.
-
## Unsupported Authentication Schemes
We will explore adding built-in support for more authentication schemes when there is sufficient demand. These might include:
From 08b7162594ceb183673ccb4dd6c7d409249cabd8 Mon Sep 17 00:00:00 2001
From: Nick Aguilar
Date: Mon, 23 Oct 2023 12:59:29 -0700
Subject: [PATCH 061/389] Disables bulk batching for SFMC by setting batch_size
to 1000 (#1680)
---
.../destinations/salesforce-marketing-cloud/sfmc-properties.ts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts b/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
index 84a785996a..638788115e 100644
--- a/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
+++ b/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
@@ -87,5 +87,5 @@ export const batch_size: InputField = {
type: 'number',
required: false,
unsafe_hidden: true,
- default: 5000
+ default: 1000 // values < 4000 will disable bulk batching
}
From 978c08738653e38bfbb200bb65a39591986a1c8f Mon Sep 17 00:00:00 2001
From: Nick Aguilar
Date: Mon, 23 Oct 2023 16:09:11 -0700
Subject: [PATCH 062/389] Lowers SFMC Batch size to 50 (#1682)
---
.../salesforce-marketing-cloud/sfmc-properties.ts | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts b/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
index 638788115e..bb7e0115cb 100644
--- a/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
+++ b/packages/destination-actions/src/destinations/salesforce-marketing-cloud/sfmc-properties.ts
@@ -87,5 +87,10 @@ export const batch_size: InputField = {
type: 'number',
required: false,
unsafe_hidden: true,
- default: 1000 // values < 4000 will disable bulk batching
+ /**
+ * SFMC has very low limits on maximum batch size.
+ * See: https://developer.salesforce.com/docs/marketing/marketing-cloud/guide/postDataExtensionRowsetByKey.html
+ * And: inc-sev3-6609-sfmc-timeouts-in-bulk-batching-2023-10-23
+ * */
+ default: 50
}
From eb025c81b73e4d1a467f50cc6d69bff24ed56ef0 Mon Sep 17 00:00:00 2001
From: maryamsharif <99763167+maryamsharif@users.noreply.github.com>
Date: Tue, 24 Oct 2023 04:33:21 -0700
Subject: [PATCH 063/389] [The Trade Desk CRM] Avoid double hashing (#1681)
* Add logic for double hashing in TTD
* Add unit test
---
.../the-trade-desk-crm/functions.ts | 17 +-
.../syncAudience/__tests__/index.test.ts | 156 ++++++++++++++++++
2 files changed, 170 insertions(+), 3 deletions(-)
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
index 6a487f84b1..d42cbffd7d 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/functions.ts
@@ -109,8 +109,7 @@ function extractUsers(payloads: Payload[]): string {
}
if (payload.pii_type == 'EmailHashedUnifiedId2') {
- const normalizedEmail = normalizeEmail(payload.email)
- const hashedEmail = hash(normalizedEmail)
+ const hashedEmail = hash(payload.email)
users += `${hashedEmail}\n`
}
})
@@ -139,8 +138,20 @@ function normalizeEmail(email: string) {
}
export const hash = (value: string): string => {
+ const isSha256HashedEmail = /^[a-f0-9]{64}$/i.test(value)
+ const isBase64Hashed = /^[A-Za-z0-9+/]*={0,2}$/i.test(value)
+
+ if (isSha256HashedEmail) {
+ return Buffer.from(value, 'hex').toString('base64')
+ }
+
+ if (isBase64Hashed) {
+ return value
+ }
+
+ const normalizedEmail = normalizeEmail(value)
const hash = createHash('sha256')
- hash.update(value)
+ hash.update(normalizedEmail)
return hash.digest('base64')
}
diff --git a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
index 9763c0c1e2..9dc4bf7e8d 100644
--- a/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/the-trade-desk-crm/syncAudience/__tests__/index.test.ts
@@ -230,4 +230,160 @@ describe('TheTradeDeskCrm.syncAudience', () => {
})
).rejects.toThrow(`No external_id found in payload.`)
})
+
+ it('should not double hash an email that is already base64 encoded', async () => {
+ const dropReferenceId = 'aabbcc5b01-c9c7-4000-9191-000000000000'
+ const dropEndpoint = `https://thetradedesk-crm-data.s3.us-east-1.amazonaws.com/data/advertiser/advertiser-id/drop/${dropReferenceId}/pii?X-Amz-Security-Token=token&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=date&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=credentials&X-Amz-Signature=signature&`
+
+ nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id/crm_data_id`)
+ .post(/.*/, { PiiType: 'EmailHashedUnifiedId2', MergeMode: 'Replace', RetentionEnabled: true })
+ .reply(200, { ReferenceId: dropReferenceId, Url: dropEndpoint })
+
+ nock(dropEndpoint).put(/.*/).reply(200)
+
+ const events: SegmentEvent[] = []
+ for (let index = 1; index <= 1500; index++) {
+ events.push(
+ createTestEvent({
+ event: 'Audience Entered',
+ type: 'track',
+ properties: {
+ audience_key: 'personas_test_audience'
+ },
+ context: {
+ device: {
+ advertisingId: '123'
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
+ }
+ }
+ })
+ )
+ }
+
+ events.push(
+ createTestEvent({
+ event: 'Audience Entered',
+ type: 'track',
+ properties: {
+ audience_key: 'personas_test_audience'
+ },
+ context: {
+ device: {
+ advertisingId: '123'
+ },
+ traits: {
+ email: `yhI0QL7dpdaHFq6DEyKlqKPn2vj7KX91BQeqhniYRvI=`
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
+ }
+ }
+ })
+ )
+
+ const responses = await testDestination.testBatchAction('syncAudience', {
+ events,
+ settings: {
+ advertiser_id: 'advertiser_id',
+ auth_token: 'test_token',
+ __segment_internal_engage_force_full_sync: true,
+ __segment_internal_engage_batch_sync: true
+ },
+ features: {
+ [TTD_LEGACY_FLOW_FLAG_NAME]: true
+ },
+ useDefaultMappings: true,
+ mapping: {
+ name: 'test_audience',
+ region: 'US',
+ pii_type: 'EmailHashedUnifiedId2'
+ }
+ })
+
+ expect(responses.length).toBe(2)
+ expect(responses[1].options.body).toMatchInlineSnapshot(`
+ "yhI0QL7dpdaHFq6DEyKlqKPn2vj7KX91BQeqhniYRvI=
+ "
+ `)
+ })
+
+ it('should base64 encode a sha256 hashed email', async () => {
+ const dropReferenceId = 'aabbcc5b01-c9c7-4000-9191-000000000000'
+ const dropEndpoint = `https://thetradedesk-crm-data.s3.us-east-1.amazonaws.com/data/advertiser/advertiser-id/drop/${dropReferenceId}/pii?X-Amz-Security-Token=token&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Date=date&X-Amz-SignedHeaders=host&X-Amz-Expires=3600&X-Amz-Credential=credentials&X-Amz-Signature=signature&`
+
+ nock(`https://api.thetradedesk.com/v3/crmdata/segment/advertiser_id/crm_data_id`)
+ .post(/.*/, { PiiType: 'EmailHashedUnifiedId2', MergeMode: 'Replace', RetentionEnabled: true })
+ .reply(200, { ReferenceId: dropReferenceId, Url: dropEndpoint })
+
+ nock(dropEndpoint).put(/.*/).reply(200)
+
+ const events: SegmentEvent[] = []
+ for (let index = 1; index <= 1500; index++) {
+ events.push(
+ createTestEvent({
+ event: 'Audience Entered',
+ type: 'track',
+ properties: {
+ audience_key: 'personas_test_audience'
+ },
+ context: {
+ device: {
+ advertisingId: '123'
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
+ }
+ }
+ })
+ )
+ }
+
+ events.push(
+ createTestEvent({
+ event: 'Audience Entered',
+ type: 'track',
+ properties: {
+ audience_key: 'personas_test_audience'
+ },
+ context: {
+ device: {
+ advertisingId: '123'
+ },
+ traits: {
+ email: `ca123440bedda5d68716ae831322a5a8a3e7daf8fb297f750507aa86789846f2`
+ },
+ personas: {
+ external_audience_id: 'external_audience_id'
+ }
+ }
+ })
+ )
+
+ const responses = await testDestination.testBatchAction('syncAudience', {
+ events,
+ settings: {
+ advertiser_id: 'advertiser_id',
+ auth_token: 'test_token',
+ __segment_internal_engage_force_full_sync: true,
+ __segment_internal_engage_batch_sync: true
+ },
+ features: {
+ [TTD_LEGACY_FLOW_FLAG_NAME]: true
+ },
+ useDefaultMappings: true,
+ mapping: {
+ name: 'test_audience',
+ region: 'US',
+ pii_type: 'EmailHashedUnifiedId2'
+ }
+ })
+
+ expect(responses.length).toBe(2)
+ expect(responses[1].options.body).toMatchInlineSnapshot(`
+ "yhI0QL7dpdaHFq6DEyKlqKPn2vj7KX91BQeqhniYRvI=
+ "
+ `)
+ })
})
From 5a3271b6acee33a3959474fa6eafd524a95566f6 Mon Sep 17 00:00:00 2001
From: Elena
Date: Tue, 24 Oct 2023 04:34:41 -0700
Subject: [PATCH 064/389] Yahoo audiences update (#1679)
* Yahoo: added support for PHONE identifier
* Fixing unit tests.
* Yahoo: minor fixes - consolidated action code; fixed trigger rule, fixed email path, Oauth2 creds, unit test
* In Yahoo Audiences, grouping same user pairs into the same data entries, as requested by Elena.
* Yahoo: added DD logs
* Yahoo: clean up console.log
* Yahoo: refactored action field types
---------
Co-authored-by: Leonel Sanches <113376080+seg-leonelsanches@users.noreply.github.com>
---
.../yahoo-audiences/__tests__/index.test.ts | 97 ++++++++++++-
.../src/destinations/yahoo-audiences/index.ts | 51 +++++--
.../updateSegment/__tests__/index.test.ts | 2 +-
.../updateSegment/generated-types.ts | 12 +-
.../yahoo-audiences/updateSegment/index.ts | 102 ++++++++------
.../destinations/yahoo-audiences/utils-rt.ts | 132 ++++++++++++------
.../destinations/yahoo-audiences/utils-tax.ts | 13 +-
7 files changed, 297 insertions(+), 112 deletions(-)
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
index 91a368a99b..48135f65d7 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/__tests__/index.test.ts
@@ -2,6 +2,8 @@ import nock from 'nock'
import { IntegrationError, createTestIntegration } from '@segment/actions-core'
import Destination from '../index'
+import { gen_update_segment_payload } from '../utils-rt'
+import { Payload } from '../updateSegment/generated-types'
const AUDIENCE_ID = 'aud_123456789012345678901234567' // References audienceSettings.audience_id
const AUDIENCE_KEY = 'sneakers_buyers' // References audienceSettings.audience_key
@@ -18,44 +20,55 @@ const createAudienceInput = {
audienceName: '',
audienceSettings: {
audience_key: AUDIENCE_KEY,
- audience_id: AUDIENCE_ID
+ audience_id: AUDIENCE_ID,
+ identifier: ''
}
}
describe('Yahoo Audiences', () => {
describe('createAudience() function', () => {
let testDestination: any
+ const OLD_ENV = process.env
beforeEach(() => {
+ jest.resetModules() // Most important - it clears the cache
+ process.env = { ...OLD_ENV } // Make a copy
+ process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET = 'yoda'
+ process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID = 'luke'
testDestination = createTestIntegration(Destination)
})
+ afterAll(() => {
+ process.env = OLD_ENV // Restore old environment
+ })
+
describe('Success cases', () => {
- it.skip('It should create the audience successfully', async () => {
+ it('It should create the audience successfully', async () => {
nock('https://datax.yahooapis.com').put(`/v1/taxonomy/append/${ENGAGE_SPACE_ID}`).reply(202, {
anything: '123'
})
+ createAudienceInput.audienceSettings.identifier = 'anything'
const result = await testDestination.createAudience(createAudienceInput)
expect(result.externalId).toBe(AUDIENCE_ID)
})
})
describe('Failure cases', () => {
- it.skip('should throw an error when audience_id setting is missing', async () => {
+ it('should throw an error when audience_id setting is missing', async () => {
createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
createAudienceInput.audienceSettings.audience_id = ''
await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
})
- it.skip('should throw an error when audience_key setting is missing', async () => {
+ it('should throw an error when audience_key setting is missing', async () => {
createAudienceInput.settings.engage_space_id = 'acme_corp_engage_space'
createAudienceInput.audienceSettings.audience_key = ''
createAudienceInput.audienceSettings.audience_id = 'aud_12345'
await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
})
- it.skip('should throw an error when engage_space_id setting is missing', async () => {
+ it('should throw an error when engage_space_id setting is missing', async () => {
createAudienceInput.settings.engage_space_id = ''
createAudienceInput.audienceSettings.audience_key = 'sneakeres_buyers'
createAudienceInput.audienceSettings.audience_id = 'aud_123456789012345678901234567'
@@ -63,4 +76,78 @@ describe('Yahoo Audiences', () => {
})
})
})
+
+ describe('gen_update_segment_payload() function', () => {
+ describe('Success cases', () => {
+ const audienceSettings = {
+ audience_key: AUDIENCE_KEY,
+ audience_id: AUDIENCE_ID,
+ identifier: 'email'
+ }
+
+ it('trivial', () => {
+ // Given
+ const payloads: Payload[] = [{ gdpr_flag: false } as Payload]
+
+ // When
+ const result = gen_update_segment_payload(payloads, audienceSettings)
+
+ // Then
+ expect(result).toBeTruthy()
+ })
+
+ it('should group multiple payloads from the same user into one Yahoo event payload', () => {
+ // Given
+ const payloads: Payload[] = [
+ {
+ gdpr_flag: false,
+ segment_audience_id: 'aud_123',
+ segment_audience_key: 'sneakers_buyers',
+ segment_computation_action: 'enter',
+ email: 'bugsbunny@warnerbros.com',
+ advertising_id: '',
+ phone: '',
+ event_attributes: {
+ sneakers_buyers: true
+ },
+ identifier: 'email'
+ } as Payload,
+ {
+ gdpr_flag: false,
+ segment_audience_id: 'aud_234',
+ segment_audience_key: 'sneakers_buyers',
+ segment_computation_action: 'enter',
+ email: 'bugsbunny@warnerbros.com',
+ advertising_id: '',
+ phone: '',
+ event_attributes: {
+ sneakers_buyers: true
+ },
+ identifier: 'email'
+ } as Payload,
+ {
+ gdpr_flag: false,
+ segment_audience_id: 'aud_123',
+ segment_audience_key: 'sneakers_buyers',
+ segment_computation_action: 'enter',
+ email: 'daffyduck@warnerbros.com',
+ advertising_id: '',
+ phone: '',
+ event_attributes: {
+ sneakers_buyers: true
+ },
+ identifier: 'email'
+ } as Payload
+ ]
+
+ // When
+ const result = gen_update_segment_payload(payloads, audienceSettings)
+
+ // Then
+ expect(result).toBeTruthy()
+ expect(result.data.length).toBe(2)
+ expect((result.data as any)[0][4]).toContain(';')
+ })
+ })
+ })
})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
index 6435a378bd..79e7eedfa8 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/index.ts
@@ -50,12 +50,22 @@ const destination: AudienceDestinationDefinition = {
}
const body_form_data = gen_customer_taxonomy_payload(settings)
- await update_taxonomy('', tx_creds, request, body_form_data)
+ // The last 2 params are undefined because we don't have statsContext.statsClient and statsContext.tags in testAuthentication()
+ await update_taxonomy('', tx_creds, request, body_form_data, undefined, undefined)
},
refreshAccessToken: async (request, { auth }) => {
// Refresh Realtime API token (Oauth2 client_credentials)
- const rt_client_key = JSON.parse(auth.clientId)['rt_api']
- const rt_client_secret = JSON.parse(auth.clientSecret)['rt_api']
+ let rt_client_key = ''
+ let rt_client_secret = ''
+ // Added try-catch in a case we don't update the vault
+ try {
+ rt_client_key = JSON.parse(auth.clientId)['rt_api']
+ rt_client_secret = JSON.parse(auth.clientSecret)['rt_api']
+ } catch (err) {
+ rt_client_key = auth.clientId
+ rt_client_secret = auth.clientSecret
+ }
+
const jwt = generate_jwt(rt_client_key, rt_client_secret)
const res: ModifiedResponse = await request(
'https://id.b2b.yahooinc.com/identity/oauth2/access_token',
@@ -96,7 +106,11 @@ const destination: AudienceDestinationDefinition = {
choices: [
{ value: 'email', label: 'Send email' },
{ value: 'maid', label: 'Send MAID' },
- { value: 'email_maid', label: 'Send email and/or MAID' }
+ { value: 'phone', label: 'Send phone' },
+ { value: 'email_maid', label: 'Send email and/or MAID' },
+ { value: 'email_maid_phone', label: 'Send email, MAID and/or phone' },
+ { value: 'email_phone', label: 'Send email and/or phone' },
+ { value: 'phone_maid', label: 'Send phone and/or MAID' }
]
}
},
@@ -117,17 +131,35 @@ const destination: AudienceDestinationDefinition = {
const audience_key = createAudienceInput.audienceSettings?.audience_key
const engage_space_id = createAudienceInput.settings?.engage_space_id
const identifier = createAudienceInput.audienceSettings?.identifier
+ const statsClient = createAudienceInput?.statsContext?.statsClient
+ const statsTags = createAudienceInput?.statsContext?.tags
// The 3 errors below will be removed once we have Payload accessible by createAudience()
if (!audience_id) {
- throw new IntegrationError('Create Audience: missing audience Id value', 'MISSING_REQUIRED_FIELD', 400)
+ throw new IntegrationError(
+ 'Create Audience: missing audience setting "audience Id"',
+ 'MISSING_REQUIRED_FIELD',
+ 400
+ )
}
if (!audience_key) {
- throw new IntegrationError('Create Audience: missing audience key value', 'MISSING_REQUIRED_FIELD', 400)
+ throw new IntegrationError(
+ 'Create Audience: missing audience setting "audience key"',
+ 'MISSING_REQUIRED_FIELD',
+ 400
+ )
}
if (!engage_space_id) {
- throw new IntegrationError('Create Audience: missing Engage space Id type value', 'MISSING_REQUIRED_FIELD', 400)
+ throw new IntegrationError('Create Audience: missing setting "Engage space Id" ', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ if (!identifier) {
+ throw new IntegrationError(
+ 'Create Audience: missing audience setting "Identifier"',
+ 'MISSING_REQUIRED_FIELD',
+ 400
+ )
}
if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET) {
@@ -136,9 +168,6 @@ const destination: AudienceDestinationDefinition = {
if (!process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_ID) {
throw new IntegrationError('Missing Taxonomy API client Id', 'MISSING_REQUIRED_FIELD', 400)
}
- if (!identifier) {
- throw new IntegrationError('Create Audience: missing Identifier type value', 'MISSING_REQUIRED_FIELD', 400)
- }
const input = {
segment_audience_id: audience_id,
@@ -154,7 +183,7 @@ const destination: AudienceDestinationDefinition = {
tx_client_secret: process.env.ACTIONS_YAHOO_AUDIENCES_TAXONOMY_CLIENT_SECRET
}
- await update_taxonomy(engage_space_id, tx_creds, request, body_form_data)
+ await update_taxonomy(engage_space_id, tx_creds, request, body_form_data, statsClient, statsTags)
return { externalId: audience_id }
},
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
index bc53b14f04..8fe159117a 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/__tests__/index.test.ts
@@ -186,7 +186,7 @@ describe('YahooAudiences.updateSegment', () => {
customer_desc: CUST_DESC
}
})
- ).rejects.toThrow('Email and / or Advertising Id not available in the profile(s)')
+ ).rejects.toThrow('Selected identifier(s) not available in the event(s)')
})
})
})
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
index 6698ba6d84..0838f2f5a7 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/generated-types.ts
@@ -19,14 +19,6 @@ export interface Payload {
* Segment computation class used to determine if input event is from an Engage Audience'. Value must be = 'audience'.
*/
segment_computation_action: string
- /**
- * Enable batching of requests
- */
- enable_batching?: boolean
- /**
- * Maximum number of events to include in each batch. Actual batch sizes may be lower.
- */
- batch_size?: number
/**
* Email address of a user
*/
@@ -35,6 +27,10 @@ export interface Payload {
* User's mobile advertising Id
*/
advertising_id?: string
+ /**
+ * Phone number of a user
+ */
+ phone?: string
/**
* User's mobile device type
*/
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
index 8b80419ca6..d3632c0ee3 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/updateSegment/index.ts
@@ -1,4 +1,4 @@
-import type { ActionDefinition } from '@segment/actions-core'
+import type { ActionDefinition, RequestClient, StatsContext } from '@segment/actions-core'
import { IntegrationError, PayloadValidationError } from '@segment/actions-core'
import type { Settings, AudienceSettings } from '../generated-types'
import type { Payload } from './generated-types'
@@ -7,7 +7,7 @@ import { gen_update_segment_payload } from '../utils-rt'
const action: ActionDefinition = {
title: 'Sync To Yahoo Ads Segment',
description: 'Sync Segment Audience to Yahoo Ads Segment',
- defaultSubscription: 'type = "identify"',
+ defaultSubscription: 'type = "identify" or type = "track"',
fields: {
segment_audience_id: {
label: 'Segment Audience Id', // Maps to Yahoo Taxonomy Segment Id
@@ -56,20 +56,6 @@ const action: ActionDefinition = {
},
choices: [{ label: 'audience', value: 'audience' }]
},
- enable_batching: {
- label: 'Enable Batching',
- description: 'Enable batching of requests',
- type: 'boolean', // We should always batch Yahoo requests
- default: true,
- unsafe_hidden: true
- },
- batch_size: {
- label: 'Batch Size',
- description: 'Maximum number of events to include in each batch. Actual batch sizes may be lower.',
- type: 'number',
- unsafe_hidden: true,
- default: 1000
- },
email: {
label: 'User Email',
description: 'Email address of a user',
@@ -80,7 +66,7 @@ const action: ActionDefinition = {
'@if': {
exists: { '@path': '$.traits.email' },
then: { '@path': '$.traits.email' },
- else: { '@path': '$.properties.email' }
+ else: { '@path': '$.context.traits.email' }
}
}
},
@@ -94,6 +80,20 @@ const action: ActionDefinition = {
},
required: false
},
+ phone: {
+ label: 'User Phone',
+ description: 'Phone number of a user',
+ type: 'string',
+ unsafe_hidden: true,
+ required: false,
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.phone' },
+ then: { '@path': '$.traits.phone' },
+ else: { '@path': '$.context.traits.phone' }
+ }
+ }
+ },
device_type: {
label: 'User Mobile Device Type', // This field is required to determine the type of the advertising Id: IDFA or GAID
description: "User's mobile device type",
@@ -113,7 +113,11 @@ const action: ActionDefinition = {
choices: [
{ value: 'email', label: 'Send email' },
{ value: 'maid', label: 'Send MAID' },
- { value: 'email_maid', label: 'Send email and/or MAID' }
+ { value: 'phone', label: 'Send phone' },
+ { value: 'email_maid', label: 'Send email and/or MAID' },
+ { value: 'email_maid_phone', label: 'Send email, MAID and/or phone' },
+ { value: 'email_phone', label: 'Send email and/or phone' },
+ { value: 'phone_maid', label: 'Send phone and/or MAID' }
]
},
gdpr_flag: {
@@ -132,44 +136,50 @@ const action: ActionDefinition = {
}
},
- perform: (request, { payload, auth, audienceSettings }) => {
+ perform: (request, { payload, auth, audienceSettings, statsContext }) => {
const rt_access_token = auth?.accessToken
if (!audienceSettings) {
throw new IntegrationError('Bad Request: no audienceSettings found.', 'INVALID_REQUEST_DATA', 400)
}
- const body = gen_update_segment_payload([payload], audienceSettings)
- // Send request to Yahoo only when the event includes selected Ids
- if (body.data.length > 0) {
- return request('https://dataxonline.yahoo.com/online/audience/', {
- method: 'POST',
- json: body,
- headers: {
- Authorization: `Bearer ${rt_access_token}`
- }
- })
- } else {
- throw new PayloadValidationError('Email and / or Advertising Id not available in the profile(s)')
- }
+ return process_payload(request, [payload], rt_access_token, audienceSettings, statsContext)
},
- performBatch: (request, { payload, audienceSettings, auth }) => {
+ performBatch: (request, { payload, audienceSettings, auth, statsContext }) => {
const rt_access_token = auth?.accessToken
-
if (!audienceSettings) {
throw new IntegrationError('Bad Request: no audienceSettings found.', 'INVALID_REQUEST_DATA', 400)
}
- const body = gen_update_segment_payload(payload, audienceSettings)
- // Send request to Yahoo only when all events in the batch include selected Ids
- if (body.data.length > 0) {
- return request('https://dataxonline.yahoo.com/online/audience/', {
- method: 'POST',
- json: body,
- headers: {
- Authorization: `Bearer ${rt_access_token}`
- }
- })
- } else {
- throw new PayloadValidationError('Email and / or Advertising Id not available in the profile(s)')
+ return process_payload(request, payload, rt_access_token, audienceSettings, statsContext)
+ }
+}
+
+async function process_payload(
+ request: RequestClient,
+ payload: Payload[],
+ token: string | undefined,
+ audienceSettings: AudienceSettings,
+ statsContext: StatsContext | undefined
+) {
+ const body = gen_update_segment_payload(payload, audienceSettings)
+ const statsClient = statsContext?.statsClient
+ const statsTag = statsContext?.tags
+ // Send request to Yahoo only when all events in the batch include selected Ids
+ if (body.data.length > 0) {
+ if (statsClient && statsTag) {
+ statsClient?.incr('yahoo_audiences', 1, [...statsTag, 'action:updateSegmentTriggered'])
+ statsClient?.incr('yahoo_audiences', body.data.length, [...statsTag, 'action:updateSegmentRecordsSent'])
+ }
+ return request('https://dataxonline.yahoo.com/online/audience/', {
+ method: 'POST',
+ json: body,
+ headers: {
+ Authorization: `Bearer ${token}`
+ }
+ })
+ } else {
+ if (statsClient && statsTag) {
+ statsClient?.incr('yahoo_audiences', 1, [...statsTag, 'action:updateSegmentDiscarded'])
}
+ throw new PayloadValidationError('Selected identifier(s) not available in the event(s)')
}
}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts b/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
index 67e397c08c..cf477e8250 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/utils-rt.ts
@@ -49,50 +49,67 @@ export function generate_jwt(client_id: string, client_secret: string): string {
}
/**
- * Gets the definition to send the hashed email or advertising ID.
+ * Gets the definition to send the hashed email, phone or advertising ID.
* @param payload The payload.
* @returns {{ maid: boolean; email: boolean }} The definitions object (id_schema).
*/
-export function get_id_schema(payload: Payload, audienceSettings: AudienceSettings): { maid: boolean; email: boolean } {
+export function get_id_schema(
+ payload: Payload,
+ audienceSettings: AudienceSettings
+): { maid: boolean; email: boolean; phone: boolean } {
const schema = {
email: false,
- maid: false
+ maid: false,
+ phone: false
}
let id_type
audienceSettings.identifier ? (id_type = audienceSettings.identifier) : (id_type = payload.identifier)
- if (id_type == 'email') {
- schema.email = true
- }
- if (id_type == 'maid') {
- schema.maid = true
- }
- if (id_type == 'email_maid') {
- schema.maid = true
- schema.email = true
+ switch (id_type) {
+ case 'email':
+ schema.email = true
+ break
+ case 'maid':
+ schema.maid = true
+ break
+ case 'phone':
+ schema.phone = true
+ break
+ case 'email_maid':
+ schema.maid = true
+ schema.email = true
+ break
+ case 'email_maid_phone':
+ schema.maid = true
+ schema.email = true
+ schema.phone = true
+ break
+ case 'email_phone':
+ schema.email = true
+ schema.phone = true
+ break
+ case 'phone_maid':
+ schema.phone = true
+ schema.maid = true
+ break
}
+
return schema
- // return {
- // maid: payload.send_advertising_id === true,
- // email: payload.send_email === true
- // }
}
-/**
- * Validates the payload schema.
- * If both `Send Email` and `Send Advertising ID` are set to `false`, an error is thrown.
- * @param payload The payload.
- */
-// Switched over to a 'choice' field, so this function is no longer required
-// export function check_schema(payload: Payload): void {
-// payload.identifier
-// if (payload.send_email === false && payload.send_advertising_id === false) {
-// throw new IntegrationError(
-// 'Either `Send Email`, or `Send Advertising ID` setting must be set to `true`.',
-// 'INVALID_SETTINGS',
-// 400
-// )
-// }
-// }
+export function validate_phone(phone: string) {
+ /*
+ Phone must match E.164 format: a number up to 15 digits in length starting with a ‘+’
+ - remove any non-numerical characters
+ - check length
+ - if phone doesn't match the criteria - drop the value, otherwise - return the value prepended with a '+'
+ */
+ const phone_num = phone.replace(/\D/g, '')
+ if (phone_num.length <= 15 && phone_num.length >= 1) {
+ return '+' + phone_num
+ } else {
+ return ''
+ }
+}
/**
* The ID schema defines whether the payload should contain the
@@ -102,11 +119,19 @@ export function get_id_schema(payload: Payload, audienceSettings: AudienceSettin
*/
export function gen_update_segment_payload(payloads: Payload[], audienceSettings: AudienceSettings): YahooPayload {
const schema = get_id_schema(payloads[0], audienceSettings)
+ const data_groups: {
+ [hashed_email: string]: {
+ exp: string
+ seg_id: string
+ ts: string
+ }[]
+ } = {}
const data = []
+ //
for (const event of payloads) {
let hashed_email: string | undefined = ''
if (schema.email === true && event.email) {
- hashed_email = create_hash(event.email)
+ hashed_email = create_hash(event.email.toLowerCase())
}
let idfa: string | undefined = ''
let gpsaid: string | undefined = ''
@@ -120,8 +145,14 @@ export function gen_update_segment_payload(payloads: Payload[], audienceSettings
break
}
}
-
- if (hashed_email == '' && idfa == '' && gpsaid == '') {
+ let hashed_phone: string | undefined = ''
+ if (schema.phone === true && event.phone) {
+ const phone = validate_phone(event.phone)
+ if (phone !== '') {
+ hashed_phone = create_hash(phone)
+ }
+ }
+ if (hashed_email === '' && idfa === '' && gpsaid === '' && hashed_phone === '') {
continue
}
const ts = Math.floor(new Date().getTime() / 1000)
@@ -137,16 +168,39 @@ export function gen_update_segment_payload(payloads: Payload[], audienceSettings
}
const seg_id = event.segment_audience_id
- data.push([hashed_email, idfa, gpsaid, 'exp=' + exp + '&seg_id=' + seg_id + '&ts=' + ts])
+
+ const group_key = `${hashed_email}|${idfa}|${gpsaid}|${hashed_phone}`
+ if (!(group_key in data_groups)) {
+ data_groups[group_key] = []
+ }
+
+ data_groups[group_key].push({
+ exp: String(exp),
+ seg_id: seg_id,
+ ts: String(ts)
+ })
}
+ for (const [key, grouped_values] of Object.entries(data_groups)) {
+ const [hashed_email, idfa, gpsaid, hashed_phone] = key.split('|')
+ let action_string = ''
+ for (const values of grouped_values) {
+ action_string += 'exp=' + values.exp + '&seg_id=' + values.seg_id + '&ts=' + values.ts + ';'
+ }
+
+ action_string = action_string.slice(0, -1)
+ data.push([hashed_email, idfa, gpsaid, hashed_phone, action_string])
+ }
+
+ const gdpr_flag = payloads.length > 0 ? payloads[0].gdpr_flag : false
+
const yahoo_payload: YahooPayload = {
- schema: ['SHA256EMAIL', 'IDFA', 'GPADVID', 'SEGMENTS'],
+ schema: ['SHA256EMAIL', 'IDFA', 'GPADVID', 'HASHEDID', 'SEGMENTS'],
data: data,
- gdpr: payloads[0].gdpr_flag
+ gdpr: gdpr_flag
}
- if (payloads[0].gdpr_flag) {
+ if (gdpr_flag && payloads.length > 0) {
yahoo_payload.gdpr_euconsent = payloads[0].gdpr_euconsent
}
diff --git a/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
index bf10905d3e..c34fb04a25 100644
--- a/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
+++ b/packages/destination-actions/src/destinations/yahoo-audiences/utils-tax.ts
@@ -2,6 +2,7 @@ import type { Settings } from './generated-types'
import { createHmac } from 'crypto'
import { CredsObj, YahooSubTaxonomy } from './types'
import { RequestClient, IntegrationError } from '@segment/actions-core'
+import { StatsClient } from '@segment/actions-core/destination-kit'
export function gen_customer_taxonomy_payload(settings: Settings) {
const data = {
@@ -70,7 +71,9 @@ export async function update_taxonomy(
engage_space_id: string,
tx_creds: CredsObj,
request: RequestClient,
- body_form_data: string
+ body_form_data: string,
+ statsClient: StatsClient | undefined,
+ statsTags: string[] | undefined
) {
const tx_client_secret = tx_creds.tx_client_secret
const tx_client_key = tx_creds.tx_client_key
@@ -85,11 +88,17 @@ export async function update_taxonomy(
'Content-Type': 'multipart/form-data; boundary=SEGMENT-DATA'
}
})
+ if (statsClient && statsTags) {
+ statsClient.incr('yahoo_audiences', 1, [...statsTags, 'util:update_taxonomy.success'])
+ }
return await add_segment_node.json()
} catch (error) {
const _error = error as { response: { data: unknown; status: string } }
+ if (statsClient && statsTags) {
+ statsClient.incr('yahoo_audiences', 1, [...statsTags, `util:update_taxonomy.error_${_error.response.status}`])
+ }
// If Taxonomy API returned 401, throw Integration error w/status 400 to prevent refreshAccessToken from firing
- // Otherwise throw the orifinal error
+ // Otherwise throw the original error
if (parseInt(_error.response.status) == 401) {
throw new IntegrationError(
`Error while updating taxonomy: ${JSON.stringify(_error.response.data)} ${
From bf5a27df241fe594ca2a018dd90a743e17ff0ef2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Mar=C3=ADn=20Alcaraz?=
Date: Tue, 24 Oct 2023 04:35:38 -0700
Subject: [PATCH 065/389] DV360: createAudience/getAudience (#1675)
---
.../display-video-360/__tests__/index.test.ts | 147 +++++++++++++++++-
.../display-video-360/constants.ts | 4 +
.../display-video-360/generated-types.ts | 8 +
.../destinations/display-video-360/index.ts | 123 ++++++++++++++-
4 files changed, 276 insertions(+), 6 deletions(-)
create mode 100644 packages/destination-actions/src/destinations/display-video-360/constants.ts
diff --git a/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts b/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
index d08b980f5c..ad6cf19e71 100644
--- a/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
+++ b/packages/destination-actions/src/destinations/display-video-360/__tests__/index.test.ts
@@ -1,5 +1,148 @@
+import nock from 'nock'
+import { createTestIntegration, IntegrationError } from '@segment/actions-core'
+import Destination from '../index'
+import { GET_AUDIENCE_URL, CREATE_AUDIENCE_URL } from '../constants'
+
+const advertiserId = '424242'
+const audienceName = 'The Super Mario Brothers Fans'
+const testDestination = createTestIntegration(Destination)
+const advertiserCreateAudienceUrl = CREATE_AUDIENCE_URL.replace('advertiserID', advertiserId)
+const advertiserGetAudienceUrl = GET_AUDIENCE_URL.replace('advertiserID', advertiserId)
+const expectedExternalID = `products/DISPLAY_VIDEO_ADVERTISER/customers/${advertiserId}/userLists/8457147615`
+
+const createAudienceInput = {
+ settings: {},
+ audienceName: '',
+ audienceSettings: {
+ advertiserId: advertiserId
+ }
+}
+
+const getAudienceInput = {
+ settings: {},
+ audienceSettings: {
+ advertiserId: advertiserId
+ },
+ audienceName: audienceName,
+ externalId: expectedExternalID
+}
+
+const getAudienceResponse = [
+ {
+ results: [
+ {
+ userList: {
+ resourceName: expectedExternalID,
+ membershipStatus: 'OPEN',
+ name: audienceName,
+ description: 'Created by Segment.'
+ }
+ }
+ ],
+ fieldMask: 'userList.name,userList.description,userList.membershipStatus,userList.matchRatePercentage',
+ requestId: 'Hw7-_h0P-vCzQ'
+ }
+]
+
describe('Display Video 360', () => {
- it('is a placeholder for an actual test', () => {
- expect(true).toBe(true)
+ describe('createAudience', () => {
+ it('should fail if no audience name is set', async () => {
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('should fail if no advertiser ID is set', async () => {
+ createAudienceInput.audienceName = 'The Void'
+ createAudienceInput.audienceSettings.advertiserId = ''
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('creates an audience', async () => {
+ nock(advertiserCreateAudienceUrl)
+ .post(/.*/)
+ .reply(200, {
+ results: [
+ {
+ resourceName: `products/DISPLAY_VIDEO_ADVERTISER/customers/${advertiserId}/userLists/8460733279`
+ }
+ ]
+ })
+
+ createAudienceInput.audienceName = audienceName
+ createAudienceInput.audienceSettings.advertiserId = advertiserId
+
+ const r = await testDestination.createAudience(createAudienceInput)
+ expect(r).toEqual({
+ externalId: `products/DISPLAY_VIDEO_ADVERTISER/customers/${advertiserId}/userLists/8460733279`
+ })
+ })
+
+ it('errors out when audience with same name already exists', async () => {
+ nock(advertiserCreateAudienceUrl)
+ .post(/.*/)
+ .reply(400, {
+ error: {
+ code: 400,
+ message: 'Request contains an invalid argument.',
+ status: 'INVALID_ARGUMENT',
+ details: [
+ {
+ '@type': 'type.googleapis.com/google.ads.audiencepartner.v2.errors.AudiencePartnerFailure',
+ errors: [
+ {
+ errorCode: {
+ userListError: 'NAME_ALREADY_USED'
+ },
+ message: 'Name is already being used for another user list for the account.',
+ trigger: {
+ stringValue: audienceName
+ },
+ location: {
+ fieldPathElements: [
+ {
+ fieldName: 'operations',
+ index: 0
+ },
+ {
+ fieldName: 'create'
+ },
+ {
+ fieldName: 'name'
+ }
+ ]
+ }
+ }
+ ],
+ requestId: 'gMjeoMWem82kFnHKBnmzsA'
+ }
+ ]
+ }
+ })
+
+ createAudienceInput.audienceName = audienceName
+ createAudienceInput.audienceSettings.advertiserId = advertiserId
+
+ await expect(testDestination.createAudience(createAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+ })
+
+ describe('getAudience', () => {
+ it("should fail if Segment Audience ID doesn't match Google Audience ID", async () => {
+ const bogusGetAudienceInput = {
+ ...getAudienceInput,
+ externalId: 'bogus'
+ }
+
+ nock(advertiserGetAudienceUrl).post(/.*/).reply(200, getAudienceResponse)
+ await expect(testDestination.getAudience(bogusGetAudienceInput)).rejects.toThrowError(IntegrationError)
+ })
+
+ it('should succeed when Segment Audience ID matches Google audience ID', async () => {
+ nock(advertiserGetAudienceUrl).post(/.*/).reply(200, getAudienceResponse)
+
+ const r = await testDestination.getAudience(getAudienceInput)
+ expect(r).toEqual({
+ externalId: expectedExternalID
+ })
+ })
})
})
diff --git a/packages/destination-actions/src/destinations/display-video-360/constants.ts b/packages/destination-actions/src/destinations/display-video-360/constants.ts
new file mode 100644
index 0000000000..78de1281a4
--- /dev/null
+++ b/packages/destination-actions/src/destinations/display-video-360/constants.ts
@@ -0,0 +1,4 @@
+export const GOOGLE_API_VERSION = 'v2'
+export const BASE_URL = `https://audiencepartner.googleapis.com/${GOOGLE_API_VERSION}/products/DISPLAY_VIDEO_ADVERTISER/customers/advertiserID/`
+export const CREATE_AUDIENCE_URL = `${BASE_URL}userLists:mutate`
+export const GET_AUDIENCE_URL = `${BASE_URL}audiencePartner:searchStream`
diff --git a/packages/destination-actions/src/destinations/display-video-360/generated-types.ts b/packages/destination-actions/src/destinations/display-video-360/generated-types.ts
index 4ab2786ec6..99e24e4b6b 100644
--- a/packages/destination-actions/src/destinations/display-video-360/generated-types.ts
+++ b/packages/destination-actions/src/destinations/display-video-360/generated-types.ts
@@ -1,3 +1,11 @@
// Generated file. DO NOT MODIFY IT BY HAND.
export interface Settings {}
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface AudienceSettings {
+ /**
+ * The ID of your advertiser, used throughout Display & Video 360. Use this ID when you contact Display & Video 360 support to help our teams locate your specific account.
+ */
+ advertiserId?: string
+}
diff --git a/packages/destination-actions/src/destinations/display-video-360/index.ts b/packages/destination-actions/src/destinations/display-video-360/index.ts
index 455024ccbd..77829d451b 100644
--- a/packages/destination-actions/src/destinations/display-video-360/index.ts
+++ b/packages/destination-actions/src/destinations/display-video-360/index.ts
@@ -1,14 +1,129 @@
-import type { DestinationDefinition } from '@segment/actions-core'
-import type { Settings } from './generated-types'
+import { AudienceDestinationDefinition, IntegrationError } from '@segment/actions-core'
+import type { Settings, AudienceSettings } from './generated-types'
import addToAudience from './addToAudience'
-
import removeFromAudience from './removeFromAudience'
-const destination: DestinationDefinition = {
+import { CREATE_AUDIENCE_URL, GET_AUDIENCE_URL } from './constants'
+
+const destination: AudienceDestinationDefinition = {
name: 'Display and Video 360 (Actions)',
slug: 'actions-display-video-360',
mode: 'cloud',
+ extendRequest() {
+ // TODO: extendRequest doesn't work within createAudience and getAudience
+ return {}
+ },
+ audienceFields: {
+ advertiserId: {
+ type: 'string',
+ label: 'Advertiser ID',
+ description:
+ 'The ID of your advertiser, used throughout Display & Video 360. Use this ID when you contact Display & Video 360 support to help our teams locate your specific account.'
+ }
+ },
+ audienceConfig: {
+ mode: {
+ type: 'synced',
+ full_audience_sync: true
+ },
+ async createAudience(request, createAudienceInput) {
+ const audienceName = createAudienceInput.audienceName
+ const advertiserId = createAudienceInput.audienceSettings?.advertiserId
+ const statsClient = createAudienceInput?.statsContext?.statsClient
+ const statsTags = createAudienceInput?.statsContext?.tags
+
+ if (!audienceName) {
+ throw new IntegrationError('Missing audience name value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ if (!advertiserId) {
+ throw new IntegrationError('Missing advertiser ID value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ const partnerCreateAudienceUrl = CREATE_AUDIENCE_URL.replace('advertiserID', advertiserId)
+ let response
+ try {
+ response = await request(partnerCreateAudienceUrl, {
+ method: 'POST',
+ headers: {
+ // 'Authorization': `Bearer ${authToken}`, // TODO: Replace with auth token
+ 'Content-Type': 'application/json',
+ 'Login-Customer-Id': `products/DISPLAY_VIDEO_ADVERTISER/customers/${advertiserId}`
+ },
+ json: {
+ operations: [
+ {
+ create: {
+ basicUserList: {},
+ name: audienceName,
+ description: 'Created by Segment',
+ membershipStatus: 'OPEN',
+ type: 'REMARKETING',
+ membershipLifeSpan: '540'
+ }
+ }
+ ]
+ }
+ })
+ } catch (error) {
+ const errorMessage = await JSON.parse(error.response.content).error.details[0].errors[0].message
+ statsClient?.incr('createAudience.error', 1, statsTags)
+ throw new IntegrationError(errorMessage, 'INVALID_RESPONSE', 400)
+ }
+
+ const r = await response.json()
+ statsClient?.incr('createAudience.success', 1, statsTags)
+
+ return {
+ externalId: r['results'][0]['resourceName']
+ }
+ },
+ async getAudience(request, getAudienceInput) {
+ const statsClient = getAudienceInput?.statsContext?.statsClient
+ const statsTags = getAudienceInput?.statsContext?.tags
+ const advertiserId = getAudienceInput.audienceSettings?.advertiserId
+
+ if (!advertiserId) {
+ throw new IntegrationError('Missing required advertiser ID value', 'MISSING_REQUIRED_FIELD', 400)
+ }
+
+ const advertiserGetAudienceUrl = GET_AUDIENCE_URL.replace('advertiserID', advertiserId)
+ const response = await request(advertiserGetAudienceUrl, {
+ headers: {
+ // 'Authorization': `Bearer ${authToken}`, // TODO: Replace with auth token
+ 'Content-Type': 'application/json',
+ 'Login-Customer-Id': `products/DISPLAY_VIDEO_ADVERTISER/customers/${advertiserId}`
+ },
+ method: 'POST',
+ json: {
+ query: `SELECT user_list.name, user_list.description, user_list.membership_status, user_list.match_rate_percentage FROM user_list WHERE user_list.resource_name = "${getAudienceInput.externalId}"`
+ }
+ })
+
+ const r = await response.json()
+
+ if (response.status !== 200) {
+ statsClient?.incr('getAudience.error', 1, statsTags)
+ throw new IntegrationError('Invalid response from get audience request', 'INVALID_RESPONSE', 400)
+ }
+
+ const externalId = r[0]?.results[0]?.userList?.resourceName
+
+ if (externalId !== getAudienceInput.externalId) {
+ throw new IntegrationError(
+ "Unable to verify ownership over audience. Segment Audience ID doesn't match Googles Audience ID.",
+ 'INVALID_REQUEST_DATA',
+ 400
+ )
+ }
+
+ statsClient?.incr('getAudience.success', 1, statsTags)
+ return {
+ externalId: externalId
+ }
+ }
+ },
actions: {
addToAudience,
removeFromAudience
From a817582687c87f2a9f2d4ddabf00eda098db9a0d Mon Sep 17 00:00:00 2001
From: Thomas Gilbert <64277654+tcgilbert@users.noreply.github.com>
Date: Tue, 24 Oct 2023 07:36:15 -0400
Subject: [PATCH 066/389] adding us 07 instance (#1674)
---
.../destination-actions/src/destinations/braze-cohorts/index.ts | 1 +
1 file changed, 1 insertion(+)
diff --git a/packages/destination-actions/src/destinations/braze-cohorts/index.ts b/packages/destination-actions/src/destinations/braze-cohorts/index.ts
index 4e20e7c4d4..7fc61e4790 100644
--- a/packages/destination-actions/src/destinations/braze-cohorts/index.ts
+++ b/packages/destination-actions/src/destinations/braze-cohorts/index.ts
@@ -29,6 +29,7 @@ const destination: DestinationDefinition = {
{ label: 'US-04 (https://dashboard-04.braze.com)', value: 'https://rest.iad-04.braze.com' },
{ label: 'US-05 (https://dashboard-05.braze.com)', value: 'https://rest.iad-05.braze.com' },
{ label: 'US-06 (https://dashboard-06.braze.com)', value: 'https://rest.iad-06.braze.com' },
+ { label: 'US-07 (https://dashboard-07.braze.com)', value: 'https://rest.iad-07.braze.com' },
{ label: 'US-08 (https://dashboard-08.braze.com)', value: 'https://rest.iad-08.braze.com' },
{ label: 'EU-01 (https://dashboard-01.braze.eu)', value: 'https://rest.fra-01.braze.eu' },
{ label: 'EU-02 (https://dashboard-02.braze.eu)', value: 'https://rest.fra-02.braze.eu' }
From 777cfde66748d537f7e5e20453af21d274090eb2 Mon Sep 17 00:00:00 2001
From: rhall-twilio <103517471+rhall-twilio@users.noreply.github.com>
Date: Tue, 24 Oct 2023 06:36:46 -0500
Subject: [PATCH 067/389] STRATCONN-2921 braze: add support for merge_behavior
(#1669)
* braze: add support for merge_behavior
* add missing dropdown labels
---
.../__snapshots__/snapshot.test.ts.snap | 15 ++++++++
.../identifyUser/__tests__/snapshot.test.ts | 34 +++++++++++++++++++
.../braze/identifyUser/generated-types.ts | 4 +++
.../destinations/braze/identifyUser/index.ts | 13 ++++++-
4 files changed, 65 insertions(+), 1 deletion(-)
diff --git a/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/__snapshots__/snapshot.test.ts.snap
index c20fec87ec..8a41ddd358 100644
--- a/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/__snapshots__/snapshot.test.ts.snap
+++ b/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -11,6 +11,7 @@ Object {
},
},
],
+ "merge_behavior": "merge",
}
`;
@@ -27,3 +28,17 @@ Object {
],
}
`;
+
+exports[`all fields - backwards compatibility testing 1`] = `
+Object {
+ "aliases_to_identify": Array [
+ Object {
+ "external_id": "L6iTV8uKjdSaPxy2fjx9",
+ "user_alias": Object {
+ "alias_label": "L6iTV8uKjdSaPxy2fjx9",
+ "alias_name": "L6iTV8uKjdSaPxy2fjx9",
+ },
+ },
+ ],
+}
+`;
diff --git a/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/snapshot.test.ts
index aab7286ee3..c4035df309 100644
--- a/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/snapshot.test.ts
+++ b/packages/destination-actions/src/destinations/braze/identifyUser/__tests__/snapshot.test.ts
@@ -73,3 +73,37 @@ describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination ac
}
})
})
+
+it('all fields - backwards compatibility testing', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ // make sure existing destinations payload did not change if they don't have merge_behavior defined
+ delete eventData.merge_behavior
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+})
diff --git a/packages/destination-actions/src/destinations/braze/identifyUser/generated-types.ts b/packages/destination-actions/src/destinations/braze/identifyUser/generated-types.ts
index 9fd2401d27..257ab73994 100644
--- a/packages/destination-actions/src/destinations/braze/identifyUser/generated-types.ts
+++ b/packages/destination-actions/src/destinations/braze/identifyUser/generated-types.ts
@@ -12,4 +12,8 @@ export interface Payload {
alias_name: string
alias_label: string
}
+ /**
+ * Sets the endpoint to merge some fields found exclusively on the anonymous user to the identified user. See [the docs](https://www.braze.com/docs/api/endpoints/user_data/post_user_identify/#request-parameters).
+ */
+ merge_behavior?: string
}
diff --git a/packages/destination-actions/src/destinations/braze/identifyUser/index.ts b/packages/destination-actions/src/destinations/braze/identifyUser/index.ts
index ac88f02f17..af2336dce9 100644
--- a/packages/destination-actions/src/destinations/braze/identifyUser/index.ts
+++ b/packages/destination-actions/src/destinations/braze/identifyUser/index.ts
@@ -31,6 +31,16 @@ const action: ActionDefinition = {
required: true
}
}
+ },
+ merge_behavior: {
+ label: 'Merge Behavior',
+ description:
+ 'Sets the endpoint to merge some fields found exclusively on the anonymous user to the identified user. See [the docs](https://www.braze.com/docs/api/endpoints/user_data/post_user_identify/#request-parameters).',
+ type: 'string',
+ choices: [
+ { value: 'none', label: 'None' },
+ { value: 'merge', label: 'Merge' }
+ ]
}
},
perform: (request, { settings, payload }) => {
@@ -42,7 +52,8 @@ const action: ActionDefinition = {
external_id: payload.external_id,
user_alias: payload.user_alias
}
- ]
+ ],
+ ...(payload.merge_behavior !== undefined && { merge_behavior: payload.merge_behavior })
}
})
}
From 1aacf4e174b80eaf05a5ed40e40b754b987f8062 Mon Sep 17 00:00:00 2001
From: Ankit Gupta <139338151+AnkitSegment@users.noreply.github.com>
Date: Tue, 24 Oct 2023 17:07:23 +0530
Subject: [PATCH 068/389] Stratconn 3130 dynamic field google enhanced
conversion (#1594)
* Added dynamic field for Google conversions api
* Added dynamic field for Google enhanced conversions
* Refactored code
* refactor imports
* Test cased for google enhanced conversions api dynamic field added
* Code refactored
* Changed description of conversion action field
* removed unnecessary file
---
.../__tests__/functions.test.ts | 57 +++++++++++++++++
.../google-enhanced-conversions/functions.ts | 61 ++++++++++++++++++-
.../google-enhanced-conversions/types.ts | 14 +++++
.../uploadCallConversion/generated-types.ts | 2 +-
.../uploadCallConversion/index.ts | 17 ++++--
.../uploadClickConversion/generated-types.ts | 2 +-
.../uploadClickConversion/index.ts | 24 ++++++--
.../generated-types.ts | 2 +-
.../uploadConversionAdjustment/index.ts | 24 ++++++--
9 files changed, 182 insertions(+), 21 deletions(-)
create mode 100644 packages/destination-actions/src/destinations/google-enhanced-conversions/__tests__/functions.test.ts
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/__tests__/functions.test.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/__tests__/functions.test.ts
new file mode 100644
index 0000000000..a29dc0318e
--- /dev/null
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/__tests__/functions.test.ts
@@ -0,0 +1,57 @@
+import { createTestIntegration, DynamicFieldResponse } from '@segment/actions-core'
+import destination from '../index'
+
+const testDestination = createTestIntegration(destination)
+
+const auth = {
+ refreshToken: 'xyz321',
+ accessToken: 'abc123'
+}
+
+describe('.getConversionActionId', () => {
+ it('should dynamically fetch event keys for uploadClickConversion action', async () => {
+ const settings = {
+ customerId: '12345678'
+ }
+ const payload = {}
+ const responses = (await testDestination.testDynamicField('uploadClickConversion', 'conversion_action', {
+ settings,
+ payload,
+ auth
+ })) as DynamicFieldResponse
+
+ expect(responses.choices.length).toBeGreaterThanOrEqual(0)
+ })
+})
+
+describe('.getConversionActionId', () => {
+ it('should dynamically fetch event keys for uploadCallConversion action', async () => {
+ const settings = {
+ customerId: '12345678'
+ }
+ const payload = {}
+ const responses = (await testDestination.testDynamicField('uploadCallConversion', 'conversion_action', {
+ settings,
+ payload,
+ auth
+ })) as DynamicFieldResponse
+
+ expect(responses.choices.length).toBeGreaterThanOrEqual(0)
+ })
+})
+
+describe('.getConversionActionId', () => {
+ it('should dynamically fetch event keys for uploadConversionAdjustment action', async () => {
+ const settings = {
+ customerId: '12345678'
+ }
+ const payload = {}
+ const responses = (await testDestination.testDynamicField('uploadConversionAdjustment', 'conversion_action', {
+ settings,
+ payload,
+ auth
+ })) as DynamicFieldResponse
+
+ expect(responses.choices.length).toBeGreaterThanOrEqual(0)
+ })
+})
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/functions.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/functions.ts
index c7fa329282..2cb29f8ecb 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/functions.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/functions.ts
@@ -1,6 +1,19 @@
import { createHash } from 'crypto'
-import { ConversionCustomVariable, PartialErrorResponse, QueryResponse } from './types'
-import { ModifiedResponse, RequestClient, IntegrationError, PayloadValidationError } from '@segment/actions-core'
+import {
+ ConversionCustomVariable,
+ PartialErrorResponse,
+ QueryResponse,
+ ConversionActionId,
+ ConversionActionResponse
+} from './types'
+import {
+ ModifiedResponse,
+ RequestClient,
+ IntegrationError,
+ PayloadValidationError,
+ DynamicFieldResponse,
+ APIError
+} from '@segment/actions-core'
import { StatsContext } from '@segment/actions-core/destination-kit'
import { Features } from '@segment/actions-core/mapping-kit'
import { fullFormats } from 'ajv-formats/dist/formats'
@@ -69,6 +82,50 @@ export async function getCustomVariables(
)
}
+export async function getConversionActionId(
+ customerId: string | undefined,
+ auth: any,
+ request: RequestClient
+): Promise> {
+ return request(`https://googleads.googleapis.com/v14/customers/${customerId}/googleAds:searchStream`, {
+ method: 'post',
+ headers: {
+ authorization: `Bearer ${auth?.accessToken}`,
+ 'developer-token': `${process.env.ADWORDS_DEVELOPER_TOKEN}`
+ },
+ json: {
+ query: `SELECT conversion_action.id, conversion_action.name FROM conversion_action`
+ }
+ })
+}
+
+export async function getConversionActionDynamicData(
+ request: RequestClient,
+ settings: any,
+ auth: any
+): Promise {
+ try {
+ const results = await getConversionActionId(settings.customerId, auth, request)
+
+ const res: Array = JSON.parse(results.content)
+ const choices = res[0].results.map((input: ConversionActionId) => {
+ return { value: input.conversionAction.id, label: input.conversionAction.name }
+ })
+ return {
+ choices
+ }
+ } catch (err) {
+ return {
+ choices: [],
+ nextPage: '',
+ error: {
+ message: (err as APIError).message ?? 'Unknown error',
+ code: (err as APIError).status + '' ?? 'Unknown error'
+ }
+ }
+ }
+}
+
/* Ensures there is no error when using Google's partialFailure mode
See here: https://developers.google.com/google-ads/api/docs/best-practices/partial-failures
*/
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/types.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/types.ts
index e052b13509..1bd370b09d 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/types.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/types.ts
@@ -12,6 +12,20 @@ export interface ConversionCustomVariable {
}
}
+export interface ConversionActionId {
+ conversionAction: {
+ resourceName: string
+ id: string
+ name: string
+ }
+}
+
+export interface ConversionActionResponse {
+ results: Array
+ fieldMask: string
+ requestId: string
+}
+
export interface QueryResponse {
results: Array
}
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/generated-types.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/generated-types.ts
index 7e9d4930d6..596bd0e8bc 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/generated-types.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/generated-types.ts
@@ -2,7 +2,7 @@
export interface Payload {
/**
- * The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.
+ * The ID of the conversion action associated with this conversion.
*/
conversion_action: number
/**
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/index.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/index.ts
index d932107cca..1d557ff6fc 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/index.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadCallConversion/index.ts
@@ -1,4 +1,4 @@
-import { ActionDefinition, PayloadValidationError } from '@segment/actions-core'
+import { ActionDefinition, DynamicFieldResponse, PayloadValidationError, RequestClient } from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import {
@@ -6,7 +6,8 @@ import {
formatCustomVariables,
getCustomVariables,
getApiVersion,
- handleGoogleErrors
+ handleGoogleErrors,
+ getConversionActionDynamicData
} from '../functions'
import { PartialErrorResponse } from '../types'
import { ModifiedResponse } from '@segment/actions-core'
@@ -17,10 +18,10 @@ const action: ActionDefinition = {
fields: {
conversion_action: {
label: 'Conversion Action ID',
- description:
- 'The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.',
+ description: 'The ID of the conversion action associated with this conversion.',
type: 'number',
- required: true
+ required: true,
+ dynamic: true
},
caller_id: {
label: 'Caller ID',
@@ -71,6 +72,12 @@ const action: ActionDefinition = {
defaultObjectUI: 'keyvalue:only'
}
},
+
+ dynamicFields: {
+ conversion_action: async (request: RequestClient, { settings, auth }): Promise => {
+ return getConversionActionDynamicData(request, settings, auth)
+ }
+ },
perform: async (request, { auth, settings, payload, features, statsContext }) => {
/* Enforcing this here since Customer ID is required for the Google Ads API
but not for the Enhanced Conversions API. */
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/generated-types.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/generated-types.ts
index 222f60ca7d..e7dce887ff 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/generated-types.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/generated-types.ts
@@ -2,7 +2,7 @@
export interface Payload {
/**
- * The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.
+ * The ID of the conversion action associated with this conversion.
*/
conversion_action: number
/**
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/index.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/index.ts
index 21b17910c1..134ed0b7e2 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/index.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadClickConversion/index.ts
@@ -1,4 +1,10 @@
-import { ActionDefinition, PayloadValidationError } from '@segment/actions-core'
+import {
+ ActionDefinition,
+ PayloadValidationError,
+ ModifiedResponse,
+ RequestClient,
+ DynamicFieldResponse
+} from '@segment/actions-core'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { CartItem, PartialErrorResponse } from '../types'
@@ -9,9 +15,9 @@ import {
handleGoogleErrors,
convertTimestamp,
getApiVersion,
- commonHashedEmailValidation
+ commonHashedEmailValidation,
+ getConversionActionDynamicData
} from '../functions'
-import { ModifiedResponse } from '@segment/actions-core'
const action: ActionDefinition = {
title: 'Upload Click Conversion',
@@ -19,10 +25,10 @@ const action: ActionDefinition = {
fields: {
conversion_action: {
label: 'Conversion Action ID',
- description:
- 'The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.',
+ description: 'The ID of the conversion action associated with this conversion.',
type: 'number',
- required: true
+ required: true,
+ dynamic: true
},
gclid: {
label: 'GCLID',
@@ -186,6 +192,12 @@ const action: ActionDefinition = {
defaultObjectUI: 'keyvalue:only'
}
},
+
+ dynamicFields: {
+ conversion_action: async (request: RequestClient, { settings, auth }): Promise => {
+ return getConversionActionDynamicData(request, settings, auth)
+ }
+ },
perform: async (request, { auth, settings, payload, features, statsContext }) => {
/* Enforcing this here since Customer ID is required for the Google Ads API
but not for the Enhanced Conversions API. */
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/generated-types.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/generated-types.ts
index 2fdfdfd376..f53bb3c5fc 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/generated-types.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/generated-types.ts
@@ -2,7 +2,7 @@
export interface Payload {
/**
- * The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.
+ * The ID of the conversion action associated with this conversion.
*/
conversion_action: number
/**
diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/index.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/index.ts
index 7801da3bc1..cdc3ace40b 100644
--- a/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/index.ts
+++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/uploadConversionAdjustment/index.ts
@@ -1,5 +1,12 @@
-import { ActionDefinition, PayloadValidationError } from '@segment/actions-core'
-import { hash, handleGoogleErrors, convertTimestamp, getApiVersion, commonHashedEmailValidation } from '../functions'
+import { ActionDefinition, DynamicFieldResponse, PayloadValidationError, RequestClient } from '@segment/actions-core'
+import {
+ hash,
+ handleGoogleErrors,
+ convertTimestamp,
+ getApiVersion,
+ commonHashedEmailValidation,
+ getConversionActionDynamicData
+} from '../functions'
import type { Settings } from '../generated-types'
import type { Payload } from './generated-types'
import { PartialErrorResponse } from '../types'
@@ -11,10 +18,10 @@ const action: ActionDefinition = {
fields: {
conversion_action: {
label: 'Conversion Action ID',
- description:
- 'The ID of the conversion action associated with this conversion. To find the Conversion Action ID, click on your conversion in Google Ads and get the value for `ctId` in the URL. For example, if the URL is `https://ads.google.com/aw/conversions/detail?ocid=00000000&ctId=570000000`, your Conversion Action ID is `570000000`.',
+ description: 'The ID of the conversion action associated with this conversion.',
type: 'number',
- required: true
+ required: true,
+ dynamic: true
},
adjustment_type: {
label: 'Adjustment Type',
@@ -22,6 +29,8 @@ const action: ActionDefinition = {
'The adjustment type. See [Google’s documentation](https://developers.google.com/google-ads/api/reference/rpc/v11/ConversionAdjustmentTypeEnum.ConversionAdjustmentType) for details on each type.',
type: 'string',
choices: [
+ { label: `UNSPECIFIED`, value: 'UNSPECIFIED' },
+ { label: `UNKNOWN`, value: 'UNKNOWN' },
{ label: `RETRACTION`, value: 'RETRACTION' },
{ label: 'RESTATEMENT', value: 'RESTATEMENT' },
{ label: `ENHANCEMENT`, value: 'ENHANCEMENT' }
@@ -197,6 +206,11 @@ const action: ActionDefinition = {
}
}
},
+ dynamicFields: {
+ conversion_action: async (request: RequestClient, { settings, auth }): Promise => {
+ return getConversionActionDynamicData(request, settings, auth)
+ }
+ },
perform: async (request, { settings, payload, features, statsContext }) => {
/* Enforcing this here since Customer ID is required for the Google Ads API
but not for the Enhanced Conversions API. */
From d97b8186f8be5553b9f48fadeacdd61d85c8e54e Mon Sep 17 00:00:00 2001
From: Joe Ayoub <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 24 Oct 2023 13:48:50 +0200
Subject: [PATCH 069/389] New Destination - Apollo.io (#1672)
* adding movable ink
* more actions
* adding stuf
* more stuff
* more work
* adding custom ACtion
* added custom event
* more updated
* more changes
* adding some tests
* more tests
* more tests
* more tests
* more tests
* more tests
* adding apollo destination
* removing movable ink
* attempting to fix tests
* minor code change
* fixing more tests
---
.../__snapshots__/snapshot.test.ts.snap | 43 +++++
.../apolloio/__tests__/index.test.ts | 19 ++
.../apolloio/__tests__/snapshot.test.ts | 105 +++++++++++
.../destinations/apolloio/generated-types.ts | 8 +
.../src/destinations/apolloio/index.ts | 57 ++++++
.../__snapshots__/snapshot.test.ts.snap | 43 +++++
.../apolloio/track/__tests__/index.test.ts | 69 ++++++++
.../apolloio/track/__tests__/snapshot.test.ts | 100 +++++++++++
.../apolloio/track/generated-types.ts | 84 +++++++++
.../src/destinations/apolloio/track/index.ts | 164 ++++++++++++++++++
10 files changed, 692 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/apolloio/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/apolloio/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/index.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/track/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/apolloio/track/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/track/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/track/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/apolloio/track/index.ts
diff --git a/packages/destination-actions/src/destinations/apolloio/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/apolloio/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..59dca46a96
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-apolloio destination: track action - all fields 1`] = `
+Array [
+ Object {
+ "anonymousId": "72d7bed1-4f42-4f2f-8955-72677340546b",
+ "campaign": Object {
+ "content": "campaign_content",
+ "medium": "campaign_medium",
+ "name": "campaign_name",
+ "source": "campaign_source",
+ "term": "campaign_term",
+ },
+ "event": "Test Event",
+ "ipAddress": "111.222.333.444",
+ "page": Object {
+ "search": "search_query",
+ },
+ "properties": Object {
+ "product_id": "pid_1",
+ },
+ "timestamp": "2023-07-29T00:00:00.000Z",
+ "userId": "user1234",
+ },
+]
+`;
+
+exports[`Testing snapshot for actions-apolloio destination: track action - required fields 1`] = `
+Array [
+ Object {
+ "anonymousId": "anonId1234",
+ "campaign": Object {},
+ "event": "Test Event",
+ "ipAddress": "111.222.333.444",
+ "page": Object {
+ "search": "search_query",
+ },
+ "properties": Object {},
+ "timestamp": "2023-07-29T00:00:00.000Z",
+ "userId": "user1234",
+ },
+]
+`;
diff --git a/packages/destination-actions/src/destinations/apolloio/__tests__/index.test.ts b/packages/destination-actions/src/destinations/apolloio/__tests__/index.test.ts
new file mode 100644
index 0000000000..c87303ec43
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/__tests__/index.test.ts
@@ -0,0 +1,19 @@
+import nock from 'nock'
+import { createTestIntegration } from '@segment/actions-core'
+import destination from '../index'
+
+const testDestination = createTestIntegration(destination)
+
+describe('Apollo.io', () => {
+ describe('testAuthentication', () => {
+ it('should validate authentication inputs', async () => {
+ const settings = {
+ apiToken: 'test'
+ }
+
+ nock(`https://apollo.io/${settings.apiToken}`).get(/.*/).reply(200, { is_logged_in: true })
+
+ await expect(testDestination.testAuthentication(settings)).resolves.not.toThrowError()
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/apolloio/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/apolloio/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..411f0bc810
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/__tests__/snapshot.test.ts
@@ -0,0 +1,105 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-apolloio'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ userId: 'user1234',
+ timestamp: '2023-07-29T00:00:00.000Z',
+ context: {
+ page: {
+ search: 'search_query'
+ },
+ ip: '111.222.333.444'
+ }
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ useDefaultMappings: true,
+ settings: {
+ apiToken: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2023-07-29T00:00:00.000Z',
+ properties: {
+ product_id: 'pid_1'
+ },
+ context: {
+ page: {
+ search: 'search_query'
+ },
+ ip: '111.222.333.444',
+ campaign: {
+ name: 'campaign_name',
+ term: 'campaign_term',
+ source: 'campaign_source',
+ medium: 'campaign_medium',
+ content: 'campaign_content'
+ }
+ }
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ useDefaultMappings: true,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/apolloio/generated-types.ts b/packages/destination-actions/src/destinations/apolloio/generated-types.ts
new file mode 100644
index 0000000000..e61f73b565
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/generated-types.ts
@@ -0,0 +1,8 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * API Token for authorization.
+ */
+ apiToken: string
+}
diff --git a/packages/destination-actions/src/destinations/apolloio/index.ts b/packages/destination-actions/src/destinations/apolloio/index.ts
new file mode 100644
index 0000000000..303f2ba91e
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/index.ts
@@ -0,0 +1,57 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+import { IntegrationError, defaultValues } from '@segment/actions-core'
+
+import track from './track'
+export const baseURL = process?.env?.ACTIONS_APOLLOIO_BASE_URL_SECRET ?? 'https://apollo.io/'
+export const authURL = process?.env?.ACTIONS_APOLLOIO_AUTH_URL_SECRET ?? 'https://apollo.io/'
+export const headerSecret = `${process.env.ACTIONS_APOLLOIO_HEADER_SECRET}`
+
+const destination: DestinationDefinition = {
+ name: 'Apollo.io',
+ slug: 'actions-apolloio',
+ mode: 'cloud',
+ description: 'Send Segment analytics events to Apollo.io',
+
+ authentication: {
+ scheme: 'custom',
+ fields: {
+ apiToken: {
+ label: 'API Token',
+ description: 'API Token for authorization.',
+ type: 'password',
+ required: true
+ }
+ },
+ testAuthentication: (request, { settings }) => {
+ return request(authURL + settings.apiToken).then(async (response) => {
+ const { is_logged_in } = await response.json()
+ if (is_logged_in === false) {
+ throw new IntegrationError(`Invalid API Token`, 'INVALID_API_TOKEN', 401)
+ }
+ })
+ }
+ },
+ extendRequest({ settings }) {
+ return {
+ headers: {
+ api_key: settings.apiToken,
+ secret: headerSecret
+ }
+ }
+ },
+ actions: {
+ track
+ },
+ presets: [
+ {
+ name: 'Track',
+ subscribe: 'type = "track"',
+ partnerAction: 'track',
+ mapping: defaultValues(track.fields),
+ type: 'automatic'
+ }
+ ]
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/apolloio/track/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/apolloio/track/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..32aa5e8d6a
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/track/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,43 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-apolloio's track destination action: all fields 1`] = `
+Array [
+ Object {
+ "anonymousId": "72d7bed1-4f42-4f2f-8955-72677340546b",
+ "campaign": Object {
+ "content": "campaign_content",
+ "medium": "campaign_medium",
+ "name": "campaign_name",
+ "source": "campaign_source",
+ "term": "campaign_term",
+ },
+ "event": "Test Event",
+ "ipAddress": "111.222.333.444",
+ "page": Object {
+ "search": "search_query",
+ },
+ "properties": Object {
+ "product_id": "pid_1",
+ },
+ "timestamp": "2023-07-29T00:00:00.000Z",
+ "userId": "user1234",
+ },
+]
+`;
+
+exports[`Testing snapshot for actions-apolloio's track destination action: required fields 1`] = `
+Array [
+ Object {
+ "anonymousId": "anonId1234",
+ "campaign": Object {},
+ "event": "Test Event",
+ "ipAddress": "111.222.333.444",
+ "page": Object {
+ "search": "search_query",
+ },
+ "properties": Object {},
+ "timestamp": "2023-07-29T00:00:00.000Z",
+ "userId": "user1234",
+ },
+]
+`;
diff --git a/packages/destination-actions/src/destinations/apolloio/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/apolloio/track/__tests__/index.test.ts
new file mode 100644
index 0000000000..2e31170bd5
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/track/__tests__/index.test.ts
@@ -0,0 +1,69 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+import { Settings } from '../../generated-types'
+
+const testDestination = createTestIntegration(Destination)
+const actionSlug = 'track'
+
+const settings: Settings = {
+ apiToken: 'test'
+}
+
+const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ product_id: 'pid_1'
+ },
+ context: {
+ page: {
+ search: 'search_query'
+ },
+ ip: '111.222.333.444',
+ campaign: {
+ name: 'campaign_name',
+ term: 'campaign_term',
+ source: 'campaign_source',
+ medium: 'campaign_medium',
+ content: 'campaign_content'
+ }
+ }
+})
+
+describe('Apolloio.track', () => {
+ it('should send event to Apollo.io', async () => {
+ nock('https://apollo.io/').post(/.*/).reply(200)
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event,
+ settings: settings,
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.json).toMatchObject([
+ {
+ event: 'Test Event',
+ properties: { product_id: 'pid_1' },
+ timestamp: '2022-03-30T17:24:58Z',
+ ipAddress: '111.222.333.444',
+ userId: 'user1234',
+ campaign: {
+ name: 'campaign_name',
+ term: 'campaign_term',
+ source: 'campaign_source',
+ medium: 'campaign_medium',
+ content: 'campaign_content'
+ },
+ page: {
+ search: 'search_query'
+ }
+ }
+ ])
+ })
+})
diff --git a/packages/destination-actions/src/destinations/apolloio/track/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/apolloio/track/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..a6a5331c17
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/track/__tests__/snapshot.test.ts
@@ -0,0 +1,100 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'track'
+const destinationSlug = 'actions-apolloio'
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ userId: 'user1234',
+ timestamp: '2023-07-29T00:00:00.000Z',
+ context: {
+ page: {
+ search: 'search_query'
+ },
+ ip: '111.222.333.444'
+ }
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ useDefaultMappings: true,
+ settings: {
+ apiToken: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ type: 'track',
+ event: 'Test Event',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2023-07-29T00:00:00.000Z',
+ properties: {
+ product_id: 'pid_1'
+ },
+ context: {
+ page: {
+ search: 'search_query'
+ },
+ ip: '111.222.333.444',
+ campaign: {
+ name: 'campaign_name',
+ term: 'campaign_term',
+ source: 'campaign_source',
+ medium: 'campaign_medium',
+ content: 'campaign_content'
+ }
+ }
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ useDefaultMappings: true,
+ settings: {
+ apiToken: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/apolloio/track/generated-types.ts b/packages/destination-actions/src/destinations/apolloio/track/generated-types.ts
new file mode 100644
index 0000000000..96386364a3
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/track/generated-types.ts
@@ -0,0 +1,84 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * An anonymous identifier
+ */
+ anonymousId?: string
+ /**
+ * Event name
+ */
+ event: string
+ /**
+ * Properties to associate with the event
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+ /**
+ * The timestamp of the event
+ */
+ timestamp: string
+ /**
+ * The users's IP address.
+ */
+ ipAddress: string
+ /**
+ * Timezone
+ */
+ timezone?: string
+ /**
+ * The ID associated with the user
+ */
+ userId?: string
+ /**
+ * UTM campaign information.
+ */
+ campaign?: {
+ /**
+ * The name of the campaign.
+ */
+ name?: string
+ /**
+ * The source of the campaign.
+ */
+ source?: string
+ /**
+ * The medium of the campaign.
+ */
+ medium?: string
+ /**
+ * The term of the campaign.
+ */
+ term?: string
+ /**
+ * The content of the campaign.
+ */
+ content?: string
+ }
+ /**
+ * Information about the page where the event occurred.
+ */
+ page: {
+ /**
+ * The URL of the page where the event occurred.
+ */
+ url?: string
+ /**
+ * The title of the page where the event occurred.
+ */
+ title?: string
+ /**
+ * The referrer of the page where the event occurred.
+ */
+ referrer?: string
+ /**
+ * The path of the page where the event occurred.
+ */
+ path?: string
+ /**
+ * The search query of the page where the event occurred.
+ */
+ search?: string
+ }
+}
diff --git a/packages/destination-actions/src/destinations/apolloio/track/index.ts b/packages/destination-actions/src/destinations/apolloio/track/index.ts
new file mode 100644
index 0000000000..ee5e9b83a6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/apolloio/track/index.ts
@@ -0,0 +1,164 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import { baseURL } from '..'
+
+const action: ActionDefinition = {
+ title: 'Track',
+ description: 'Send user analytics events to Apollo.io',
+ defaultSubscription: 'type = "track"',
+ fields: {
+ anonymousId: {
+ type: 'string',
+ description: 'An anonymous identifier',
+ label: 'Anonymous ID',
+ default: { '@path': '$.anonymousId' }
+ },
+ event: {
+ type: 'string',
+ label: 'Name',
+ description: 'Event name',
+ required: true,
+ default: { '@path': '$.event' }
+ },
+ properties: {
+ type: 'object',
+ label: 'Properties',
+ description: 'Properties to associate with the event',
+ default: { '@path': '$.properties' }
+ },
+ timestamp: {
+ type: 'string',
+ format: 'date-time',
+ required: true,
+ description: 'The timestamp of the event',
+ label: 'Timestamp',
+ default: { '@path': '$.timestamp' }
+ },
+ ipAddress: {
+ label: 'IP Address',
+ description: "The users's IP address.",
+ type: 'string',
+ required: true,
+ default: { '@path': '$.context.ip' }
+ },
+ timezone: {
+ label: 'Timezone',
+ description: 'Timezone',
+ type: 'string',
+ default: {
+ '@path': '$.context.timezone'
+ }
+ },
+ userId: {
+ type: 'string',
+ description: 'The ID associated with the user',
+ label: 'User ID',
+ default: { '@path': '$.userId' }
+ },
+ campaign: {
+ type: 'object',
+ required: false,
+ description: 'UTM campaign information.',
+ label: 'Campaign',
+ default: {
+ name: { '@path': '$.context.campaign.name' },
+ source: { '@path': '$.context.campaign.source' },
+ medium: { '@path': '$.context.campaign.medium' },
+ term: { '@path': '$.context.campaign.term' },
+ content: { '@path': '$.context.campaign.content' }
+ },
+ properties: {
+ name: {
+ type: 'string',
+ required: false,
+ description: 'The name of the campaign.',
+ label: 'Name'
+ },
+ source: {
+ type: 'string',
+ required: false,
+ description: 'The source of the campaign.',
+ label: 'Source'
+ },
+ medium: {
+ type: 'string',
+ required: false,
+ description: 'The medium of the campaign.',
+ label: 'Medium'
+ },
+ term: {
+ type: 'string',
+ required: false,
+ description: 'The term of the campaign.',
+ label: 'Term'
+ },
+ content: {
+ type: 'string',
+ required: false,
+ description: 'The content of the campaign.',
+ label: 'Content'
+ }
+ }
+ },
+ page: {
+ type: 'object',
+ required: true,
+ description: 'Information about the page where the event occurred.',
+ label: 'Page',
+ default: {
+ url: { '@path': '$.context.page.url' },
+ title: { '@path': '$.context.page.title' },
+ referrer: { '@path': '$.context.page.referrer' },
+ path: { '@path': '$.context.page.path' },
+ search: { '@path': '$.context.page.search' }
+ },
+ properties: {
+ url: {
+ type: 'string',
+ required: false,
+ description: 'The URL of the page where the event occurred.',
+ label: 'URL'
+ },
+ title: {
+ type: 'string',
+ required: false,
+ description: 'The title of the page where the event occurred.',
+ label: 'Title'
+ },
+ referrer: {
+ type: 'string',
+ required: false,
+ description: 'The referrer of the page where the event occurred.',
+ label: 'Referrer'
+ },
+ path: {
+ type: 'string',
+ required: false,
+ description: 'The path of the page where the event occurred.',
+ label: 'Path'
+ },
+ search: {
+ type: 'string',
+ required: false,
+ description: 'The search query of the page where the event occurred.',
+ label: 'Search'
+ }
+ }
+ }
+ },
+ perform: (request, data) => {
+ return request(baseURL, {
+ method: 'post',
+ json: [data.payload]
+ })
+ },
+ performBatch: (request, data) => {
+ return request(baseURL, {
+ method: 'post',
+ json: data.payload
+ })
+ }
+}
+
+export default action
From bbb9f3982d8bb23522640b56f1650f16e13952c0 Mon Sep 17 00:00:00 2001
From: Amirali Nurmagomedov
Date: Tue, 24 Oct 2023 14:49:54 +0300
Subject: [PATCH 070/389] UserMotion Cloud Action (#1670)
* [UserMotion] init
* [UserMotion] group method and tests
* [UserMotion] track, page methods and tests
* [UserMotion] minor
* [UserMotion] minor
---
.../__snapshots__/snapshot.test.ts.snap | 58 ++++++++++
.../usermotion/__tests__/index.test.ts | 26 +++++
.../usermotion/__tests__/snapshot.test.ts | 77 ++++++++++++++
.../usermotion/generated-types.ts | 8 ++
.../__snapshots__/snapshot.test.ts.snap | 18 ++++
.../usermotion/group/__tests__/index.test.ts | 51 +++++++++
.../group/__tests__/snapshot.test.ts | 75 +++++++++++++
.../usermotion/group/generated-types.ts | 18 ++++
.../destinations/usermotion/group/index.ts | 50 +++++++++
.../__snapshots__/snapshot.test.ts.snap | 21 ++++
.../identify/__tests__/index.test.ts | 73 +++++++++++++
.../identify/__tests__/snapshot.test.ts | 75 +++++++++++++
.../usermotion/identify/generated-types.ts | 22 ++++
.../destinations/usermotion/identify/index.ts | 59 +++++++++++
.../src/destinations/usermotion/index.ts | 67 ++++++++++++
.../__snapshots__/snapshot.test.ts.snap | 21 ++++
.../usermotion/track/__tests__/index.test.ts | 100 ++++++++++++++++++
.../track/__tests__/snapshot.test.ts | 75 +++++++++++++
.../usermotion/track/generated-types.ts | 26 +++++
.../destinations/usermotion/track/index.ts | 74 +++++++++++++
20 files changed, 994 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/usermotion/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/usermotion/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/group/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/usermotion/group/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/group/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/group/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/group/index.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/identify/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/usermotion/identify/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/identify/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/identify/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/identify/index.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/index.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/track/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/usermotion/track/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/track/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/track/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/usermotion/track/index.ts
diff --git a/packages/destination-actions/src/destinations/usermotion/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/usermotion/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..9d3f943dce
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,58 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-usermotion destination: group action - all fields 1`] = `
+Object {
+ "id": "ZKOt93",
+ "properties": Object {
+ "testType": "ZKOt93",
+ "website": "ZKOt93",
+ },
+}
+`;
+
+exports[`Testing snapshot for actions-usermotion destination: group action - required fields 1`] = `
+Object {
+ "id": "ZKOt93",
+ "properties": Object {},
+}
+`;
+
+exports[`Testing snapshot for actions-usermotion destination: identify action - all fields 1`] = `
+Object {
+ "id": "L[L@D",
+ "properties": Object {
+ "anonymousId": "L[L@D",
+ "email": "duz@raomopiw.to",
+ "testType": "L[L@D",
+ },
+}
+`;
+
+exports[`Testing snapshot for actions-usermotion destination: identify action - required fields 1`] = `
+Object {
+ "id": "L[L@D",
+ "properties": Object {
+ "email": "duz@raomopiw.to",
+ },
+}
+`;
+
+exports[`Testing snapshot for actions-usermotion destination: track action - all fields 1`] = `
+Object {
+ "anonymousId": "ZIYyudisV2#71gd",
+ "email": "gen@el.ci",
+ "event": "ZIYyudisV2#71gd",
+ "properties": Object {
+ "testType": "ZIYyudisV2#71gd",
+ },
+ "userId": "ZIYyudisV2#71gd",
+}
+`;
+
+exports[`Testing snapshot for actions-usermotion destination: track action - required fields 1`] = `
+Object {
+ "event": "ZIYyudisV2#71gd",
+ "properties": Object {},
+ "userId": "ZIYyudisV2#71gd",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/usermotion/__tests__/index.test.ts b/packages/destination-actions/src/destinations/usermotion/__tests__/index.test.ts
new file mode 100644
index 0000000000..ae724fc17b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/__tests__/index.test.ts
@@ -0,0 +1,26 @@
+import nock from 'nock'
+import { createTestIntegration } from '@segment/actions-core'
+import Definition from '../index'
+
+const testDestination = createTestIntegration(Definition)
+
+const endpoint = ' https://api.usermotion.com'
+
+describe('User Motion', () => {
+ describe('testAuthentication', () => {
+ it('should validate authentication inputs', async () => {
+ nock(endpoint).post('/v1/verify').reply(200, {})
+
+ await expect(testDestination.testAuthentication({ apiKey: 'TEST' })).resolves.not.toThrowError()
+ })
+
+ it('should fail authentication inputs', async () => {
+ nock(endpoint).post('/v1/verify').reply(403, {
+ code: 'AUTH_NOT_AUTHENTICATED',
+ error: 'You are not logged in'
+ })
+
+ await expect(testDestination.testAuthentication({ apiKey: '000' })).rejects.toThrowError()
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/usermotion/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..fa121b1ab6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/__tests__/snapshot.test.ts
@@ -0,0 +1,77 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-usermotion'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/generated-types.ts b/packages/destination-actions/src/destinations/usermotion/generated-types.ts
new file mode 100644
index 0000000000..90e55008c8
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/generated-types.ts
@@ -0,0 +1,8 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Settings {
+ /**
+ * Your UserMotion API Key
+ */
+ apiKey: string
+}
diff --git a/packages/destination-actions/src/destinations/usermotion/group/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/usermotion/group/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..a85e2fde7c
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/group/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,18 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Usermotion's group destination action: all fields 1`] = `
+Object {
+ "id": "vd^9vzD#xh*",
+ "properties": Object {
+ "testType": "vd^9vzD#xh*",
+ "website": "vd^9vzD#xh*",
+ },
+}
+`;
+
+exports[`Testing snapshot for Usermotion's group destination action: required fields 1`] = `
+Object {
+ "id": "vd^9vzD#xh*",
+ "properties": Object {},
+}
+`;
diff --git a/packages/destination-actions/src/destinations/usermotion/group/__tests__/index.test.ts b/packages/destination-actions/src/destinations/usermotion/group/__tests__/index.test.ts
new file mode 100644
index 0000000000..b53cf8b491
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/group/__tests__/index.test.ts
@@ -0,0 +1,51 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+const endpoint = ' https://api.usermotion.com'
+
+describe('Usermotion.group', () => {
+ test('should map groupId and traits and pass them into UserMotion.group', async () => {
+ nock(`${endpoint}`).post(`/v1/group`).reply(200, {})
+
+ const event = createTestEvent({
+ groupId: '1453',
+ traits: { website: 'usermotion.com' }
+ })
+
+ const responses = await testDestination.testAction('group', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.body).toBe(JSON.stringify({ id: '1453', properties: { website: 'usermotion.com' } }))
+ })
+
+ test('should not call group if groupId is not provided', async () => {
+ nock(`${endpoint}`).post(`/v1/group`).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'group',
+ groupId: null,
+ traits: {
+ website: 'usermotion.com'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('group', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'groupId'.")
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/group/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/usermotion/group/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..bcc364f02b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/group/__tests__/snapshot.test.ts
@@ -0,0 +1,75 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'group'
+const destinationSlug = 'Usermotion'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/group/generated-types.ts b/packages/destination-actions/src/destinations/usermotion/group/generated-types.ts
new file mode 100644
index 0000000000..a007f5b022
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/group/generated-types.ts
@@ -0,0 +1,18 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * A identifier for a known company.
+ */
+ groupId: string
+ /**
+ * The website address of the identified company
+ */
+ website?: string
+ /**
+ * Traits to associate with the company
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/usermotion/group/index.ts b/packages/destination-actions/src/destinations/usermotion/group/index.ts
new file mode 100644
index 0000000000..b5a6ff8a25
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/group/index.ts
@@ -0,0 +1,50 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Identify Company',
+ description: 'Create or update a company in UserMotion',
+ defaultSubscription: 'type = "group"',
+ fields: {
+ groupId: {
+ type: 'string',
+ description: 'A identifier for a known company.',
+ label: 'Group ID',
+ required: true,
+ default: { '@path': '$.groupId' }
+ },
+ website: {
+ type: 'string',
+ label: 'Website',
+ description: 'The website address of the identified company',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.website' },
+ then: { '@path': '$.traits.website' },
+ else: { '@path': '$.properties.website' }
+ }
+ }
+ },
+ traits: {
+ type: 'object',
+ label: 'Traits',
+ description: 'Traits to associate with the company',
+ default: { '@path': '$.traits' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request('https://api.usermotion.com/v1/group', {
+ method: 'post',
+ json: {
+ id: payload.groupId,
+ properties: {
+ ...payload.traits,
+ website: payload.website
+ }
+ }
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/usermotion/identify/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..d48b9d72f9
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Usermotion's identify destination action: all fields 1`] = `
+Object {
+ "id": "m5@snjS^ncZB*",
+ "properties": Object {
+ "anonymousId": "m5@snjS^ncZB*",
+ "email": "gi@kigot.bh",
+ "testType": "m5@snjS^ncZB*",
+ },
+}
+`;
+
+exports[`Testing snapshot for Usermotion's identify destination action: required fields 1`] = `
+Object {
+ "id": "m5@snjS^ncZB*",
+ "properties": Object {
+ "email": "gi@kigot.bh",
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/usermotion/identify/__tests__/index.test.ts b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/index.test.ts
new file mode 100644
index 0000000000..00e00b84f1
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/index.test.ts
@@ -0,0 +1,73 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+const endpoint = ' https://api.usermotion.com'
+
+describe('Usermotion.identify', () => {
+ test('should map userId and traits and pass them into UserMotion.identify', async () => {
+ nock(`${endpoint}`).post(`/v1/identify`).reply(200, {})
+
+ const event = createTestEvent({
+ userId: '1453',
+ anonymousId: 'test-anonymous-id',
+ traits: { email: 'amirali@usermotion.com' }
+ })
+
+ const responses = await testDestination.testAction('identify', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.body).toBe(
+ JSON.stringify({ id: '1453', properties: { email: 'amirali@usermotion.com', anonymousId: 'test-anonymous-id' } })
+ )
+ })
+
+ test('should not call identify if userId is not provided', async () => {
+ nock(`${endpoint}`).post(`/v1/identify`).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'identify',
+ userId: null,
+ traits: {
+ email: 'amirali@usermotion.com'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'userId'.")
+ })
+
+ test('should not call identify if email is not provided', async () => {
+ nock(`${endpoint}`).post(`/v1/identify`).reply(200, {})
+ const event = createTestEvent({
+ type: 'identify',
+ userId: '1453',
+ traits: {}
+ })
+
+ await expect(
+ testDestination.testAction('identify', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'email'.")
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/identify/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..ae2bfc5c07
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/identify/__tests__/snapshot.test.ts
@@ -0,0 +1,75 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'identify'
+const destinationSlug = 'Usermotion'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/identify/generated-types.ts b/packages/destination-actions/src/destinations/usermotion/identify/generated-types.ts
new file mode 100644
index 0000000000..2edf2821f0
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/identify/generated-types.ts
@@ -0,0 +1,22 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * A identifier for a known user.
+ */
+ userId: string
+ /**
+ * An identifier for an anonymous user
+ */
+ anonymousId?: string
+ /**
+ * The email address of the identified user
+ */
+ email: string
+ /**
+ * Traits to associate with the user
+ */
+ traits?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/usermotion/identify/index.ts b/packages/destination-actions/src/destinations/usermotion/identify/index.ts
new file mode 100644
index 0000000000..2f3815fb9b
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/identify/index.ts
@@ -0,0 +1,59 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Identify',
+ description: 'Identify user in UserMotion',
+ defaultSubscription: 'type = "identify"',
+ fields: {
+ userId: {
+ type: 'string',
+ description: 'A identifier for a known user.',
+ label: 'User ID',
+ required: true,
+ default: { '@path': '$.userId' }
+ },
+ anonymousId: {
+ type: 'string',
+ required: false,
+ description: 'An identifier for an anonymous user',
+ label: 'Anonymous ID',
+ default: { '@path': '$.anonymousId' }
+ },
+ email: {
+ type: 'string',
+ required: true,
+ label: 'Email',
+ description: 'The email address of the identified user',
+ default: {
+ '@if': {
+ exists: { '@path': '$.traits.email' },
+ then: { '@path': '$.traits.email' },
+ else: { '@path': '$.email' }
+ }
+ }
+ },
+ traits: {
+ type: 'object',
+ label: 'Traits',
+ description: 'Traits to associate with the user',
+ default: { '@path': '$.traits' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request('https://api.usermotion.com/v1/identify', {
+ method: 'post',
+ json: {
+ id: payload.userId,
+ properties: {
+ ...payload.traits,
+ email: payload.email,
+ anonymousId: payload.anonymousId
+ }
+ }
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/usermotion/index.ts b/packages/destination-actions/src/destinations/usermotion/index.ts
new file mode 100644
index 0000000000..d1e567aa9d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/index.ts
@@ -0,0 +1,67 @@
+import type { DestinationDefinition } from '@segment/actions-core'
+import type { Settings } from './generated-types'
+import { defaultValues } from '@segment/actions-core'
+
+import identify from './identify'
+
+import group from './group'
+
+import track from './track'
+
+const presets: DestinationDefinition['presets'] = [
+ {
+ name: 'Identify User',
+ subscribe: 'type = "identify"',
+ partnerAction: 'identify',
+ mapping: defaultValues(identify.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Identify Group',
+ subscribe: 'type = "group"',
+ partnerAction: 'group',
+ mapping: defaultValues(group.fields),
+ type: 'automatic'
+ },
+ {
+ name: 'Track Analytics Event',
+ subscribe: 'type = "track" or type = "page"',
+ partnerAction: 'track',
+ mapping: defaultValues(track.fields),
+ type: 'automatic'
+ }
+]
+
+const destination: DestinationDefinition = {
+ name: 'UserMotion (Actions)',
+ slug: 'actions-usermotion',
+ mode: 'cloud',
+ description: 'Send server-side events to the UserMotion REST API.',
+ extendRequest: ({ settings }) => {
+ return {
+ headers: { Authorization: `Basic ${settings.apiKey}`, 'Content-Type': 'application/json' }
+ }
+ },
+ authentication: {
+ scheme: 'custom',
+ fields: {
+ apiKey: {
+ label: 'API Key',
+ description: 'Your UserMotion API Key',
+ type: 'string',
+ required: true
+ }
+ },
+ testAuthentication: (request) => {
+ return request('https://api.usermotion.com/v1/verify', { method: 'POST' })
+ }
+ },
+ presets,
+ actions: {
+ identify,
+ group,
+ track
+ }
+}
+
+export default destination
diff --git a/packages/destination-actions/src/destinations/usermotion/track/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/usermotion/track/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..b7c2f9fd03
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/track/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,21 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for Usermotion's track destination action: all fields 1`] = `
+Object {
+ "anonymousId": "D7eiUOIRWs#EuRzn@d)n",
+ "email": "riknonolu@refe.sa",
+ "event": "D7eiUOIRWs#EuRzn@d)n",
+ "properties": Object {
+ "testType": "D7eiUOIRWs#EuRzn@d)n",
+ },
+ "userId": "D7eiUOIRWs#EuRzn@d)n",
+}
+`;
+
+exports[`Testing snapshot for Usermotion's track destination action: required fields 1`] = `
+Object {
+ "event": "D7eiUOIRWs#EuRzn@d)n",
+ "properties": Object {},
+ "userId": "D7eiUOIRWs#EuRzn@d)n",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/usermotion/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/usermotion/track/__tests__/index.test.ts
new file mode 100644
index 0000000000..8cf92fd4d6
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/track/__tests__/index.test.ts
@@ -0,0 +1,100 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+
+const testDestination = createTestIntegration(Destination)
+
+const endpoint = ' https://api.usermotion.com'
+
+describe('Usermotion.track', () => {
+ test('should map userId and traits and pass them into UserMotion.track', async () => {
+ nock(`${endpoint}`).post(`/v1/track`).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ properties: { clickedButton: true },
+ userId: '1453',
+ anonymousId: null,
+ event: 'Test Event'
+ })
+
+ const responses = await testDestination.testAction('track', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.body).toBe(
+ JSON.stringify({ event: 'Test Event', userId: '1453', properties: { clickedButton: true } })
+ )
+ })
+
+ test('should map userId and traits and pass them into UserMotion.pageview', async () => {
+ nock(`${endpoint}`).post(`/v1/track`).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'page',
+ properties: { clickedButton: true },
+ userId: '1453',
+ anonymousId: null,
+ event: 'Page View'
+ })
+
+ const responses = await testDestination.testAction('track', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.body).toBe(
+ JSON.stringify({ event: 'Page View', userId: '1453', properties: { clickedButton: true } })
+ )
+ })
+
+ test('should not call track if userId is not provided', async () => {
+ nock(`${endpoint}`).post(`/v1/track`).reply(200, {})
+
+ const event = createTestEvent({
+ type: 'track',
+ userId: null,
+ traits: {
+ email: 'amirali@usermotion.com'
+ }
+ })
+
+ await expect(
+ testDestination.testAction('track', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'userId'.")
+ })
+
+ test('should not call track if eventName is not provided', async () => {
+ nock(`${endpoint}`).post(`/v1/track`).reply(200, {})
+ const event = createTestEvent({
+ type: 'track',
+ userId: '1453',
+ event: ''
+ })
+
+ await expect(
+ testDestination.testAction('track', {
+ event,
+ useDefaultMappings: true,
+ settings: {
+ apiKey: 'test-api-key'
+ }
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'eventName'.")
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/track/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/usermotion/track/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..13204f0a6d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/track/__tests__/snapshot.test.ts
@@ -0,0 +1,75 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'track'
+const destinationSlug = 'Usermotion'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/usermotion/track/generated-types.ts b/packages/destination-actions/src/destinations/usermotion/track/generated-types.ts
new file mode 100644
index 0000000000..cc6619e578
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/track/generated-types.ts
@@ -0,0 +1,26 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * A identifier for a known user.
+ */
+ userId: string
+ /**
+ * An identifier for an anonymous user
+ */
+ anonymousId?: string
+ /**
+ * The email address for the user
+ */
+ email?: string
+ /**
+ * The name of the track() event or page() event
+ */
+ eventName: string
+ /**
+ * Properties to send with the event.
+ */
+ properties?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/usermotion/track/index.ts b/packages/destination-actions/src/destinations/usermotion/track/index.ts
new file mode 100644
index 0000000000..361b5dcb33
--- /dev/null
+++ b/packages/destination-actions/src/destinations/usermotion/track/index.ts
@@ -0,0 +1,74 @@
+import type { ActionDefinition } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+
+const action: ActionDefinition = {
+ title: 'Track Analytics Event',
+ description: 'Send user and page events to UserMotion',
+ defaultSubscription: 'type = "track" or type = "page"',
+ fields: {
+ userId: {
+ type: 'string',
+ required: true,
+ description: 'A identifier for a known user.',
+ label: 'User ID',
+ default: { '@path': '$.userId' }
+ },
+ anonymousId: {
+ type: 'string',
+ required: false,
+ description: 'An identifier for an anonymous user',
+ label: 'Anonymous ID',
+ default: { '@path': '$.anonymousId' }
+ },
+ email: {
+ type: 'string',
+ required: false,
+ description: 'The email address for the user',
+ label: 'Email address',
+ default: {
+ '@if': {
+ exists: { '@path': '$.context.traits.email' },
+ then: { '@path': '$.context.traits.email' },
+ else: { '@path': '$.properties.email' }
+ }
+ }
+ },
+ eventName: {
+ type: 'string',
+ required: true,
+ description: 'The name of the track() event or page() event',
+ label: 'Event Name',
+ default: {
+ '@if': {
+ exists: { '@path': '$.event' },
+ then: { '@path': '$.event' },
+ else: { '@path': '$.name' }
+ }
+ }
+ },
+ properties: {
+ type: 'object',
+ required: false,
+ description: 'Properties to send with the event.',
+ label: 'Event Properties',
+ default: { '@path': '$.properties' }
+ }
+ },
+ perform: (request, { payload }) => {
+ return request('https://api.usermotion.com/v1/track', {
+ method: 'post',
+ json: {
+ event: payload.eventName,
+ userId: payload.userId,
+ email: payload.email,
+ anonymousId: payload.anonymousId,
+ properties: {
+ ...payload.properties
+ }
+ }
+ })
+ }
+}
+
+export default action
From b3299854335c820d33e63c86c15ee625e2e30b32 Mon Sep 17 00:00:00 2001
From: joe-ayoub-segment <45374896+joe-ayoub-segment@users.noreply.github.com>
Date: Tue, 24 Oct 2023 12:57:21 +0100
Subject: [PATCH 071/389] adding movable ink destination
---
.../__snapshots__/snapshot.test.ts.snap | 267 ++++++++++++++++++
.../movable-ink/__tests__/index.test.ts | 122 ++++++++
.../movable-ink/__tests__/snapshot.test.ts | 81 ++++++
.../__snapshots__/snapshot.test.ts.snap | 44 +++
.../categoryView/__tests__/index.test.ts | 67 +++++
.../categoryView/__tests__/snapshot.test.ts | 79 ++++++
.../categoryView/generated-types.ts | 69 +++++
.../movable-ink/categoryView/index.ts | 55 ++++
.../__snapshots__/snapshot.test.ts.snap | 42 +++
.../conversion/__tests__/index.test.ts | 166 +++++++++++
.../conversion/__tests__/snapshot.test.ts | 79 ++++++
.../movable-ink/conversion/generated-types.ts | 64 +++++
.../movable-ink/conversion/index.ts | 58 ++++
.../src/destinations/movable-ink/fields.ts | 254 +++++++++++++++++
.../movable-ink/generated-types.ts | 16 ++
.../__snapshots__/snapshot.test.ts.snap | 18 ++
.../identify/__tests__/index.test.ts | 45 +++
.../identify/__tests__/snapshot.test.ts | 79 ++++++
.../movable-ink/identify/generated-types.ts | 24 ++
.../movable-ink/identify/index.ts | 38 +++
.../src/destinations/movable-ink/index.ts | 72 +++++
.../__snapshots__/snapshot.test.ts.snap | 40 +++
.../productAdded/__tests__/index.test.ts | 110 ++++++++
.../productAdded/__tests__/snapshot.test.ts | 79 ++++++
.../productAdded/generated-types.ts | 69 +++++
.../movable-ink/productAdded/index.ts | 55 ++++
.../__snapshots__/snapshot.test.ts.snap | 39 +++
.../productViewed/__tests__/index.test.ts | 110 ++++++++
.../productViewed/__tests__/snapshot.test.ts | 79 ++++++
.../productViewed/generated-types.ts | 65 +++++
.../movable-ink/productViewed/index.ts | 55 ++++
.../__snapshots__/snapshot.test.ts.snap | 27 ++
.../search/__tests__/index.test.ts | 113 ++++++++
.../search/__tests__/snapshot.test.ts | 79 ++++++
.../movable-ink/search/generated-types.ts | 38 +++
.../destinations/movable-ink/search/index.ts | 46 +++
.../__snapshots__/snapshot.test.ts.snap | 42 +++
.../sendCustomEvent/__tests__/index.test.ts | 80 ++++++
.../__tests__/snapshot.test.ts | 79 ++++++
.../sendCustomEvent/generated-types.ts | 81 ++++++
.../movable-ink/sendCustomEvent/index.ts | 63 +++++
.../__snapshots__/snapshot.test.ts.snap | 22 ++
.../sendEntireEvent/__tests__/index.test.ts | 59 ++++
.../__tests__/snapshot.test.ts | 79 ++++++
.../sendEntireEvent/generated-types.ts | 28 ++
.../movable-ink/sendEntireEvent/index.ts | 89 ++++++
46 files changed, 3365 insertions(+)
create mode 100644 packages/destination-actions/src/destinations/movable-ink/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/categoryView/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/categoryView/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/conversion/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/conversion/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/fields.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/identify/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/identify/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/identify/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/identify/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/identify/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productAdded/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productAdded/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productAdded/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productAdded/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productAdded/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productViewed/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productViewed/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productViewed/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productViewed/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/productViewed/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/search/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/search/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/search/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/search/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/search/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendCustomEvent/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendCustomEvent/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendCustomEvent/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendCustomEvent/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendCustomEvent/index.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendEntireEvent/__tests__/__snapshots__/snapshot.test.ts.snap
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendEntireEvent/__tests__/index.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendEntireEvent/__tests__/snapshot.test.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendEntireEvent/generated-types.ts
create mode 100644 packages/destination-actions/src/destinations/movable-ink/sendEntireEvent/index.ts
diff --git a/packages/destination-actions/src/destinations/movable-ink/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/movable-ink/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..ac72dbad22
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,267 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-movable-ink destination: categoryView action - all fields 1`] = `
+Object {
+ "anonymous_id": "UNSa)YJoVcxD*x",
+ "categories": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ "url": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "event_name": "Category View",
+ "metadata": Object {
+ "testType": "UNSa)YJoVcxD*x",
+ },
+ "product": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ "price": 17360873282600.96,
+ "quantity": 1736087328260096,
+ "title": "UNSa)YJoVcxD*x",
+ "url": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "UNSa)YJoVcxD*x",
+ "user_id": "UNSa)YJoVcxD*x",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: categoryView action - required fields 1`] = `
+Object {
+ "anonymous_id": "UNSa)YJoVcxD*x",
+ "categories": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "event_name": "Category View",
+ "metadata": Object {},
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "UNSa)YJoVcxD*x",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: conversion action - all fields 1`] = `
+Object {
+ "anonymous_id": "PQ2QIzIjTB",
+ "event_name": "Conversion",
+ "metadata": Object {
+ "testType": "PQ2QIzIjTB",
+ },
+ "order_id": "PQ2QIzIjTB",
+ "products": Array [
+ Object {
+ "id": "PQ2QIzIjTB",
+ "price": -27320916618772.48,
+ "quantity": -2732091661877248,
+ "title": "PQ2QIzIjTB",
+ "url": "PQ2QIzIjTB",
+ },
+ ],
+ "revenue": -27320916618772.48,
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "PQ2QIzIjTB",
+ "user_id": "PQ2QIzIjTB",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: conversion action - required fields 1`] = `
+Object {
+ "anonymous_id": "PQ2QIzIjTB",
+ "event_name": "Conversion",
+ "metadata": Object {},
+ "order_id": "PQ2QIzIjTB",
+ "products": Array [
+ Object {
+ "id": "PQ2QIzIjTB",
+ },
+ ],
+ "revenue": -27320916618772.48,
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "PQ2QIzIjTB",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: identify action - all fields 1`] = `
+Object {
+ "anonymous_id": "jWk*N5b5E4VTiB6Q]",
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "jWk*N5b5E4VTiB6Q]",
+ "user_id": "jWk*N5b5E4VTiB6Q]",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: identify action - required fields 1`] = `
+Object {
+ "anonymous_id": "jWk*N5b5E4VTiB6Q]",
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "jWk*N5b5E4VTiB6Q]",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: productAdded action - all fields 1`] = `
+Object {
+ "anonymous_id": "C6eQ7krEG8NsPiQOr",
+ "categories": Array [
+ Object {
+ "id": "C6eQ7krEG8NsPiQOr",
+ "url": "C6eQ7krEG8NsPiQOr",
+ },
+ ],
+ "event_name": "Cart Add",
+ "metadata": Object {
+ "testType": "C6eQ7krEG8NsPiQOr",
+ },
+ "product": Object {
+ "id": "C6eQ7krEG8NsPiQOr",
+ "price": 45880264370421.76,
+ "quantity": 4588026437042176,
+ "title": "C6eQ7krEG8NsPiQOr",
+ "url": "C6eQ7krEG8NsPiQOr",
+ },
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "C6eQ7krEG8NsPiQOr",
+ "user_id": "C6eQ7krEG8NsPiQOr",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: productAdded action - required fields 1`] = `
+Object {
+ "anonymous_id": "C6eQ7krEG8NsPiQOr",
+ "event_name": "Cart Add",
+ "metadata": Object {},
+ "product": Object {
+ "id": "C6eQ7krEG8NsPiQOr",
+ },
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "C6eQ7krEG8NsPiQOr",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: productViewed action - all fields 1`] = `
+Object {
+ "anonymous_id": ")X*ZnUpNWN@S4t]]",
+ "categories": Array [
+ Object {
+ "id": ")X*ZnUpNWN@S4t]]",
+ "url": ")X*ZnUpNWN@S4t]]",
+ },
+ ],
+ "event_name": "Product Viewed",
+ "metadata": Object {
+ "testType": ")X*ZnUpNWN@S4t]]",
+ },
+ "product": Object {
+ "id": ")X*ZnUpNWN@S4t]]",
+ "price": 38988624020111.36,
+ "title": ")X*ZnUpNWN@S4t]]",
+ "url": ")X*ZnUpNWN@S4t]]",
+ },
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": ")X*ZnUpNWN@S4t]]",
+ "user_id": ")X*ZnUpNWN@S4t]]",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: productViewed action - required fields 1`] = `
+Object {
+ "anonymous_id": ")X*ZnUpNWN@S4t]]",
+ "event_name": "Product Viewed",
+ "metadata": Object {},
+ "product": Object {
+ "id": ")X*ZnUpNWN@S4t]]",
+ },
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": ")X*ZnUpNWN@S4t]]",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: search action - all fields 1`] = `
+Object {
+ "anonymous_id": "thvLm@$Yn7k917)bo",
+ "event_name": "Search",
+ "metadata": Object {
+ "testType": "thvLm@$Yn7k917)bo",
+ },
+ "query": "thvLm@$Yn7k917)bo",
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "thvLm@$Yn7k917)bo",
+ "url": "thvLm@$Yn7k917)bo",
+ "user_id": "thvLm@$Yn7k917)bo",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: search action - required fields 1`] = `
+Object {
+ "anonymous_id": "thvLm@$Yn7k917)bo",
+ "event_name": "Search",
+ "metadata": Object {},
+ "query": "thvLm@$Yn7k917)bo",
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "thvLm@$Yn7k917)bo",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: sendCustomEvent action - all fields 1`] = `
+Object {
+ "anonymous_id": "6eS[@]@T7H%oI]ro",
+ "categories": Array [
+ Object {
+ "id": "6eS[@]@T7H%oI]ro",
+ "url": "6eS[@]@T7H%oI]ro",
+ },
+ ],
+ "event_name": "6eS[@]@T7H%oI]ro",
+ "metadata": Object {
+ "testType": "6eS[@]@T7H%oI]ro",
+ },
+ "order_id": "6eS[@]@T7H%oI]ro",
+ "products": Array [
+ Object {
+ "id": "6eS[@]@T7H%oI]ro",
+ "price": 38149067259248.64,
+ "quantity": 3814906725924864,
+ "title": "6eS[@]@T7H%oI]ro",
+ "url": "6eS[@]@T7H%oI]ro",
+ },
+ ],
+ "revenue": 38149067259248.64,
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "6eS[@]@T7H%oI]ro",
+ "user_id": "6eS[@]@T7H%oI]ro",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: sendCustomEvent action - required fields 1`] = `
+Object {
+ "anonymous_id": "6eS[@]@T7H%oI]ro",
+ "event_name": "6eS[@]@T7H%oI]ro",
+ "metadata": Object {},
+ "order_id": "6eS[@]@T7H%oI]ro",
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "6eS[@]@T7H%oI]ro",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: sendEntireEvent action - all fields 1`] = `
+Object {
+ "testType": "LmFmzlF7F",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink destination: sendEntireEvent action - required fields 1`] = `""`;
+
+exports[`Testing snapshot for actions-movable-ink destination: sendEntireEvent action - required fields 2`] = `
+Headers {
+ Symbol(map): Object {
+ "authorization": Array [
+ "Basic dGVzdDp0ZXN0",
+ ],
+ "user-agent": Array [
+ "Segment (Actions)",
+ ],
+ },
+}
+`;
diff --git a/packages/destination-actions/src/destinations/movable-ink/__tests__/index.test.ts b/packages/destination-actions/src/destinations/movable-ink/__tests__/index.test.ts
new file mode 100644
index 0000000000..feb260afd8
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/__tests__/index.test.ts
@@ -0,0 +1,122 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-movable-ink'
+
+const settingsNoMovableInkURL = {
+ username: 'test',
+ password: 'test'
+}
+
+describe('Movable Ink', () => {
+ describe('testAuthentication', () => {
+ it('should validate authentication inputs', async () => {
+ nock('https://your.destination.endpoint').get('*').reply(200, {})
+
+ const settings = {
+ username: '',
+ password: ''
+ }
+
+ await expect(testDestination.testAuthentication(settings)).resolves.not.toThrowError()
+ })
+ })
+
+ describe('Every Action - ', () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} - Should error if no url in settings AND payload provided`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData] = generateTestData(seedName, destination, action, true)
+
+ const event = createTestEvent({
+ properties: {
+ ...eventData,
+ product_id: 'product_id_1', // added to ensure a suitable payload for productAdded and productViewed Actions
+ products: [
+ { product_id: 'product_id_1' } // added to ensure a suitable payload for conversion Action
+ ]
+ }
+ })
+
+ await expect(
+ testDestination.testAction(actionSlug, {
+ event: event,
+ useDefaultMappings: true,
+ settings: settingsNoMovableInkURL
+ })
+ ).rejects.toThrowError('"Movable Ink URL" setting or "Movable Ink URL" field must be populated')
+ })
+ }
+ })
+
+ describe('Every Action - ', () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} should send event if settings url not provided but if properties.url provided`, async () => {
+ nock('https://www.test.com').post(/.*/).reply(200)
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: createTestEvent({
+ // event payload which will work for any Action
+ type: 'track',
+ event: 'Custom Event',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ movable_ink_url: 'https://www.test.com',
+ query: 'transformer toys',
+ url: 'https://www.transformertoys.com',
+ product_id: '12345',
+ products: [{ product_id: '12345' }],
+ order_id: 'abcde',
+ revenue: 1234,
+ categories: [{ id: 'cat1' }]
+ }
+ }),
+ settings: {
+ username: '',
+ password: ''
+ },
+ mapping: {
+ // event mapping which will work for any Action
+ event_name: { '@path': '$.event' },
+ movable_ink_url: { '@path': '$.properties.movable_ink_url' },
+ timestamp: { '@path': '$.timestamp' },
+ query: { '@path': '$.properties.query' },
+ anonymous_id: { '@path': '$.anonymousId' },
+ user_id: { '@path': '$.userId' },
+ query_url: { '@path': '$.properties.url' },
+ order_id: { '@path': '$.properties.order_id' },
+ revenue: { '@path': '$.properties.revenue' },
+ product: {
+ id: { '@path': '$.properties.product_id' }
+ },
+ products: {
+ '@arrayPath': [
+ '$.properties.products',
+ {
+ id: { '@path': '$.product_id' }
+ }
+ ]
+ },
+ product_with_quantity: {
+ id: { '@path': '$.properties.product_id' }
+ },
+ categories: {
+ '@arrayPath': ['$.properties.categories', { id: { '@path': '$.id' } }]
+ },
+ method: 'POST'
+ },
+ useDefaultMappings: false
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ })
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/movable-ink/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..b699caf543
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/__tests__/snapshot.test.ts
@@ -0,0 +1,81 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../lib/test-data'
+import destination from '../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const destinationSlug = 'actions-movable-ink'
+
+describe(`Testing snapshot for ${destinationSlug} destination:`, () => {
+ for (const actionSlug in destination.actions) {
+ it(`${actionSlug} action - required fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: {
+ movable_ink_url: 'https://www.test.com',
+ username: 'test',
+ password: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it(`${actionSlug} action - all fields`, async () => {
+ const seedName = `${destinationSlug}#${actionSlug}`
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+ }
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..842d334636
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,44 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-movable-ink's categoryView destination action: all fields 1`] = `
+Object {
+ "anonymous_id": "UNSa)YJoVcxD*x",
+ "categories": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ "url": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "event_name": "Category View",
+ "metadata": Object {
+ "testType": "UNSa)YJoVcxD*x",
+ },
+ "product": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ "price": 17360873282600.96,
+ "quantity": 1736087328260096,
+ "title": "UNSa)YJoVcxD*x",
+ "url": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "UNSa)YJoVcxD*x",
+ "user_id": "UNSa)YJoVcxD*x",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink's categoryView destination action: required fields 1`] = `
+Object {
+ "anonymous_id": "UNSa)YJoVcxD*x",
+ "categories": Array [
+ Object {
+ "id": "UNSa)YJoVcxD*x",
+ },
+ ],
+ "event_name": "Category View",
+ "metadata": Object {},
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "UNSa)YJoVcxD*x",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/index.test.ts b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/index.test.ts
new file mode 100644
index 0000000000..45d66eb96d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/index.test.ts
@@ -0,0 +1,67 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+import { Settings } from '../../generated-types'
+
+const testDestination = createTestIntegration(Destination)
+const actionSlug = 'categoryView'
+
+const settings: Settings = {
+ movable_ink_url: 'https://www.test.com',
+ username: 'test',
+ password: 'test'
+}
+
+const event = createTestEvent({
+ type: 'track',
+ event: 'Category Viewed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ categories: [{ id: 'cat2' }]
+ }
+})
+
+const eventNoCategory = createTestEvent({
+ type: 'track',
+ event: 'Category Viewed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {}
+})
+
+describe('MovableInk.categoryView', () => {
+ it('should send event to Movable Ink if properties.categories.$.id provided', async () => {
+ nock(settings.movable_ink_url as string)
+ .post(/.*/)
+ .reply(200)
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event,
+ settings: settings,
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.json).toMatchObject({
+ event_name: 'Category View',
+ user_id: 'user1234',
+ anonymous_id: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ categories: [{ id: 'cat2' }]
+ })
+ })
+
+ it('should throw an error if no properties.categories.$.id in payload', async () => {
+ await expect(
+ testDestination.testAction(actionSlug, {
+ event: eventNoCategory,
+ useDefaultMappings: true,
+ settings: settings
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'categories'.")
+ })
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..63c73179b4
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/categoryView/__tests__/snapshot.test.ts
@@ -0,0 +1,79 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'categoryView'
+const destinationSlug = 'actions-movable-ink'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: {
+ movable_ink_url: 'https://www.test.com',
+ username: 'test',
+ password: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/categoryView/generated-types.ts b/packages/destination-actions/src/destinations/movable-ink/categoryView/generated-types.ts
new file mode 100644
index 0000000000..ff22c6477d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/categoryView/generated-types.ts
@@ -0,0 +1,69 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The Movable Ink URL to send data to. This field overrides the "Movable Ink URL" setting.
+ */
+ movable_ink_url?: string
+ /**
+ * The unique identifier of the profile that triggered this event.
+ */
+ user_id?: string
+ /**
+ * A unique identifier of the anonymous profile that triggered this event.
+ */
+ anonymous_id?: string
+ /**
+ * Timestamp for the event. Must be in ISO 8601 format. For example '2023-09-18T11:45:59.533Z'. Segment will convert to Unix time before sending to Movable Ink.
+ */
+ timestamp: string | number
+ /**
+ * The timezone of where the event took place (TZ database name in the IANA Time Zone Database)
+ */
+ timezone?: string
+ /**
+ * Product details to associate with the event.
+ */
+ products_required_false?: {
+ /**
+ * The unique identifier of the product.
+ */
+ id: string
+ /**
+ * The title or name of the product.
+ */
+ title?: string
+ /**
+ * The product price.
+ */
+ price?: number
+ /**
+ * The URL of the product.
+ */
+ url?: string
+ /**
+ * The quantity of the product.
+ */
+ quantity?: number
+ [k: string]: unknown
+ }[]
+ /**
+ * Product Category details
+ */
+ categories: {
+ /**
+ * The unique identifier of the Category.
+ */
+ id: string
+ /**
+ * The URL of the Category
+ */
+ url?: string
+ }[]
+ /**
+ * A map of meta data to provide additional context about the event.
+ */
+ meta?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/movable-ink/categoryView/index.ts b/packages/destination-actions/src/destinations/movable-ink/categoryView/index.ts
new file mode 100644
index 0000000000..4517ecb9fc
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/categoryView/index.ts
@@ -0,0 +1,55 @@
+import { ActionDefinition, IntegrationError } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import {
+ movable_ink_url,
+ user_id,
+ anonymous_id,
+ timestamp,
+ timezone,
+ products_required_false,
+ categories,
+ meta
+} from '../fields'
+import omit from 'lodash/omit'
+
+const action: ActionDefinition = {
+ title: 'Category View',
+ description: 'Send a "Category View" event to Movable Ink',
+ defaultSubscription: 'type = "track" and event = "Category Viewed"',
+ fields: {
+ movable_ink_url,
+ user_id,
+ anonymous_id,
+ timestamp,
+ timezone,
+ products_required_false,
+ categories,
+ meta
+ },
+ perform: (request, { settings, payload }) => {
+ const url = payload?.movable_ink_url ?? settings?.movable_ink_url
+ if (!url)
+ throw new IntegrationError(
+ '"Movable Ink URL" setting or "Movable Ink URL" field must be populated',
+ 'MISSING_DESTINATION_URL',
+ 400
+ )
+
+ return request(url, {
+ method: 'POST',
+ json: {
+ event_name: 'Category View',
+ user_id: payload.user_id,
+ anonymous_id: payload.anonymous_id,
+ timestamp: payload.timestamp,
+ timezone: payload.timezone,
+ product: payload.products_required_false,
+ categories: payload.categories,
+ metadata: { ...omit(payload.meta, ['products_required_false', 'categories']) }
+ }
+ })
+ }
+}
+
+export default action
diff --git a/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/__snapshots__/snapshot.test.ts.snap
new file mode 100644
index 0000000000..112966de92
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/__snapshots__/snapshot.test.ts.snap
@@ -0,0 +1,42 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Testing snapshot for actions-movable-ink's conversion destination action: all fields 1`] = `
+Object {
+ "anonymous_id": "PQ2QIzIjTB",
+ "event_name": "Conversion",
+ "metadata": Object {
+ "testType": "PQ2QIzIjTB",
+ },
+ "order_id": "PQ2QIzIjTB",
+ "products": Array [
+ Object {
+ "id": "PQ2QIzIjTB",
+ "price": -27320916618772.48,
+ "quantity": -2732091661877248,
+ "title": "PQ2QIzIjTB",
+ "url": "PQ2QIzIjTB",
+ },
+ ],
+ "revenue": -27320916618772.48,
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "timezone": "PQ2QIzIjTB",
+ "user_id": "PQ2QIzIjTB",
+}
+`;
+
+exports[`Testing snapshot for actions-movable-ink's conversion destination action: required fields 1`] = `
+Object {
+ "anonymous_id": "PQ2QIzIjTB",
+ "event_name": "Conversion",
+ "metadata": Object {},
+ "order_id": "PQ2QIzIjTB",
+ "products": Array [
+ Object {
+ "id": "PQ2QIzIjTB",
+ },
+ ],
+ "revenue": -27320916618772.48,
+ "timestamp": "2021-02-01T00:00:00.000Z",
+ "user_id": "PQ2QIzIjTB",
+}
+`;
diff --git a/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/index.test.ts b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/index.test.ts
new file mode 100644
index 0000000000..dd1cd0a809
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/index.test.ts
@@ -0,0 +1,166 @@
+import nock from 'nock'
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import Destination from '../../index'
+import { Settings } from '../../generated-types'
+
+const testDestination = createTestIntegration(Destination)
+const actionSlug = 'conversion'
+
+const settings: Settings = {
+ movable_ink_url: 'https://www.test.com',
+ username: 'test',
+ password: 'test'
+}
+
+const event = createTestEvent({
+ type: 'track',
+ event: 'Order Completed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ order_id: 'order_1',
+ revenue: 100,
+ products: [{ product_id: 'pid_1' }]
+ }
+})
+
+const eventNoOrderId = createTestEvent({
+ type: 'track',
+ event: 'Category Viewed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ revenue: 100,
+ products: [{ product_id: 'pid_1' }]
+ }
+})
+
+const eventNoProducts = createTestEvent({
+ type: 'track',
+ event: 'Category Viewed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ order_id: 'order_1',
+ revenue: 100
+ }
+})
+
+const eventNoRevenue = createTestEvent({
+ type: 'track',
+ event: 'Category Viewed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ order_id: 'order_1',
+ products: [{ product_id: 'pid_1' }]
+ }
+})
+
+const eventWithMetadata = createTestEvent({
+ type: 'track',
+ event: 'Order Completed',
+ userId: 'user1234',
+ anonymousId: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ properties: {
+ order_id: 'order_1',
+ revenue: 100,
+ products: [{ product_id: 'pid_1' }],
+ random_field: 'random_field_value'
+ }
+})
+
+describe('MovableInk.conversion', () => {
+ it('should send event to Movable Ink if revenue and products and order_id provided', async () => {
+ nock(settings.movable_ink_url as string)
+ .post(/.*/)
+ .reply(200)
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event,
+ settings: settings,
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.json).toMatchObject({
+ event_name: 'Conversion',
+ user_id: 'user1234',
+ anonymous_id: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ order_id: 'order_1',
+ products: [{ id: 'pid_1' }],
+ revenue: 100
+ })
+ })
+
+ it('should throw an error if revenue missing', async () => {
+ await expect(
+ testDestination.testAction(actionSlug, {
+ event: eventNoOrderId,
+ useDefaultMappings: true,
+ settings: settings
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'order_id'.")
+ })
+
+ it('should throw an error if products missing', async () => {
+ await expect(
+ testDestination.testAction(actionSlug, {
+ event: eventNoProducts,
+ useDefaultMappings: true,
+ settings: settings
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'products'.")
+ })
+
+ it('should throw an error if revenue missing', async () => {
+ await expect(
+ testDestination.testAction(actionSlug, {
+ event: eventNoRevenue,
+ useDefaultMappings: true,
+ settings: settings
+ })
+ ).rejects.toThrowError("The root value is missing the required field 'revenue'.")
+ })
+
+ it('should send event to Movable Ink and should exclude products order_id and categories from metadata field', async () => {
+ nock(settings.movable_ink_url as string)
+ .post(/.*/)
+ .reply(200)
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: eventWithMetadata,
+ settings: settings,
+ useDefaultMappings: true
+ })
+
+ expect(responses.length).toBe(1)
+ expect(responses[0].status).toBe(200)
+ expect(responses[0].options.json).toMatchObject({
+ event_name: 'Conversion',
+ user_id: 'user1234',
+ anonymous_id: '72d7bed1-4f42-4f2f-8955-72677340546b',
+ timestamp: '2022-03-30T17:24:58Z',
+ order_id: 'order_1',
+ products: [{ id: 'pid_1' }],
+ revenue: 100,
+ metadata: { random_field: 'random_field_value' }
+ })
+ expect(responses[0].options.json).not.toMatchObject({
+ metadata: { order_id: 'order_1' }
+ })
+ expect(responses[0].options.json).not.toMatchObject({
+ metadata: { products: [{ id: 'pid_1' }] }
+ })
+ expect(responses[0].options.json).not.toMatchObject({
+ metadata: { revenue: 100 }
+ })
+ })
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/snapshot.test.ts
new file mode 100644
index 0000000000..0bcb81a289
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/conversion/__tests__/snapshot.test.ts
@@ -0,0 +1,79 @@
+import { createTestEvent, createTestIntegration } from '@segment/actions-core'
+import { generateTestData } from '../../../../lib/test-data'
+import destination from '../../index'
+import nock from 'nock'
+
+const testDestination = createTestIntegration(destination)
+const actionSlug = 'conversion'
+const destinationSlug = 'actions-movable-ink'
+const seedName = `${destinationSlug}#${actionSlug}`
+
+describe(`Testing snapshot for ${destinationSlug}'s ${actionSlug} destination action:`, () => {
+ it('required fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData] = generateTestData(seedName, destination, action, true)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: {
+ movable_ink_url: 'https://www.test.com',
+ username: 'test',
+ password: 'test'
+ },
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+
+ expect(request.headers).toMatchSnapshot()
+ })
+
+ it('all fields', async () => {
+ const action = destination.actions[actionSlug]
+ const [eventData, settingsData] = generateTestData(seedName, destination, action, false)
+
+ nock(/.*/).persist().get(/.*/).reply(200)
+ nock(/.*/).persist().post(/.*/).reply(200)
+ nock(/.*/).persist().put(/.*/).reply(200)
+
+ const event = createTestEvent({
+ properties: eventData
+ })
+
+ const responses = await testDestination.testAction(actionSlug, {
+ event: event,
+ mapping: event.properties,
+ settings: settingsData,
+ auth: undefined
+ })
+
+ const request = responses[0].request
+ const rawBody = await request.text()
+
+ try {
+ const json = JSON.parse(rawBody)
+ expect(json).toMatchSnapshot()
+ return
+ } catch (err) {
+ expect(rawBody).toMatchSnapshot()
+ }
+ })
+})
diff --git a/packages/destination-actions/src/destinations/movable-ink/conversion/generated-types.ts b/packages/destination-actions/src/destinations/movable-ink/conversion/generated-types.ts
new file mode 100644
index 0000000000..0cddae855d
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/conversion/generated-types.ts
@@ -0,0 +1,64 @@
+// Generated file. DO NOT MODIFY IT BY HAND.
+
+export interface Payload {
+ /**
+ * The Movable Ink URL to send data to. This field overrides the "Movable Ink URL" setting.
+ */
+ movable_ink_url?: string
+ /**
+ * The unique identifier of the profile that triggered this event.
+ */
+ user_id?: string
+ /**
+ * A unique identifier of the anonymous profile that triggered this event.
+ */
+ anonymous_id?: string
+ /**
+ * Timestamp for the event. Must be in ISO 8601 format. For example '2023-09-18T11:45:59.533Z'. Segment will convert to Unix time before sending to Movable Ink.
+ */
+ timestamp: string | number
+ /**
+ * The timezone of where the event took place (TZ database name in the IANA Time Zone Database)
+ */
+ timezone?: string
+ /**
+ * Product details to associate with the event.
+ */
+ products: {
+ /**
+ * The unique identifier of the product.
+ */
+ id: string
+ /**
+ * The title or name of the product.
+ */
+ title?: string
+ /**
+ * The product price.
+ */
+ price?: number
+ /**
+ * The URL of the product.
+ */
+ url?: string
+ /**
+ * The quantity of the product.
+ */
+ quantity?: number
+ [k: string]: unknown
+ }[]
+ /**
+ * Unique ID for the purchase
+ */
+ order_id: string
+ /**
+ * The revenue generated by the purchase
+ */
+ revenue: number
+ /**
+ * A map of meta data to provide additional context about the event.
+ */
+ meta?: {
+ [k: string]: unknown
+ }
+}
diff --git a/packages/destination-actions/src/destinations/movable-ink/conversion/index.ts b/packages/destination-actions/src/destinations/movable-ink/conversion/index.ts
new file mode 100644
index 0000000000..21dee55598
--- /dev/null
+++ b/packages/destination-actions/src/destinations/movable-ink/conversion/index.ts
@@ -0,0 +1,58 @@
+import { ActionDefinition, IntegrationError } from '@segment/actions-core'
+import type { Settings } from '../generated-types'
+import type { Payload } from './generated-types'
+import {
+ movable_ink_url,
+ user_id,
+ anonymous_id,
+ timestamp,
+ timezone,
+ products,
+ order_id,
+ revenue,
+ meta
+} from '../fields'
+import omit from 'lodash/omit'
+
+const action: ActionDefinition