diff --git a/packages/browser-destinations/destinations/1flow/README.md b/packages/browser-destinations/destinations/1flow/README.md new file mode 100644 index 0000000000..eb893c5ade --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/README.md @@ -0,0 +1,31 @@ +# @segment/analytics-browser-actions-1flow + +The 1Flow 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/1flow/package.json b/packages/browser-destinations/destinations/1flow/package.json new file mode 100644 index 0000000000..9a0217a5ad --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/package.json @@ -0,0 +1,24 @@ +{ + "name": "@segment/analytics-browser-actions-1flow", + "version": "1.0.0", + "license": "MIT", + "repository": { + "type": "git", + "url": "https://github.com/segmentio/action-destinations", + "directory": "packages/browser-destinations/destinations/1flow" + }, + "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.4.0" + }, + "peerDependencies": { + "@segment/analytics-next": ">=1.55.0" + } +} diff --git a/packages/browser-destinations/destinations/1flow/src/1flow.ts b/packages/browser-destinations/destinations/1flow/src/1flow.ts new file mode 100644 index 0000000000..67bf6a48a2 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/1flow.ts @@ -0,0 +1,22 @@ +/* eslint-disable */ +// @ts-nocheck + +export function initScript({ projectApiKey }) { + //Set your APP_ID + const apiKey = projectApiKey + + const autoURLTracking = false + ;(function (w, o, s, t, k, a, r) { + ;(w._1flow = function (e, d, v) { + s(function () { + w._1flow(e, d, !v ? {} : v) + }, 5) + }), + (a = o.getElementsByTagName('head')[0]) + r = o.createElement('script') + r.async = 1 + r.setAttribute('data-api-key', k) + r.src = t + a.appendChild(r) + })(window, document, setTimeout, 'https://cdn-development.1flow.ai/js-sdk/1flow.js', apiKey) +} diff --git a/packages/browser-destinations/destinations/1flow/src/__tests__/index.test.ts b/packages/browser-destinations/destinations/1flow/src/__tests__/index.test.ts new file mode 100644 index 0000000000..cd839e0ed5 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/__tests__/index.test.ts @@ -0,0 +1,14 @@ +import _1FlowDestination from '../index' +import { _1Flow } from '../api' + +describe('_1Flow', () => { + 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) => {} + })) + }) + test('it maps event parameters correctly to identify function ', async () => {}) +}) diff --git a/packages/browser-destinations/destinations/1flow/src/api.ts b/packages/browser-destinations/destinations/1flow/src/api.ts new file mode 100644 index 0000000000..b8279d0f4e --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/api.ts @@ -0,0 +1,11 @@ +type method = 'track' | 'identify' + +type _1FlowApi = { + richLinkProperties: string[] | undefined + activator: string | undefined + projectApiKey: string +} + +type _1FlowFunction = (method: method, ...args: unknown[]) => void + +export type _1Flow = _1FlowFunction & _1FlowApi diff --git a/packages/browser-destinations/destinations/1flow/src/generated-types.ts b/packages/browser-destinations/destinations/1flow/src/generated-types.ts new file mode 100644 index 0000000000..ad85489880 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/generated-types.ts @@ -0,0 +1,8 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Settings { + /** + * This is the unique app_id for your 1Flow application, serving as the identifier for data storage and retrieval. This field is mandatory. + */ + projectApiKey: string +} diff --git a/packages/browser-destinations/destinations/1flow/src/identifyUser/__tests__/index.test.ts b/packages/browser-destinations/destinations/1flow/src/identifyUser/__tests__/index.test.ts new file mode 100644 index 0000000000..f080cf0579 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/identifyUser/__tests__/index.test.ts @@ -0,0 +1,14 @@ +import _1FlowDestination from '../../index' + +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) => {} + })) + }) + + test('it maps event parameters correctly to identify function ', async () => {}) +}) diff --git a/packages/browser-destinations/destinations/1flow/src/identifyUser/generated-types.ts b/packages/browser-destinations/destinations/1flow/src/identifyUser/generated-types.ts new file mode 100644 index 0000000000..f5b1336f24 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/identifyUser/generated-types.ts @@ -0,0 +1,34 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique identifier for the user. + */ + userId?: string + /** + * An anonymous identifier for the user. + */ + anonymousId?: string + /** + * The user's custom attributes. + */ + traits?: { + [k: string]: unknown + } + /** + * The user's first name. + */ + first_name?: string + /** + * The user's last name. + */ + last_name?: string + /** + * The user's phone number. + */ + phone?: string + /** + * The user's email address. + */ + email?: string +} diff --git a/packages/browser-destinations/destinations/1flow/src/identifyUser/index.ts b/packages/browser-destinations/destinations/1flow/src/identifyUser/index.ts new file mode 100644 index 0000000000..80401e35a7 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/identifyUser/index.ts @@ -0,0 +1,90 @@ +import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types' +import { _1Flow } from '../api' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' + +const action: BrowserActionDefinition = { + title: 'Identify User', + description: 'Create or update a user in 1Flow.', + defaultSubscription: 'type = "identify"', + platform: 'web', + fields: { + userId: { + description: 'A unique identifier for the user.', + label: 'User ID', + type: 'string', + required: false, + default: { + '@path': '$.userId' + } + }, + anonymousId: { + description: 'An anonymous identifier for the user.', + label: 'Anonymous ID', + type: 'string', + required: false, + default: { + '@path': '$.anonymousId' + } + }, + traits: { + description: "The user's custom attributes.", + label: 'Custom Attributes', + type: 'object', + required: false, + defaultObjectUI: 'keyvalue', + default: { + '@path': '$.traits' + } + }, + first_name: { + description: "The user's first name.", + label: 'First Name', + type: 'string', + required: false, + default: { + '@path': '$.traits.first_name' + } + }, + last_name: { + description: "The user's last name.", + label: 'First Name', + type: 'string', + required: false, + default: { + '@path': '$.traits.last_name' + } + }, + phone: { + description: "The user's phone number.", + label: 'Phone Number', + type: 'string', + required: false, + default: { + '@path': '$.traits.phone' + } + }, + + email: { + description: "The user's email address.", + label: 'Email Address', + type: 'string', + required: false, + default: { + '@path': '$.traits.email' + } + } + }, + perform: (_1Flow, event) => { + const { userId, anonymousId, traits, first_name, last_name, phone, email } = event.payload + _1Flow('identify', userId, anonymousId, { + ...traits, + first_name: first_name, + last_name: last_name, + phone: phone, + email: email + }) + } +} + +export default action diff --git a/packages/browser-destinations/destinations/1flow/src/index.ts b/packages/browser-destinations/destinations/1flow/src/index.ts new file mode 100644 index 0000000000..aa98b2e2d0 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/index.ts @@ -0,0 +1,58 @@ +import type { Settings } from './generated-types' +import type { BrowserDestinationDefinition } from '@segment/browser-destination-runtime/types' +import { browserDestination } from '@segment/browser-destination-runtime/shim' +import trackEvent from './trackEvent' +import { initScript } from './1flow' +import { _1Flow } from './api' +import identifyUser from './identifyUser' +import { defaultValues } from '@segment/actions-core' +declare global { + interface Window { + _1Flow: _1Flow + } +} + +export const destination: BrowserDestinationDefinition = { + name: '1Flow', + slug: 'actions-1flow', + mode: 'device', + description: 'Send analytics from Segment to 1Flow', + settings: { + projectApiKey: { + description: + 'This is the unique app_id for your 1Flow application, serving as the identifier for data storage and retrieval. This field is mandatory.', + label: 'Project API Key', + type: 'string', + required: true + } + }, + presets: [ + { + name: 'Track Event', + subscribe: 'type = "track"', + partnerAction: 'trackEvent', + mapping: defaultValues(trackEvent.fields), + type: 'automatic' + }, + { + name: 'Identify User', + subscribe: 'type = "identify"', + partnerAction: 'identifyUser', + mapping: defaultValues(identifyUser.fields), + type: 'automatic' + } + ], + + initialize: async ({ settings }, deps) => { + const projectApiKey = settings.projectApiKey + initScript({ projectApiKey }) + await deps.resolveWhen(() => Object.prototype.hasOwnProperty.call(window, '_1Flow'), 100) + return window._1Flow + }, + actions: { + trackEvent, + identifyUser + } +} + +export default browserDestination(destination) diff --git a/packages/browser-destinations/destinations/1flow/src/trackEvent/__tests__/index.test.ts b/packages/browser-destinations/destinations/1flow/src/trackEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..8564c31fea --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/trackEvent/__tests__/index.test.ts @@ -0,0 +1,14 @@ +import _1flowDestination from '../../index' + +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) => {} + })) + }) + + test('it maps event parameters correctly to track function', async () => {}) +}) diff --git a/packages/browser-destinations/destinations/1flow/src/trackEvent/generated-types.ts b/packages/browser-destinations/destinations/1flow/src/trackEvent/generated-types.ts new file mode 100644 index 0000000000..5c7fd1c746 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/trackEvent/generated-types.ts @@ -0,0 +1,22 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The name of the event. + */ + event_name: string + /** + * A unique identifier for the user. + */ + userId?: string + /** + * An anonymous identifier for the user. + */ + anonymousId?: string + /** + * Information associated with the event + */ + properties?: { + [k: string]: unknown + } +} diff --git a/packages/browser-destinations/destinations/1flow/src/trackEvent/index.ts b/packages/browser-destinations/destinations/1flow/src/trackEvent/index.ts new file mode 100644 index 0000000000..0fec9ca043 --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/src/trackEvent/index.ts @@ -0,0 +1,59 @@ +import type { BrowserActionDefinition } from '@segment/browser-destination-runtime/types' +import { _1Flow } from '../api' +import type { Settings } from '../generated-types' +import type { Payload } from './generated-types' + +const action: BrowserActionDefinition = { + title: 'Track Event', + description: 'Submit an event to 1Flow.', + defaultSubscription: 'type = "track"', + platform: 'web', + fields: { + event_name: { + description: 'The name of the event.', + label: 'Event Name', + type: 'string', + required: true, + default: { + '@path': '$.event' + } + }, + userId: { + description: 'A unique identifier for the user.', + label: 'User ID', + type: 'string', + required: false, + default: { + '@path': '$.userId' + } + }, + anonymousId: { + description: 'An anonymous identifier for the user.', + label: 'Anonymous ID', + type: 'string', + required: false, + default: { + '@path': '$.anonymousId' + } + }, + properties: { + description: 'Information associated with the event', + label: 'Event Properties', + type: 'object', + required: false, + default: { + '@path': '$.properties' + } + } + }, + perform: (_1Flow, event) => { + const { event_name, userId, anonymousId, properties } = event.payload + _1Flow('track', event_name, { + userId: userId, + anonymousId: anonymousId, + properties: properties + }) + } +} + +export default action diff --git a/packages/browser-destinations/destinations/1flow/tsconfig.json b/packages/browser-destinations/destinations/1flow/tsconfig.json new file mode 100644 index 0000000000..c2a7897afd --- /dev/null +++ b/packages/browser-destinations/destinations/1flow/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.build.json", + "compilerOptions": { + "rootDir": "./src", + "baseUrl": "." + }, + "include": ["src"], + "exclude": ["dist", "**/__tests__"] +}