diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 52fe4be475..88a8337613 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -69,6 +69,11 @@ jobs: fetch-depth: 0 # Shallow clones should be disabled to ensure the commit history for the repository is available to the action fetch-tags: true + - name: Setup git credentials + run: | + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + - name: Generate Release Tag id: get-release-tag run: ./scripts/generate-release-tags.sh diff --git a/.github/workflows/version-packages.yml b/.github/workflows/version-packages.yml index 6d8399818f..136593ddd8 100644 --- a/.github/workflows/version-packages.yml +++ b/.github/workflows/version-packages.yml @@ -19,8 +19,8 @@ jobs: steps: - uses: actions/checkout@v4 with: - ref: main - depth: 0 + fetch-depth: 0 + fetch-tags: true - name: Use Node.js ${{ matrix.node-version }} uses: actions/setup-node@v4 @@ -51,22 +51,26 @@ jobs: - name: Commit and push id: commit_and_push run: | + git add . count=$(git diff --cached --stat) if [ -z "$count" ]; then echo "No changes to commit" echo "SKIP_PR=true" >> $GITHUB_OUTPUT exit 0 fi - git add . - git commit -m "chore: version packages" + + packages_published=$(git status -s -uno| grep "package.json" |awk '{print $2}'| xargs jq -r '.name + "@" + .version' --argjson null {}) + echo "packages_published<> $GITHUB_OUTPUT + echo "$packages_published" >> $GITHUB_OUTPUT + echo "EOF" >> $GITHUB_OUTPUT + git commit -m "Publish" git push origin ${{ github.event.inputs.branch }} - name: Create PR if: ${{ steps.commit_and_push.outputs.SKIP_PR != 'true' }} run: | - packages_published=$(git status -s -uno| grep "package.json" |awk '{print $2}'| xargs jq -r '.name + "@" + .version' --argjson null {}) pr_message="This PR was opened by GithHub Actions. Whenever you're ready to publish the packages, merge this PR." - description="$(printf "%s\n # Packages\n%s" "$pr_message" "$packages_published")" + description="$(printf "%s\n # Packages\n%s" "$pr_message" "${{ steps.commit_and_push.outputs.packages_published }}")" gh pr create --base main --head ${{ github.event.inputs.branch }} --title "Publish" --body "$description" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/docs/actions_tester.md b/docs/actions_tester.md index 96730f600f..53a16d037d 100644 --- a/docs/actions_tester.md +++ b/docs/actions_tester.md @@ -16,7 +16,7 @@ Getting started with actions tester is quite easy. For cloud action destinations For web action destinations, use the following command instead: -`./bin/run serve --directory ./packages/browser-destinations/src/destinations --browser` +`./bin/run serve --directory ./packages/browser-destinations/destinations --browser` You may either select your new action destination via the command line menu, or optionally pass it via enviornment variable to skip that step. diff --git a/package.json b/package.json index 8c153de99b..a97763e2b9 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "shared": "yarn workspace @segment/actions-shared", "subscriptions": "yarn workspace @segment/destination-subscriptions", "test": "nx run-many -t test", + "test:clear-cache": "nx clear-cache", "test-browser": "bash scripts/test-browser.sh", "test-partners": "lerna run test --stream --ignore @segment/actions-core --ignore @segment/actions-cli --ignore @segment/ajv-human-errors", "typecheck": "lerna run typecheck --stream", @@ -87,8 +88,8 @@ } }, "lint-staged": { - "**/src/destinations/**/index.ts": [ - "./bin/run generate:types", + "**/{browser-destinations,destinations}/**/*.ts": [ + "./bin/run generate:types -p", "git add **/generated-types.ts" ], "!(**/templates/**)/*.ts": [ diff --git a/packages/actions-shared/package.json b/packages/actions-shared/package.json index 72cbad9ae2..7c80e7f0e0 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.102.0", + "version": "1.103.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.121.0", + "@segment/actions-core": "^3.122.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 a7d11c8b66..59d489ddee 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.50.0", + "version": "1.51.0", "license": "MIT", "publishConfig": { "access": "public", @@ -62,7 +62,7 @@ } }, "dependencies": { - "@segment/actions-core": "^3.121.0" + "@segment/actions-core": "^3.122.0" }, "devDependencies": { "@segment/analytics-next": "*" diff --git a/packages/browser-destinations/destinations/1flow/package.json b/packages/browser-destinations/destinations/1flow/package.json index 8092d1ea4f..db54f5c160 100644 --- a/packages/browser-destinations/destinations/1flow/package.json +++ b/packages/browser-destinations/destinations/1flow/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-1flow", - "version": "1.33.0", + "version": "1.34.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/adobe-target/package.json b/packages/browser-destinations/destinations/adobe-target/package.json index d98d43608a..df04211505 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -16,7 +16,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/algolia-plugins/package.json b/packages/browser-destinations/destinations/algolia-plugins/package.json index 20640acdb0..7673b1065d 100644 --- a/packages/browser-destinations/destinations/algolia-plugins/package.json +++ b/packages/browser-destinations/destinations/algolia-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-algolia-plugins", - "version": "1.28.0", + "version": "1.29.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 96a07ed7f2..1ffc222e12 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 7e8bb3ffb6..d42499512f 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.54.0", + "version": "1.55.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/analytics-browser-actions-braze": "^1.54.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/analytics-browser-actions-braze": "^1.55.0", + "@segment/browser-destination-runtime": "^1.51.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 015415662b..c7743dc71b 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.54.0", + "version": "1.55.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.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/bucket/package.json b/packages/browser-destinations/destinations/bucket/package.json index fb9d102c61..2bbc7bf0f7 100644 --- a/packages/browser-destinations/destinations/bucket/package.json +++ b/packages/browser-destinations/destinations/bucket/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-bucket", - "version": "1.31.0", + "version": "1.32.0", "license": "MIT", "publishConfig": { "access": "public", @@ -16,8 +16,8 @@ "typings": "./dist/esm", "dependencies": { "@bucketco/tracking-sdk": "^2.0.0", - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 df7c980421..87a4629ea9 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.38.0", + "version": "1.39.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 09efd2e1ae..1e1b1c0937 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 ec697bab41..351a1a3267 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.38.0", + "version": "1.39.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 259dd43e26..b49576100a 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.52.0", + "version": "1.53.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,9 +15,9 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/actions-shared": "^1.102.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/actions-shared": "^1.103.0", + "@segment/browser-destination-runtime": "^1.51.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 c179b1239e..fedbda638c 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.53.0", + "version": "1.54.0", "license": "MIT", "publishConfig": { "access": "public", @@ -16,8 +16,8 @@ "typings": "./dist/esm", "dependencies": { "@fullstory/browser": "^2.0.3", - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 f87081f55b..848f7fd0d9 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.58.0", + "version": "1.59.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 51f29fb668..f0a2ada2c3 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.42.0", + "version": "1.43.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 e630f461e3..3685614535 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 f4d28ce3e0..33966cd03c 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.37.0", + "version": "1.38.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 067f17edcc..71a05f5cb6 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 111dc55059..4b181360f8 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.54.0", + "version": "1.55.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,9 +15,9 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/actions-shared": "^1.102.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/actions-shared": "^1.103.0", + "@segment/browser-destination-runtime": "^1.51.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 d3a14e9f79..e6a3efd16e 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 907a52339a..173f9b6779 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.39.0", + "version": "1.40.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 6102ab757d..382f2e9e41 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.52.0", + "version": "1.53.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 6b5de92a03..7bb4e0e206 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0", + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 3fbbddbd67..5778e22cb8 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.40.0", + "version": "1.41.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 29bd8cc75a..57ea9eca0b 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/replaybird/package.json b/packages/browser-destinations/destinations/replaybird/package.json index 0b3ffbbb1e..08d3558f18 100644 --- a/packages/browser-destinations/destinations/replaybird/package.json +++ b/packages/browser-destinations/destinations/replaybird/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-replaybird", - "version": "1.32.0", + "version": "1.33.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 83852f8066..1b8b87fbfe 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 d3af4181ab..12f084eb05 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.40.0", + "version": "1.41.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 33dea429b2..8f703e300d 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.52.0", + "version": "1.53.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 8faa1a8c2c..3b60c8ebfb 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/snap-plugins/package.json b/packages/browser-destinations/destinations/snap-plugins/package.json index c165e10a76..60074e95fc 100644 --- a/packages/browser-destinations/destinations/snap-plugins/package.json +++ b/packages/browser-destinations/destinations/snap-plugins/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-snap-plugins", - "version": "1.32.0", + "version": "1.33.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 6cf3d8a61c..1d738c401e 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 911544c3eb..fcca2027d4 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.53.0", + "version": "1.54.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/browser-destinations/destinations/survicate/package.json b/packages/browser-destinations/destinations/survicate/package.json index 0122f6da04..573fcf33dd 100644 --- a/packages/browser-destinations/destinations/survicate/package.json +++ b/packages/browser-destinations/destinations/survicate/package.json @@ -1,6 +1,6 @@ { "name": "@segment/analytics-browser-actions-survicate", - "version": "1.27.0", + "version": "1.28.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,7 +15,7 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/browser-destination-runtime": "^1.51.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 5e5898fabc..fbe128b218 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 35772b320d..f2b29ebb93 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 c085b3de5e..637873ba95 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.51.0", + "version": "1.52.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 46f9478668..60b41b9189 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.52.0", + "version": "1.53.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.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 baadb5f349..971fc02cda 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.52.0", + "version": "1.53.0", "license": "MIT", "publishConfig": { "access": "public", @@ -15,8 +15,8 @@ }, "typings": "./dist/esm", "dependencies": { - "@segment/actions-core": "^3.121.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/actions-core": "^3.122.0", + "@segment/browser-destination-runtime": "^1.51.0" }, "peerDependencies": { "@segment/analytics-next": ">=1.55.0" diff --git a/packages/core/package.json b/packages/core/package.json index ed7f24b3e7..9a24ccb95e 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.121.0", + "version": "3.122.0", "repository": { "type": "git", "url": "https://github.com/segmentio/fab-5-engine", diff --git a/packages/core/src/__tests__/destination-kit.test.ts b/packages/core/src/__tests__/destination-kit.test.ts index 6135405a4a..176459808c 100644 --- a/packages/core/src/__tests__/destination-kit.test.ts +++ b/packages/core/src/__tests__/destination-kit.test.ts @@ -1,3 +1,4 @@ +import { ActionDefinition } from '../destination-kit/action' import { StateContext, Destination, @@ -172,6 +173,15 @@ const destinationWithIdentifier: DestinationDefinition = { } } +interface Payload { + testDynamicField: string + testUnstructuredObject: Record + testStructuredObject: { + testDynamicSubfield: string + } + testObjectArrays: Array<{ testDynamicSubfield: string }> +} + const destinationWithDynamicFields: DestinationDefinition = { name: 'Actions Dynamic Fields', mode: 'cloud', @@ -271,7 +281,7 @@ const destinationWithDynamicFields: DestinationDefinition = { perform: (_request, { syncMode }) => { return ['this is a test', syncMode] } - } + } as ActionDefinition } } diff --git a/packages/core/src/destination-kit/action.ts b/packages/core/src/destination-kit/action.ts index 9a56e9a492..e933daca55 100644 --- a/packages/core/src/destination-kit/action.ts +++ b/packages/core/src/destination-kit/action.ts @@ -70,6 +70,9 @@ type GenericActionHookBundle = { } } +// Utility type to check if T is an array +type IsArray = T extends (infer U)[] ? U : never + // eslint-disable-next-line @typescript-eslint/no-explicit-any export interface ActionDefinition< Settings, @@ -82,16 +85,27 @@ export interface ActionDefinition< * This is likely going to change as we productionalize the data model and definition object */ dynamicFields?: { - [K in keyof Payload]?: Payload[K] extends object + [K in keyof Payload]?: IsArray extends never + ? Payload[K] extends object + ? { + [ObjectProperty in keyof Payload[K] | '__keys__' | '__values__']?: RequestFn< + Settings, + Payload, + DynamicFieldResponse, + AudienceSettings + > + } + : RequestFn + : IsArray extends object ? { - [ObjectProperty in keyof Payload[K] | '__keys__' | '__values__']?: RequestFn< + [ObjectProperty in keyof IsArray | '__keys__' | '__values__']?: RequestFn< Settings, - Payload[K], + Payload, DynamicFieldResponse, AudienceSettings > } - : RequestFn + : never } /** The operation to perform when this action is triggered */ diff --git a/packages/destination-actions/package.json b/packages/destination-actions/package.json index 54a06a844c..5f1df9e424 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.288.0", + "version": "3.290.0", "repository": { "type": "git", "url": "https://github.com/segmentio/action-destinations", @@ -43,8 +43,8 @@ "@bufbuild/protobuf": "^1.4.2", "@bufbuild/protoc-gen-es": "^1.4.2", "@segment/a1-notation": "^2.1.4", - "@segment/actions-core": "^3.121.0", - "@segment/actions-shared": "^1.102.0", + "@segment/actions-core": "^3.122.0", + "@segment/actions-shared": "^1.103.0", "@types/node": "^18.11.15", "ajv-formats": "^2.1.1", "aws4": "^1.12.0", diff --git a/packages/destination-actions/src/destinations/angler-ai/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..0cc78fbc3d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,1385 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for actions-angler-ai destination: saveBaseEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "HJmV*", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": -87007447524311.05, + "currencyCode": "HJmV*", + }, + }, + "id": "HJmV*", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": -87007447524311.05, + }, + }, + "merchandise": Object { + "id": "HJmV*", + "image": Object { + "src": "HJmV*", + }, + "price": Object { + "amount": -87007447524311.05, + }, + "product": Object { + "title": "HJmV*", + "type": "HJmV*", + "untranslatedTitle": "HJmV*", + "url": "HJmV*", + "vendor": "HJmV*", + }, + "sku": "HJmV*", + "title": "HJmV*", + "untranslatedTitle": "HJmV*", + }, + "quantity": -87007447524311.05, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "HJmV*", + }, + ], + "customer": Object { + "dob": "HJmV*", + "email": "ladu@pe.me", + "firstName": "HJmV*", + "id": "HJmV*", + "lastName": "HJmV*", + "phone": "HJmV*", + }, + }, + "event_id": "HJmV*", + "event_name": "page_viewed", + "fbc": "HJmV*", + "fpb": "HJmV*", + "ga": "HJmV*", + "identifiers": Array [], + "ip_address": "HJmV*", + "referrer": "HJmV*", + "timestamp": "HJmV*", + "url": "HJmV*", + "user_agent": "HJmV*", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveBaseEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "HJmV*", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "HJmV*", + "event_name": "page_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCartEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "HI!s%", + "data": Object { + "cartLine": Object { + "cost": Object { + "totalAmount": Object { + "amount": -84797762138275.84, + }, + }, + "merchandise": Object { + "id": "HI!s%", + "image": Object { + "src": "HI!s%", + }, + "price": Object { + "amount": -84797762138275.84, + }, + "product": Object { + "title": "HI!s%", + "type": "HI!s%", + "untranslatedTitle": "HI!s%", + "url": "HI!s%", + "vendor": "HI!s%", + }, + "sku": "HI!s%", + "title": "HI!s%", + "untranslatedTitle": "HI!s%", + }, + "quantity": -84797762138275.84, + }, + "customData": Array [ + Object { + "name": "testType", + "value": "HI!s%", + }, + ], + "customer": Object { + "dob": "HI!s%", + "email": "go@erojoavo.tw", + "firstName": "HI!s%", + "id": "HI!s%", + "lastName": "HI!s%", + "phone": "HI!s%", + }, + }, + "event_id": "HI!s%", + "event_name": "product_added_to_cart", + "fbc": "HI!s%", + "fpb": "HI!s%", + "ga": "HI!s%", + "identifiers": Array [], + "ip_address": "HI!s%", + "referrer": "HI!s%", + "timestamp": "HI!s%", + "url": "HI!s%", + "user_agent": "HI!s%", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCartEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "HI!s%", + "data": Object { + "cartLine": Object { + "cost": Object { + "totalAmount": Object {}, + }, + "merchandise": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "HI!s%", + "event_name": "product_added_to_cart", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCheckoutEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "ThtPtJ2v(7[yo[", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "checkout": Object { + "currencyCode": "ThtPtJ2v(7[yo[", + "lineItems": Array [ + Object { + "discountAllocations": Array [ + Object { + "amount": Object { + "amount": 11547049229025.28, + }, + "discountApplication": Object { + "title": "ThtPtJ2v(7[yo[", + "value": Object { + "amount": 11547049229025.28, + }, + }, + }, + ], + "id": "ThtPtJ2v(7[yo[", + "quantity": 11547049229025.28, + "title": "ThtPtJ2v(7[yo[", + "variant": Object { + "id": "ThtPtJ2v(7[yo[", + "image": Object { + "src": "ThtPtJ2v(7[yo[", + }, + "price": Object { + "amount": 11547049229025.28, + }, + "product": Object { + "id": "ThtPtJ2v(7[yo[", + "title": "ThtPtJ2v(7[yo[", + "type": "ThtPtJ2v(7[yo[", + "untranslatedTitle": "ThtPtJ2v(7[yo[", + "url": "ThtPtJ2v(7[yo[", + "vendor": "ThtPtJ2v(7[yo[", + }, + "sku": "ThtPtJ2v(7[yo[", + "title": "ThtPtJ2v(7[yo[", + "untranslatedTitle": "ThtPtJ2v(7[yo[", + }, + }, + ], + "order": Object { + "id": "ThtPtJ2v(7[yo[", + }, + "shippingLine": Object { + "price": Object { + "amount": 11547049229025.28, + }, + }, + "subtotalPrice": Object { + "amount": 11547049229025.28, + }, + "totalPrice": Object { + "amount": 11547049229025.28, + }, + "totalTax": Object { + "amount": 11547049229025.28, + }, + }, + "customData": Array [ + Object { + "name": "testType", + "value": "ThtPtJ2v(7[yo[", + }, + ], + "customer": Object { + "dob": "ThtPtJ2v(7[yo[", + "email": "woglad@famhenwip.qa", + "firstName": "ThtPtJ2v(7[yo[", + "id": "ThtPtJ2v(7[yo[", + "lastName": "ThtPtJ2v(7[yo[", + "phone": "ThtPtJ2v(7[yo[", + }, + }, + "event_id": "ThtPtJ2v(7[yo[", + "event_name": "checkout_contact_info_submitted", + "fbc": "ThtPtJ2v(7[yo[", + "fpb": "ThtPtJ2v(7[yo[", + "ga": "ThtPtJ2v(7[yo[", + "identifiers": Array [], + "ip_address": "ThtPtJ2v(7[yo[", + "referrer": "ThtPtJ2v(7[yo[", + "timestamp": "ThtPtJ2v(7[yo[", + "url": "ThtPtJ2v(7[yo[", + "user_agent": "ThtPtJ2v(7[yo[", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCheckoutEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "ThtPtJ2v(7[yo[", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "checkout": Object { + "order": Object {}, + "shippingLine": Object { + "price": Object {}, + }, + "subtotalPrice": Object {}, + "totalPrice": Object {}, + "totalTax": Object {}, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "ThtPtJ2v(7[yo[", + "event_name": "checkout_contact_info_submitted", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCollectionEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "3@hKatc0uie7SW8j", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 37315919101296.64, + "currencyCode": "3@hKatc0uie7SW8j", + }, + }, + "id": "3@hKatc0uie7SW8j", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 37315919101296.64, + }, + }, + "merchandise": Object { + "id": "3@hKatc0uie7SW8j", + "image": Object { + "src": "3@hKatc0uie7SW8j", + }, + "price": Object { + "amount": 37315919101296.64, + }, + "product": Object { + "title": "3@hKatc0uie7SW8j", + "type": "3@hKatc0uie7SW8j", + "untranslatedTitle": "3@hKatc0uie7SW8j", + "url": "3@hKatc0uie7SW8j", + "vendor": "3@hKatc0uie7SW8j", + }, + "sku": "3@hKatc0uie7SW8j", + "title": "3@hKatc0uie7SW8j", + "untranslatedTitle": "3@hKatc0uie7SW8j", + }, + "quantity": 37315919101296.64, + }, + ], + }, + "collection": Object { + "id": "3@hKatc0uie7SW8j", + "productVariants": Array [ + Object { + "id": "3@hKatc0uie7SW8j", + "image": Object { + "src": "3@hKatc0uie7SW8j", + }, + "price": Object { + "amount": 37315919101296.64, + }, + "product": Object { + "id": "3@hKatc0uie7SW8j", + "title": "3@hKatc0uie7SW8j", + "type": "3@hKatc0uie7SW8j", + "untranslatedTitle": "3@hKatc0uie7SW8j", + "url": "3@hKatc0uie7SW8j", + "vendor": "3@hKatc0uie7SW8j", + }, + "sku": "3@hKatc0uie7SW8j", + "title": "3@hKatc0uie7SW8j", + "untranslatedTitle": "3@hKatc0uie7SW8j", + }, + ], + "title": "3@hKatc0uie7SW8j", + }, + "customData": Array [ + Object { + "name": "testType", + "value": "3@hKatc0uie7SW8j", + }, + ], + "customer": Object { + "dob": "3@hKatc0uie7SW8j", + "email": "obcaswi@zoba.sy", + "firstName": "3@hKatc0uie7SW8j", + "id": "3@hKatc0uie7SW8j", + "lastName": "3@hKatc0uie7SW8j", + "phone": "3@hKatc0uie7SW8j", + }, + }, + "event_id": "3@hKatc0uie7SW8j", + "event_name": "collection_viewed", + "fbc": "3@hKatc0uie7SW8j", + "fpb": "3@hKatc0uie7SW8j", + "ga": "3@hKatc0uie7SW8j", + "identifiers": Array [], + "ip_address": "3@hKatc0uie7SW8j", + "referrer": "3@hKatc0uie7SW8j", + "timestamp": "3@hKatc0uie7SW8j", + "url": "3@hKatc0uie7SW8j", + "user_agent": "3@hKatc0uie7SW8j", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCollectionEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "3@hKatc0uie7SW8j", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "collection": Object {}, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "3@hKatc0uie7SW8j", + "event_name": "collection_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCustomEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "#p#iS", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": -86377660573286.4, + "currencyCode": "#p#iS", + }, + }, + "id": "#p#iS", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": -86377660573286.4, + }, + }, + "merchandise": Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + "quantity": -86377660573286.4, + }, + ], + }, + "cartLine": Object { + "cost": Object { + "totalAmount": Object { + "amount": -86377660573286.4, + }, + }, + "merchandise": Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + "quantity": -86377660573286.4, + }, + "checkout": Object { + "currencyCode": "#p#iS", + "lineItems": Array [ + Object { + "discountAllocations": Array [ + Object { + "amount": Object { + "amount": -86377660573286.4, + }, + "discountApplication": Object { + "title": "#p#iS", + "value": Object { + "amount": -86377660573286.4, + }, + }, + }, + ], + "id": "#p#iS", + "quantity": -86377660573286.4, + "title": "#p#iS", + "variant": Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "id": "#p#iS", + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + }, + ], + "order": Object { + "id": "#p#iS", + }, + "shippingLine": Object { + "price": Object { + "amount": -86377660573286.4, + }, + }, + "subtotalPrice": Object { + "amount": -86377660573286.4, + }, + "totalPrice": Object { + "amount": -86377660573286.4, + }, + "totalTax": Object { + "amount": -86377660573286.4, + }, + }, + "collection": Object { + "id": "#p#iS", + "productVariants": Array [ + Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "id": "#p#iS", + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + ], + "title": "#p#iS", + }, + "customData": Array [ + Object { + "name": "testType", + "value": "#p#iS", + }, + ], + "customer": Object { + "dob": "#p#iS", + "email": "ali@so.td", + "firstName": "#p#iS", + "id": "#p#iS", + "lastName": "#p#iS", + "phone": "#p#iS", + }, + "form": Object { + "action": "#p#iS", + "elements": Array [ + Object { + "id": "#p#iS", + "name": "#p#iS", + "tagName": "#p#iS", + "type": "#p#iS", + "value": "#p#iS", + }, + ], + "id": "#p#iS", + }, + "productVariant": Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "id": "#p#iS", + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + "searchResult": Object { + "productVariants": Array [ + Object { + "id": "#p#iS", + "image": Object { + "src": "#p#iS", + }, + "price": Object { + "amount": -86377660573286.4, + }, + "product": Object { + "id": "#p#iS", + "title": "#p#iS", + "type": "#p#iS", + "untranslatedTitle": "#p#iS", + "url": "#p#iS", + "vendor": "#p#iS", + }, + "sku": "#p#iS", + "title": "#p#iS", + "untranslatedTitle": "#p#iS", + }, + ], + "query": "#p#iS", + }, + }, + "event_id": "#p#iS", + "event_name": "page_viewed", + "fbc": "#p#iS", + "fpb": "#p#iS", + "ga": "#p#iS", + "identifiers": Array [], + "ip_address": "#p#iS", + "referrer": "#p#iS", + "timestamp": "#p#iS", + "url": "#p#iS", + "user_agent": "#p#iS", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveCustomEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "#p#iS", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "cartLine": Object { + "cost": Object { + "totalAmount": Object {}, + }, + "merchandise": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "checkout": Object { + "order": Object {}, + "shippingLine": Object { + "price": Object {}, + }, + "subtotalPrice": Object {}, + "totalPrice": Object {}, + "totalTax": Object {}, + }, + "collection": Object {}, + "customData": Array [], + "customer": Object {}, + "form": Object { + "id": "#p#iS", + }, + "productVariant": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + "searchResult": Object {}, + }, + "event_id": "#p#iS", + "event_name": "page_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveFormEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "MzABQb$ZztnY3", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 3543243161600, + "currencyCode": "MzABQb$ZztnY3", + }, + }, + "id": "MzABQb$ZztnY3", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 3543243161600, + }, + }, + "merchandise": Object { + "id": "MzABQb$ZztnY3", + "image": Object { + "src": "MzABQb$ZztnY3", + }, + "price": Object { + "amount": 3543243161600, + }, + "product": Object { + "title": "MzABQb$ZztnY3", + "type": "MzABQb$ZztnY3", + "untranslatedTitle": "MzABQb$ZztnY3", + "url": "MzABQb$ZztnY3", + "vendor": "MzABQb$ZztnY3", + }, + "sku": "MzABQb$ZztnY3", + "title": "MzABQb$ZztnY3", + "untranslatedTitle": "MzABQb$ZztnY3", + }, + "quantity": 3543243161600, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "MzABQb$ZztnY3", + }, + ], + "customer": Object { + "dob": "MzABQb$ZztnY3", + "email": "tecav@fijumo.gi", + "firstName": "MzABQb$ZztnY3", + "id": "MzABQb$ZztnY3", + "lastName": "MzABQb$ZztnY3", + "phone": "MzABQb$ZztnY3", + }, + "form": Object { + "action": "MzABQb$ZztnY3", + "elements": Array [ + Object { + "id": "MzABQb$ZztnY3", + "name": "MzABQb$ZztnY3", + "tagName": "MzABQb$ZztnY3", + "type": "MzABQb$ZztnY3", + "value": "MzABQb$ZztnY3", + }, + ], + "id": "MzABQb$ZztnY3", + }, + }, + "event_id": "MzABQb$ZztnY3", + "event_name": "form_submitted", + "fbc": "MzABQb$ZztnY3", + "fpb": "MzABQb$ZztnY3", + "ga": "MzABQb$ZztnY3", + "identifiers": Array [], + "ip_address": "MzABQb$ZztnY3", + "referrer": "MzABQb$ZztnY3", + "timestamp": "MzABQb$ZztnY3", + "url": "MzABQb$ZztnY3", + "user_agent": "MzABQb$ZztnY3", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveFormEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "MzABQb$ZztnY3", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "form": Object { + "id": "MzABQb$ZztnY3", + }, + }, + "event_id": "MzABQb$ZztnY3", + "event_name": "form_submitted", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveOrder action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "additional_fields": Array [ + Object { + "name": "E0rNrwcK", + "value": "E0rNrwcK", + }, + ], + "billing_address": Object { + "address1": "E0rNrwcK", + "address2": "E0rNrwcK", + "city": "E0rNrwcK", + "company": "E0rNrwcK", + "country": "E0rNrwcK", + "country_code": "E0rNrwcK", + "country_name": "E0rNrwcK", + "customer_id": "E0rNrwcK", + "default": true, + "first_name": "E0rNrwcK", + "hashed_address1": "E0rNrwcK", + "hashed_address2": "E0rNrwcK", + "hashed_city": "E0rNrwcK", + "hashed_country_code": "E0rNrwcK", + "hashed_first_name": "E0rNrwcK", + "hashed_last_name": "E0rNrwcK", + "hashed_phone": "E0rNrwcK", + "hashed_zip": "E0rNrwcK", + "id": "E0rNrwcK", + "last_name": "E0rNrwcK", + "name": "E0rNrwcK", + "phone": "E0rNrwcK", + "province": "E0rNrwcK", + "province_code": "E0rNrwcK", + "zip": "E0rNrwcK", + }, + "browser_ip": "E0rNrwcK", + "buyer_accepts_marketing": true, + "checkout_id": "E0rNrwcK", + "client_details": Object { + "browser_ip": "E0rNrwcK", + "user_agent": "E0rNrwcK", + }, + "confirmed": true, + "contact_email": "E0rNrwcK", + "created_at": "E0rNrwcK", + "currency": "KYD", + "current_subtotal_price": "E0rNrwcK", + "current_total_discounts": "E0rNrwcK", + "current_total_price": "E0rNrwcK", + "current_total_tax": "E0rNrwcK", + "customer_id": "E0rNrwcK", + "discount_applications": Array [ + Object { + "allocation_method": "E0rNrwcK", + "code": "E0rNrwcK", + "target_selection": "E0rNrwcK", + "target_type": "E0rNrwcK", + "type": "E0rNrwcK", + "value": "E0rNrwcK", + "value_type": "E0rNrwcK", + }, + ], + "discount_codes": Array [ + Object { + "amount": "E0rNrwcK", + "code": "E0rNrwcK", + "type": "E0rNrwcK", + }, + ], + "email": "giko@vowolo.pr", + "estimated_taxes": true, + "financial_status": "E0rNrwcK", + "fulfillment_status": "E0rNrwcK", + "gateway": "E0rNrwcK", + "id": "E0rNrwcK", + "landing_site": "E0rNrwcK", + "landing_site_ref": "E0rNrwcK", + "name": "E0rNrwcK", + "order_number": -5134747260944384, + "phone": "E0rNrwcK", + "processed_at": "E0rNrwcK", + "processing_method": "E0rNrwcK", + "reference": "E0rNrwcK", + "referring_site": "E0rNrwcK", + "shipping_address": Object { + "address1": "E0rNrwcK", + "address2": "E0rNrwcK", + "city": "E0rNrwcK", + "company": "E0rNrwcK", + "country": "E0rNrwcK", + "country_code": "E0rNrwcK", + "country_name": "E0rNrwcK", + "customer_id": "E0rNrwcK", + "default": true, + "first_name": "E0rNrwcK", + "hashed_address1": "E0rNrwcK", + "hashed_address2": "E0rNrwcK", + "hashed_city": "E0rNrwcK", + "hashed_country_code": "E0rNrwcK", + "hashed_first_name": "E0rNrwcK", + "hashed_last_name": "E0rNrwcK", + "hashed_phone": "E0rNrwcK", + "hashed_zip": "E0rNrwcK", + "id": "E0rNrwcK", + "last_name": "E0rNrwcK", + "name": "E0rNrwcK", + "phone": "E0rNrwcK", + "province": "E0rNrwcK", + "province_code": "E0rNrwcK", + "zip": "E0rNrwcK", + }, + "source_identifier": "E0rNrwcK", + "source_name": "E0rNrwcK", + "source_url": "E0rNrwcK", + "subtotal_price": "E0rNrwcK", + "tags": "E0rNrwcK", + "taxes_included": true, + "total_discounts": "E0rNrwcK", + "total_line_items_price": "E0rNrwcK", + "total_outstanding": "E0rNrwcK", + "total_price": "E0rNrwcK", + "total_price_usd": "E0rNrwcK", + "total_tax": "E0rNrwcK", + "updated_at": "E0rNrwcK", + "user_id": "E0rNrwcK", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveOrder action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "checkout_id": "E0rNrwcK", + "customer_id": "E0rNrwcK", + "id": "E0rNrwcK", + "source_identifier": "E0rNrwcK", + "user_id": "E0rNrwcK", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveProductEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "Gzg!*To", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": -59279958731653.12, + "currencyCode": "Gzg!*To", + }, + }, + "id": "Gzg!*To", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": -59279958731653.12, + }, + }, + "merchandise": Object { + "id": "Gzg!*To", + "image": Object { + "src": "Gzg!*To", + }, + "price": Object { + "amount": -59279958731653.12, + }, + "product": Object { + "title": "Gzg!*To", + "type": "Gzg!*To", + "untranslatedTitle": "Gzg!*To", + "url": "Gzg!*To", + "vendor": "Gzg!*To", + }, + "sku": "Gzg!*To", + "title": "Gzg!*To", + "untranslatedTitle": "Gzg!*To", + }, + "quantity": -59279958731653.12, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "Gzg!*To", + }, + ], + "customer": Object { + "dob": "Gzg!*To", + "email": "pug@te.bn", + "firstName": "Gzg!*To", + "id": "Gzg!*To", + "lastName": "Gzg!*To", + "phone": "Gzg!*To", + }, + "productVariant": Object { + "id": "Gzg!*To", + "image": Object { + "src": "Gzg!*To", + }, + "price": Object { + "amount": -59279958731653.12, + }, + "product": Object { + "id": "Gzg!*To", + "title": "Gzg!*To", + "type": "Gzg!*To", + "untranslatedTitle": "Gzg!*To", + "url": "Gzg!*To", + "vendor": "Gzg!*To", + }, + "sku": "Gzg!*To", + "title": "Gzg!*To", + "untranslatedTitle": "Gzg!*To", + }, + }, + "event_id": "Gzg!*To", + "event_name": "product_viewed", + "fbc": "Gzg!*To", + "fpb": "Gzg!*To", + "ga": "Gzg!*To", + "identifiers": Array [], + "ip_address": "Gzg!*To", + "referrer": "Gzg!*To", + "timestamp": "Gzg!*To", + "url": "Gzg!*To", + "user_agent": "Gzg!*To", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveProductEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "Gzg!*To", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "productVariant": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "event_id": "Gzg!*To", + "event_name": "product_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveSearchEvent action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "zjYJOkMXvxa&fnXrdj", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 66925103950069.76, + "currencyCode": "zjYJOkMXvxa&fnXrdj", + }, + }, + "id": "zjYJOkMXvxa&fnXrdj", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 66925103950069.76, + }, + }, + "merchandise": Object { + "id": "zjYJOkMXvxa&fnXrdj", + "image": Object { + "src": "zjYJOkMXvxa&fnXrdj", + }, + "price": Object { + "amount": 66925103950069.76, + }, + "product": Object { + "title": "zjYJOkMXvxa&fnXrdj", + "type": "zjYJOkMXvxa&fnXrdj", + "untranslatedTitle": "zjYJOkMXvxa&fnXrdj", + "url": "zjYJOkMXvxa&fnXrdj", + "vendor": "zjYJOkMXvxa&fnXrdj", + }, + "sku": "zjYJOkMXvxa&fnXrdj", + "title": "zjYJOkMXvxa&fnXrdj", + "untranslatedTitle": "zjYJOkMXvxa&fnXrdj", + }, + "quantity": 66925103950069.76, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "zjYJOkMXvxa&fnXrdj", + }, + ], + "customer": Object { + "dob": "zjYJOkMXvxa&fnXrdj", + "email": "gep@coaseto.gg", + "firstName": "zjYJOkMXvxa&fnXrdj", + "id": "zjYJOkMXvxa&fnXrdj", + "lastName": "zjYJOkMXvxa&fnXrdj", + "phone": "zjYJOkMXvxa&fnXrdj", + }, + "searchResult": Object { + "productVariants": Array [ + Object { + "id": "zjYJOkMXvxa&fnXrdj", + "image": Object { + "src": "zjYJOkMXvxa&fnXrdj", + }, + "price": Object { + "amount": 66925103950069.76, + }, + "product": Object { + "id": "zjYJOkMXvxa&fnXrdj", + "title": "zjYJOkMXvxa&fnXrdj", + "type": "zjYJOkMXvxa&fnXrdj", + "untranslatedTitle": "zjYJOkMXvxa&fnXrdj", + "url": "zjYJOkMXvxa&fnXrdj", + "vendor": "zjYJOkMXvxa&fnXrdj", + }, + "sku": "zjYJOkMXvxa&fnXrdj", + "title": "zjYJOkMXvxa&fnXrdj", + "untranslatedTitle": "zjYJOkMXvxa&fnXrdj", + }, + ], + "query": "zjYJOkMXvxa&fnXrdj", + }, + }, + "event_id": "zjYJOkMXvxa&fnXrdj", + "event_name": "search_submitted", + "fbc": "zjYJOkMXvxa&fnXrdj", + "fpb": "zjYJOkMXvxa&fnXrdj", + "ga": "zjYJOkMXvxa&fnXrdj", + "identifiers": Array [], + "ip_address": "zjYJOkMXvxa&fnXrdj", + "referrer": "zjYJOkMXvxa&fnXrdj", + "timestamp": "zjYJOkMXvxa&fnXrdj", + "url": "zjYJOkMXvxa&fnXrdj", + "user_agent": "zjYJOkMXvxa&fnXrdj", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveSearchEvent action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "zjYJOkMXvxa&fnXrdj", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "searchResult": Object {}, + }, + "event_id": "zjYJOkMXvxa&fnXrdj", + "event_name": "search_submitted", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveUser action - all fields 1`] = ` +Object { + "data": Array [ + Object { + "addresses": Array [ + Object { + "address1": "g[^FhJnb(lsNz", + "address2": "g[^FhJnb(lsNz", + "city": "g[^FhJnb(lsNz", + "company": "g[^FhJnb(lsNz", + "country": "g[^FhJnb(lsNz", + "country_code": "g[^FhJnb(lsNz", + "country_name": "g[^FhJnb(lsNz", + "customer_id": "g[^FhJnb(lsNz", + "default": false, + "first_name": "g[^FhJnb(lsNz", + "hashed_address1": "g[^FhJnb(lsNz", + "hashed_address2": "g[^FhJnb(lsNz", + "hashed_city": "g[^FhJnb(lsNz", + "hashed_country_code": "g[^FhJnb(lsNz", + "hashed_first_name": "g[^FhJnb(lsNz", + "hashed_last_name": "g[^FhJnb(lsNz", + "hashed_phone": "g[^FhJnb(lsNz", + "hashed_zip": "g[^FhJnb(lsNz", + "id": "g[^FhJnb(lsNz", + "last_name": "g[^FhJnb(lsNz", + "name": "g[^FhJnb(lsNz", + "phone": "g[^FhJnb(lsNz", + "province": "g[^FhJnb(lsNz", + "province_code": "g[^FhJnb(lsNz", + "zip": "g[^FhJnb(lsNz", + }, + ], + "default_address": Object { + "address1": "g[^FhJnb(lsNz", + "address2": "g[^FhJnb(lsNz", + "city": "g[^FhJnb(lsNz", + "company": "g[^FhJnb(lsNz", + "country": "g[^FhJnb(lsNz", + "country_code": "g[^FhJnb(lsNz", + "country_name": "g[^FhJnb(lsNz", + "customer_id": "g[^FhJnb(lsNz", + "default": false, + "first_name": "g[^FhJnb(lsNz", + "hashed_address1": "g[^FhJnb(lsNz", + "hashed_address2": "g[^FhJnb(lsNz", + "hashed_city": "g[^FhJnb(lsNz", + "hashed_country_code": "g[^FhJnb(lsNz", + "hashed_first_name": "g[^FhJnb(lsNz", + "hashed_last_name": "g[^FhJnb(lsNz", + "hashed_phone": "g[^FhJnb(lsNz", + "hashed_zip": "g[^FhJnb(lsNz", + "id": "g[^FhJnb(lsNz", + "last_name": "g[^FhJnb(lsNz", + "name": "g[^FhJnb(lsNz", + "phone": "g[^FhJnb(lsNz", + "province": "g[^FhJnb(lsNz", + "province_code": "g[^FhJnb(lsNz", + "zip": "g[^FhJnb(lsNz", + }, + "email_marketing_consent": Object { + "consent_updated_at": "g[^FhJnb(lsNz", + "opt_in_level": "g[^FhJnb(lsNz", + "state": "g[^FhJnb(lsNz", + }, + "metafield": Object { + "key": "g[^FhJnb(lsNz", + "namespace": "g[^FhJnb(lsNz", + "type": "g[^FhJnb(lsNz", + "value": "g[^FhJnb(lsNz", + }, + "sms_marketing_consent": Object { + "consent_collected_from": "g[^FhJnb(lsNz", + "consent_updated_at": "g[^FhJnb(lsNz", + "opt_in_level": "g[^FhJnb(lsNz", + "state": "g[^FhJnb(lsNz", + }, + "user": Object { + "accepts_marketing": false, + "accepts_marketing_updated_at": "g[^FhJnb(lsNz", + "created_at": "g[^FhJnb(lsNz", + "currency": "DZD", + "email": "zav@eja.hm", + "first_name": "g[^FhJnb(lsNz", + "hashed_email": "g[^FhJnb(lsNz", + "hashed_first_name": "g[^FhJnb(lsNz", + "hashed_last_name": "g[^FhJnb(lsNz", + "hashed_phone": "g[^FhJnb(lsNz", + "id": "g[^FhJnb(lsNz", + "last_name": "g[^FhJnb(lsNz", + "last_order_id": "g[^FhJnb(lsNz", + "last_order_name": "g[^FhJnb(lsNz", + "marketing_opt_in_level": "g[^FhJnb(lsNz", + "note": "g[^FhJnb(lsNz", + "orders_count": 9227457181777.92, + "phone": "g[^FhJnb(lsNz", + "state": "INVITED", + "tax_exempt": false, + "total_spent": "g[^FhJnb(lsNz", + "updated_at": "g[^FhJnb(lsNz", + "verified_email": false, + }, + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for actions-angler-ai destination: saveUser action - required fields 1`] = ` +Object { + "data": Array [ + Object { + "email_marketing_consent": Object {}, + "sms_marketing_consent": Object {}, + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/__tests__/index.test.ts new file mode 100644 index 0000000000..640174208f --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/__tests__/index.test.ts @@ -0,0 +1,26 @@ +import nock from 'nock' +import { createTestIntegration } from '@segment/actions-core' +import Definition from '../index' +import { baseURL } from '../routes' + +const testDestination = createTestIntegration(Definition) + +describe('Angler Ai', () => { + describe('testAuthentication', () => { + it('should validate authentication inputs', async () => { + const authResponse = { + sub: 'test_workspace_id', + scopes: 'DATA_ADMIN' + } + + nock(baseURL).get('/v1/me').reply(200, authResponse) + + const authData = { + accessToken: 'test_token', + workspaceId: 'test_workspace_id' + } + + await expect(testDestination.testAuthentication(authData)).resolves.not.toThrowError() + }) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..77ec634f06 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/__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-angler-ai' + +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/angler-ai/fields/addressFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/addressFields.ts new file mode 100644 index 0000000000..f8e85f8536 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/addressFields.ts @@ -0,0 +1,164 @@ +import { PathDirective, InputField } from '@segment/actions-core' + +export const addressProperties: Record = { + id: { + label: 'ID', + type: 'string', + description: 'A unique identifier for the address.' + }, + address1: { + label: 'Address 1', + type: 'string', + description: "The customer's mailing address." + }, + address2: { + label: 'Address 2', + type: 'string', + description: "An additional field for the customer's mailing address." + }, + city: { + label: 'City', + type: 'string', + description: "The customer's city, town, or village." + }, + company: { + label: 'Company', + type: 'string', + description: "The customer's company." + }, + country: { + label: 'Country', + type: 'string', + description: "The customer's country." + }, + country_code: { + label: 'Country Code', + type: 'string', + description: "The two-letter country code corresponding to the customer's country" + }, + country_name: { + label: 'Country Name', + type: 'string', + description: "The customer's normalized country name." + }, + customer_id: { + label: 'Customer ID', + type: 'string', + description: 'A unique identifier for the customer.' + }, + default: { + label: 'Default', + type: 'boolean', + description: 'Whether this address is the default address for the customer.' + }, + first_name: { + label: 'First Name', + type: 'string', + description: "The customer's first name." + }, + last_name: { + label: 'Last Name', + type: 'string', + description: "The customer's last name." + }, + name: { + label: 'Name', + type: 'string', + description: "The customer's first and last names." + }, + phone: { + label: 'Phone', + type: 'string', + description: "The customer's phone number at this address." + }, + province: { + label: 'Province', + type: 'string', + description: "The customer's region name. Typically a province, a state, or a prefecture" + }, + province_code: { + label: 'Province Code', + type: 'string', + description: + 'The code for the region of the address, such as the province, state, or district. For example QC for Quebec, Canada.' + }, + zip: { + label: 'Zip', + type: 'string', + description: "The customer's postal code, also known as zip, postcode, Eircode, etc" + }, + hashed_first_name: { + label: 'Hashed First Name', + type: 'string', + description: 'Hashed value of first name in SHA256 (lower case).' + }, + hashed_last_name: { + label: 'Hashed Last Name', + type: 'string', + description: 'Hashed value of last name in SHA256 (lower case).' + }, + hashed_phone: { + label: 'Hashed Phone', + type: 'string', + description: 'Hashed value of phone in SHA256 (lower case).' + }, + hashed_address1: { + label: 'Hashed Address 1', + type: 'string', + description: 'Hashed value of address1 in SHA256 (lower case).' + }, + hashed_address2: { + label: 'Hashed Address 2', + type: 'string', + description: 'Hashed value of address2 in SHA256 (lower case).' + }, + hashed_city: { + label: 'Hashed City', + type: 'string', + description: 'Hashed value of city in SHA256 (lower case).' + }, + hashed_zip: { + label: 'Hashed Zip', + type: 'string', + description: 'Hashed value of zip in SHA256 (lower case).' + }, + hashed_country_code: { + label: 'Hashed Country Code', + type: 'string', + description: 'Hashed value of country code in SHA256 (lower case).' + } +} + +export function addressDefaultFields(path = ''): Record { + if (path && !path.endsWith('.')) { + path += '.' + } + + return { + id: { '@path': `${path}id` }, + address1: { '@path': `${path}address1` }, + address2: { '@path': `${path}address2` }, + city: { '@path': `${path}city` }, + company: { '@path': `${path}company` }, + country: { '@path': `${path}country` }, + country_code: { '@path': `${path}country_code` }, + country_name: { '@path': `${path}country_name` }, + customer_id: { '@path': `${path}customer_id` }, + default: { '@path': `${path}default` }, + first_name: { '@path': `${path}first_name` }, + last_name: { '@path': `${path}last_name` }, + name: { '@path': `${path}name` }, + phone: { '@path': `${path}phone` }, + province: { '@path': `${path}province` }, + province_code: { '@path': `${path}province_code` }, + zip: { '@path': `${path}zip` }, + hashed_first_name: { '@path': `${path}hashed_first_name` }, + hashed_last_name: { '@path': `${path}hashed_last_name` }, + hashed_phone: { '@path': `${path}hashed_phone` }, + hashed_address1: { '@path': `${path}hashed_address1` }, + hashed_address2: { '@path': `${path}hashed_address2` }, + hashed_city: { '@path': `${path}hashed_city` }, + hashed_zip: { '@path': `${path}hashed_zip` }, + hashed_country_code: { '@path': `${path}hashed_country_code` } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/cartFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/cartFields.ts new file mode 100644 index 0000000000..4a30753713 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/cartFields.ts @@ -0,0 +1,40 @@ +import { InputField } from '@segment/actions-core/index' +import { productsFields } from './productsFields' + +export const cartFields: Record = { + cart: { + label: 'Cart', + type: 'object', + description: 'Cart details', + properties: { + id: { + label: 'Cart ID', + type: 'string', + description: 'A globally unique identifier for the cart.' + }, + totalAmount: { + label: 'Total Amount', + type: 'number', + description: 'Decimal money amount.' + }, + currencyCode: { + label: 'Currency Code', + type: 'string', + description: 'The currency code of the money.' + } + } + }, + cartLines: { + ...productsFields, + label: 'Cart Line Items', + description: 'Cart Line Item details', + properties: { + ...productsFields.properties, + quantity: { + label: 'Quantity', + type: 'number', + description: 'Quantity of the item' + } + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/cartLineFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/cartLineFields.ts new file mode 100644 index 0000000000..35f9ef15a6 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/cartLineFields.ts @@ -0,0 +1,29 @@ +import { InputField } from '@segment/actions-core/index' +import { productFields, productDefaultProperties } from './productFields' + +export const cartLineFields: Record = { + cartLine: { + ...productFields, + label: 'Cart Line', + description: 'Cart Line details', + properties: { + ...productFields.properties, + quantity: { + label: 'Quantity', + type: 'number', + description: 'Quantity of the item' + } + }, + default: { + '@arrayPath': [ + '$.properties.products', + { + ...productDefaultProperties, + quantity: { + '@path': '$.quantity' + } + } + ] + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/checkoutFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/checkoutFields.ts new file mode 100644 index 0000000000..dfbd01f23d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/checkoutFields.ts @@ -0,0 +1,100 @@ +import { InputField } from '@segment/actions-core/index' +import { productsDefaultProperties, productsFields } from './productsFields' + +export const checkoutFields: Record = { + checkout: { + label: 'Checkout', + type: 'object', + description: 'Checkout details', + properties: { + totalAmount: { + label: 'Total Amount', + type: 'number', + description: 'Decimal money amount.', + default: { + '@path': '$.properties.total' + } + }, + currencyCode: { + label: 'Currency Code', + type: 'string', + description: 'The currency code of the money.', + default: { + '@path': '$.properties.currency' + } + }, + orderId: { + label: 'Order ID', + type: 'string', + description: 'The ID of the order associated with this checkout.', + default: { + '@path': '$.properties.order_id' + } + }, + subtotalPriceAmount: { + label: 'Subtotal Price Amount', + type: 'number', + description: 'A monetary value.', + default: { + '@path': '$.properties.subtotal' + } + }, + totalTaxAmount: { + label: 'Total Tax Amount', + type: 'number', + description: 'A monetary value with currency.', + default: { + '@path': '$.properties.tax' + } + }, + shippingLinePriceAmount: { + label: 'Shipping Line Price Amount', + type: 'number', + description: 'A monetary value.', + default: { + '@path': '$.properties.shipping' + } + } + } + }, + checkoutLineItems: { + ...productsFields, + label: 'Checkout Line Items', + description: 'Checkout Line Item details', + properties: { + ...productsFields.properties, + quantity: { + label: 'Quantity', + type: 'number', + description: 'Quantity of the item' + }, + discountTitle: { + label: 'Discount Title', + type: 'string', + description: 'The Discount Code applied to the item.' + }, + discountValue: { + label: 'Discount Value', + type: 'number', + description: 'The Discount value applied to the item.' + } + }, + default: { + '@arrayPath': [ + '$.properties.products', + { + ...productsDefaultProperties, + quantity: { + '@path': '$.quantity' + }, + discountTitle: { + '@path': '$.coupon' + }, + discountValue: { + '@path': '$.discount' + } + } + ] + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/collectionFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/collectionFields.ts new file mode 100644 index 0000000000..d20e7db7fb --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/collectionFields.ts @@ -0,0 +1,36 @@ +import { InputField } from '@segment/actions-core/index' +import { productsFields } from './productsFields' + +export const collectionFields: Record = { + collection: { + label: 'Collection', + type: 'object', + description: 'Collection details', + additionalProperties: false, + properties: { + id: { + label: 'Collection Id', + type: 'string', + description: 'A globally unique identifier for the collection.' + }, + title: { + label: 'Title', + type: 'string', + description: 'The collection title.' + } + }, + default: { + id: { + '@path': '$.properties.list_id' + }, + title: { + '@path': '$.properties.list_name' + } + } + }, + collectionProductVariants: { + ...productsFields, + label: 'Collection Product Variants', + description: 'A list of product variants associated with the collection.' + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/commonFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/commonFields.ts new file mode 100644 index 0000000000..8ae71c6c9d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/commonFields.ts @@ -0,0 +1,113 @@ +import type { InputField } from '@segment/actions-core' + +export const commonFields: Record = { + eventId: { + label: 'Event ID', + type: 'string', + description: 'A unique event identifier.', + required: true, + default: { + '@path': '$.messageId' + } + }, + ipAddress: { + label: 'IP Address', + type: 'string', + description: 'The IP address of the user.', + default: { + '@path': '$.context.ip' + } + }, + userAgent: { + label: 'User Agent', + type: 'string', + description: 'The user agent of the device sending the event.', + default: { + '@path': '$.context.userAgent' + } + }, + timestamp: { + label: 'Timestamp', + type: 'string', + description: 'The timestamp when the event was triggered.', + default: { + '@path': '$.timestamp' + } + }, + identifiers: { + label: 'Identifiers', + type: 'object', + description: 'Identifiers for the user', + required: true, + additionalProperties: true, + properties: { + userId: { + label: 'Segment user ID', + type: 'string', + description: 'Segment User ID.' + }, + anonymousId: { + label: 'Segment anonymous ID', + type: 'string', + description: 'Segment anonymous ID.' + }, + clientId: { + label: 'Client ID', + type: 'string', + description: 'Client ID.', + required: true + }, + fbp: { + label: 'Facebook Pixel ID', + type: 'string', + description: 'Facebook Pixel ID. This is a cookie which is unique to each user.' + }, + fbc: { + label: 'Facebook Click ID', + type: 'string', + description: 'Facebook Click ID. This is a cookie which is unique to each user.' + }, + ga: { + label: 'Google Analytics ID', + type: 'string', + description: 'Google Analytics ID. This is a cookie which is unique to each user.' + } + }, + default: { + userId: { '@path': '$.userId' }, + anonymousId: { '@path': '$.anonymousId' }, + clientId: { '@path': '$.anonymousId' }, + fbp: { '@path': '$.properties.fbp' }, + fbc: { '@path': '$.properties.fbc' }, + ga: { '@path': '$.properties.ga' } + } + }, + page: { + label: 'Page', + type: 'object', + description: 'Page details to send with the event', + properties: { + url: { + label: 'URL', + type: 'string', + description: 'The URL where the event occurred.' + }, + referrer: { + label: 'Referrer', + type: 'string', + description: 'The referring URL if applicable.' + } + }, + additionalProperties: false, + default: { + url: { '@path': '$.context.page.url' }, + referrer: { '@path': '$.context.page.referrer' } + } + }, + customAttributes: { + label: 'Custom Attributes', + type: 'object', + description: 'Custom attributes for the event. Data should be specified as key:value pairs', + additionalProperties: true + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/customerFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/customerFields.ts new file mode 100644 index 0000000000..9b306feaea --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/customerFields.ts @@ -0,0 +1,73 @@ +import { InputField } from '@segment/actions-core/index' + +export const customerFields: Record = { + customer: { + label: 'Customer', + type: 'object', + description: 'Customer details', + properties: { + email: { + type: 'string', + label: 'Email', + description: "The customer's email address." + }, + firstName: { + type: 'string', + label: 'First Name', + description: "The customer's first name." + }, + lastName: { + type: 'string', + label: 'Last Name', + description: "The customer's last name." + }, + phone: { + type: 'string', + label: 'Phone', + description: 'The unique phone number (E.164 format) for this customer.' + }, + dob: { + type: 'string', + label: 'Date of Birth', + description: "The customer's date of birth." + } + }, + default: { + email: { + '@if': { + exists: { '@path': '$.traits.email' }, + then: { '@path': '$.traits.email' }, + else: { '@path': '$.context.traits.email' } + } + }, + firstName: { + '@if': { + exists: { '@path': '$.traits.first_name' }, + then: { '@path': '$.traits.first_name' }, + else: { '@path': '$.context.traits.first_name' } + } + }, + lastName: { + '@if': { + exists: { '@path': '$.traits.last_name' }, + then: { '@path': '$.traits.last_name' }, + else: { '@path': '$.context.traits.last_name' } + } + }, + phone: { + '@if': { + exists: { '@path': '$.traits.phone' }, + then: { '@path': '$.traits.phone' }, + else: { '@path': '$.context.traits.phone' } + } + }, + dob: { + '@if': { + exists: { '@path': '$.traits.birthday' }, + then: { '@path': '$.traits.birthday' }, + else: { '@path': '$.context.traits.birthday' } + } + } + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/formFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/formFields.ts new file mode 100644 index 0000000000..2830152cc3 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/formFields.ts @@ -0,0 +1,59 @@ +import { InputField } from '@segment/actions-core/index' + +export const formFields: Record = { + id: { + type: 'string', + label: 'Form ID', + description: 'The id attribute of an element.' + }, + action: { + type: 'string', + label: 'Form Action', + description: 'The action attribute of a form element.' + }, + elements: { + type: 'object', + multiple: true, + label: 'Form Elements', + description: 'A list of elements associated with the form.', + properties: { + id: { + type: 'string', + label: 'Element ID', + description: 'The id attribute of an element.' + }, + name: { + type: 'string', + label: 'Name', + description: 'The name attribute of an element.' + }, + tagName: { + type: 'string', + label: 'Tag Name', + description: 'A string representation of the tag of an element.' + }, + type: { + type: 'string', + label: 'Type', + description: 'The type attribute of an element. Often relevant for an input or button element.' + }, + value: { + type: 'string', + label: 'Value', + description: 'The value attribute of an element. Often relevant for an input element.' + } + }, + default: { + '@arrayPath': [ + '$.properties.form.elements', + { + id: { '@path': '$.id' }, + name: { '@path': '$.name' }, + tagName: { '@path': '$.tagName' }, + type: { '@path': '$.type' }, + value: { '@path': '$.value' } + } + ] + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/productFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/productFields.ts new file mode 100644 index 0000000000..85113aba5a --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/productFields.ts @@ -0,0 +1,100 @@ +import { InputField } from '@segment/actions-core/index' + +export const productDefaultProperties = { + quantity: { + '@path': '$.properties.quantity' + }, + id: { + '@path': '$.properties.product_id' + }, + variantId: { + '@path': '$.properties.variant' + }, + imageSrc: { + '@path': '$.properties.image_url' + }, + priceAmount: { + '@path': '$.properties.price' + }, + sku: { + '@path': '$.properties.sku' + }, + title: { + '@path': '$.properties.name' + }, + untranslatedTitle: { + '@if': { + exists: [{ '@path': '$.properties.variant' }], + then: { '@path': '$.properties.variant' }, + else: { '@path': '$.properties.title' } + } + }, + vendor: { + '@path': '$.properties.vendor' + }, + type: { + '@path': '$.properties.category' + }, + url: { + '@path': '$.properties.url' + } +} + +export const productFields: InputField = { + label: '', + type: 'object', + description: '', + properties: { + id: { + label: 'Product Id', + type: 'string', + description: 'A globally unique identifier for the item.' + }, + variantId: { + label: 'Variant Id', + type: 'string', + description: 'Identifier for the variant of the product' + }, + imageSrc: { + label: 'Image Source URL', + type: 'string', + description: 'The location of the image as a URL.' + }, + priceAmount: { + label: 'Price Amount', + type: 'number', + description: 'The price of the product variant.' + }, + sku: { + label: 'SKU', + type: 'string', + description: 'The SKU (stock keeping unit) associated with the variant.' + }, + title: { + label: 'Title', + type: 'string', + description: "The product variant's title." + }, + untranslatedTitle: { + label: 'Untranslated Title', + type: 'string', + description: "The product variant's untranslated title." + }, + vendor: { + label: 'Vendor', + type: 'string', + description: "The product's vendor name." + }, + type: { + label: 'Type', + type: 'string', + description: 'The product type specified by the merchant.' + }, + url: { + label: 'URL', + type: 'string', + description: 'The relative URL of the product.' + } + }, + default: productDefaultProperties +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/productVariantFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/productVariantFields.ts new file mode 100644 index 0000000000..2d13502281 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/productVariantFields.ts @@ -0,0 +1,10 @@ +import { InputField } from '@segment/actions-core/index' +import { productFields } from './productFields' + +export const productVariantFields: Record = { + productVariant: { + ...productFields, + label: 'Product Variant', + description: 'Product Variant details' + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/productsFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/productsFields.ts new file mode 100644 index 0000000000..5de3047fd2 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/productsFields.ts @@ -0,0 +1,99 @@ +import { InputField } from '@segment/actions-core/index' + +export const productsDefaultProperties = { + quantity: { + '@path': '$.quantity' + }, + id: { + '@path': '$.product_id' + }, + variantId: { + '@path': '$.variant' + }, + imageSrc: { + '@path': '$.image_url' + }, + priceAmount: { + '@path': '$.price' + }, + sku: { + '@path': '$.sku' + }, + title: { + '@path': '$.name' + }, + untranslatedTitle: { + '@path': '$.untranslated_title' + }, + vendor: { + '@path': '$.vendor' + }, + type: { + '@path': '$.category' + }, + url: { + '@path': '$.url' + } +} + +export const productsFields: InputField = { + label: '', + type: 'object', + multiple: true, + description: '', + properties: { + id: { + label: 'Product Id', + type: 'string', + description: 'A globally unique identifier for the item.' + }, + variantId: { + label: 'Variant Id', + type: 'string', + description: 'Identifier for the variant of the product' + }, + imageSrc: { + label: 'Image Source URL', + type: 'string', + description: 'The location of the image as a URL.' + }, + priceAmount: { + label: 'Price Amount', + type: 'number', + description: 'The price of the product variant.' + }, + sku: { + label: 'SKU', + type: 'string', + description: 'The SKU (stock keeping unit) associated with the variant.' + }, + title: { + label: 'Title', + type: 'string', + description: "The product variant's title." + }, + untranslatedTitle: { + label: 'Untranslated Title', + type: 'string', + description: "The product variant's untranslated title." + }, + vendor: { + label: 'Vendor', + type: 'string', + description: "The product's vendor name." + }, + type: { + label: 'Type', + type: 'string', + description: 'The product type specified by the merchant.' + }, + url: { + label: 'URL', + type: 'string', + description: 'The relative URL of the product.' + } + }, + default: { + '@arrayPath': ['$.properties.products', productsDefaultProperties] + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/searchFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/searchFields.ts new file mode 100644 index 0000000000..11c99c7069 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/searchFields.ts @@ -0,0 +1,18 @@ +import { InputField } from '@segment/actions-core/index' +import { productsFields } from './productsFields' + +export const searchFields: Record = { + searchResults: { + ...productsFields, + label: 'Search Results', + description: 'Search results details' + }, + query: { + type: 'string', + label: 'Search Query', + description: 'The search query that was executed.', + default: { + '@path': '$.properties.query' + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/fields/userFields.ts b/packages/destination-actions/src/destinations/angler-ai/fields/userFields.ts new file mode 100644 index 0000000000..a64782044d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/fields/userFields.ts @@ -0,0 +1,301 @@ +import type { InputField } from '@segment/actions-core' +import { addressDefaultFields, addressProperties } from './addressFields' + +export const userFields: Record = { + user: { + type: 'object', + label: 'User', + description: 'The user object.', + defaultObjectUI: 'keyvalue', + additionalProperties: true, + properties: { + accepts_marketing: { + label: 'Accepts Marketing', + type: 'boolean', + description: 'Whether the customer has consented to receive marketing material by email.' + }, + accepts_marketing_updated_at: { + label: 'Accepts Marketing Updated At', + type: 'string', + description: + 'The date and time (ISO 8601 format) when the customer consented or objected to receiving marketing material by email.' + }, + currency: { + label: 'Currency', + type: 'string', + description: + 'The three-letter code (ISO 4217 format) for the currency that the customer used when they paid for their last order.' + }, + created_at: { + label: 'Created At', + type: 'string', + description: 'The date and time (ISO 8601 format) when the customer was created.' + }, + email: { + label: 'Email', + type: 'string', + description: 'The unique email address of the customer.' + }, + hashed_email: { + label: 'Hashed Email', + type: 'string', + description: "Hashed customer's email in SHA256 (lower case)." + }, + hashed_first_name: { + label: 'Hashed First Name', + type: 'string', + description: "Hashed customer's first name in SHA256 (lower case)." + }, + hashed_last_name: { + label: 'Hashed Last Name', + type: 'string', + description: "Hashed customer's last name in SHA256 (lower case)." + }, + hashed_phone: { + label: 'Hashed Phone', + type: 'string', + description: "Hashed customer's phone in SHA256 (lower case)." + }, + first_name: { + label: 'First Name', + type: 'string', + description: "The customer's first name." + }, + id: { + label: 'ID', + type: 'string', + description: 'A unique identifier for the customer.' + }, + last_name: { + label: 'Last Name', + type: 'string', + description: "The customer's last name." + }, + last_order_id: { + label: 'Last Order ID', + type: 'string', + description: "The ID of the customer's last order." + }, + last_order_name: { + label: 'Last Order Name', + type: 'string', + description: "The name of the customer's last order." + }, + marketing_opt_in_level: { + label: 'Marketing Opt In Level', + type: 'string', + description: + 'The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by email.' + }, + note: { + label: 'Note', + type: 'string', + description: 'A note about the customer.' + }, + orders_count: { + label: 'Orders Count', + type: 'number', + description: 'The number of orders associated with this customer.' + }, + phone: { + label: 'Phone', + type: 'string', + description: 'The unique phone number (E.164 format) for this customer.' + }, + state: { + label: 'State', + type: 'string', + choices: [ + { value: 'ENABLED', label: 'Enabled' }, + { value: 'DISABLED', label: 'Disabled' }, + { value: 'INVITED', label: 'Invited' }, + { value: 'DECLINED', label: 'Declined' } + ], + description: "The state of the customer's account with a shop." + }, + tax_exempt: { + label: 'Tax Exempt', + type: 'boolean', + description: 'Whether the customer is exempt from paying taxes on their order.' + }, + total_spent: { + label: 'Total Spent', + type: 'string', + description: 'The total amount of money that the customer has spent across their order history.' + }, + updated_at: { + label: 'Updated At', + type: 'string', + description: 'The date and time (ISO 8601 format) when the customer information was last updated.' + }, + verified_email: { + label: 'Verified Email', + type: 'boolean', + description: 'Whether the customer has verified their email address.' + } + }, + default: { + accepts_marketing: { '@path': '$.traits.accepts_marketing' }, + accepts_marketing_updated_at: { '@path': '$.traits.accepts_marketing_updated_at' }, + currency: { '@path': '$.traits.currency' }, + created_at: { '@path': '$.traits.created_at' }, + email: { '@path': '$.traits.email' }, + hashed_email: { '@path': '$.traits.hashed_email' }, + hashed_first_name: { '@path': '$.traits.hashed_first_name' }, + hashed_last_name: { '@path': '$.traits.hashed_last_name' }, + hashed_phone: { '@path': '$.traits.hashed_phone' }, + first_name: { '@path': '$.traits.first_name' }, + id: { + '@if': { + exists: { '@path': '$.userId' }, + then: { '@path': '$.userId' }, + else: { '@path': '$.traits.id' } + } + }, + last_name: { '@path': '$.traits.last_name' }, + last_order_id: { '@path': '$.traits.last_order_id' }, + last_order_name: { '@path': '$.traits.last_order_name' }, + marketing_opt_in_level: { '@path': '$.traits.marketing_opt_in_level' }, + note: { '@path': '$.traits.note' }, + orders_count: { '@path': '$.traits.orders_count' }, + phone: { '@path': '$.traits.phone' }, + state: { '@path': '$.traits.state' }, + tax_exempt: { '@path': '$.traits.tax_exempt' }, + total_spent: { '@path': '$.traits.total_spent' }, + updated_at: { '@path': '$.traits.updated_at' }, + verified_email: { '@path': '$.traits.verified_email' } + } + }, + addresses: { + label: 'Addresses', + type: 'object', + description: 'A list of the ten most recently updated addresses for the customer.', + multiple: true, + properties: addressProperties, + default: { + '@arrayPath': ['$.traits.addresses', addressDefaultFields('$')] + } + }, + default_address: { + label: 'Default Address', + type: 'object', + description: 'The mailing address associated with the payment method.', + properties: addressProperties, + default: addressDefaultFields('$.traits.default_address.') + }, + email_marketing_consent: { + label: 'Email Marketing Consent', + type: 'object', + description: + 'The marketing consent information when the customer consented to receiving marketing material by email.', + properties: { + state: { + label: 'State', + type: 'string', + description: 'The current email marketing state for the customer.' + }, + opt_in_level: { + label: 'Opt In Level', + type: 'string', + description: + 'The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by email.' + }, + consent_updated_at: { + label: 'Consent Updated At', + type: 'string', + description: + 'The date and time when the customer consented to receive marketing material by email. If no date is provided, then the date and time when the consent information was sent is used.' + } + }, + default: { + '@arrayPath': [ + '$.traits.email_marketing_consent', + { + state: { '@path': '$.state' }, + opt_in_level: { '@path': '$.opt_in_level' }, + consent_updated_at: { '@path': '$.consent_updated_at' } + } + ] + } + }, + metafield: { + label: 'Metafield', + type: 'object', + description: "Attaches additional metadata to a shop's resources.", + properties: { + key: { + label: 'Key', + type: 'string', + description: 'An identifier for the metafield.' + }, + namespace: { + label: 'Namespace', + type: 'string', + description: + 'A container for a set of metadata. Namespaces help distinguish between metadata that you created and metadata created by another individual with a similar namespace.' + }, + value: { + label: 'Value', + type: 'string', + description: 'Information to be stored as metadata.' + }, + type: { + label: 'Type', + type: 'string', + description: 'The type.' + } + }, + default: { + '@arrayPath': [ + '$.traits.metafield', + { + key: { '@path': '$.key' }, + namespace: { '@path': '$.namespace' }, + value: { '@path': '$.value' }, + type: { '@path': '$.type' } + } + ] + } + }, + sms_marketing_consent: { + label: 'SMS Marketing Consent', + type: 'object', + description: + 'The marketing consent information when the customer consented to receiving marketing material by SMS.', + properties: { + state: { + label: 'State', + type: 'string', + description: 'The state of the SMS marketing consent.' + }, + opt_in_level: { + label: 'Opt In Level', + type: 'string', + description: + 'The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by SMS.' + }, + consent_updated_at: { + label: 'Consent Updated At', + type: 'string', + description: + 'The date and time when the customer consented to receive marketing material by SMS. If no date is provided, then the date and time when the consent information was sent is used.' + }, + consent_collected_from: { + label: 'Consent Collected From', + type: 'string', + description: 'The source for whether the customer has consented to receive marketing material by SMS.' + } + }, + default: { + '@arrayPath': [ + '$.traits.sms_marketing_consent', + { + state: { '@path': '$.state' }, + opt_in_level: { '@path': '$.opt_in_level' }, + consent_updated_at: { '@path': '$.consent_updated_at' }, + consent_collected_from: { '@path': '$.consent_collected_from' } + } + ] + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/generated-types.ts new file mode 100644 index 0000000000..9e7c074407 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/generated-types.ts @@ -0,0 +1,12 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Settings { + /** + * Your Angler AI API Authentication Token + */ + accessToken: string + /** + * Your Angler AI Workspace ID + */ + workspaceId: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/index.ts b/packages/destination-actions/src/destinations/angler-ai/index.ts new file mode 100644 index 0000000000..85af31c0be --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/index.ts @@ -0,0 +1,104 @@ +import { DestinationDefinition, ErrorCodes, IntegrationError } from '@segment/actions-core' +import type { Settings } from './generated-types' +import { presets } from './presets' +import { baseURL, privacyEndpoint, testEndpoint } from './routes' +import saveBaseEvent from './saveBaseEvent' +import saveCartEvent from './saveCartEvent' +import saveCheckoutEvent from './saveCheckoutEvent' +import saveCollectionEvent from './saveCollectionEvent' +import saveCustomEvent from './saveCustomEvent' +import saveFormEvent from './saveFormEvent' +import saveOrder from './saveOrder' +import saveProductEvent from './saveProductEvent' +import saveSearchEvent from './saveSearchEvent' +import saveUser from './saveUser' + +export type AuthResponseType = { + iat: number + exp: number + sub: string + scopes: string + iss: string + jti: string +} + +const destination: DestinationDefinition = { + name: 'Angler AI', + slug: 'actions-angler-ai', + description: 'Send analytics events to Angler AI.', + mode: 'cloud', + + authentication: { + scheme: 'custom', + fields: { + accessToken: { + label: 'Authentication Token', + description: 'Your Angler AI API Authentication Token', + type: 'password', + required: true + }, + workspaceId: { + label: 'Workspace ID', + description: 'Your Angler AI Workspace ID', + type: 'string', + required: true + } + }, + testAuthentication: async (request, options) => { + const me = await request(baseURL + testEndpoint(), { + method: 'get' + }) + + if (me.data.sub !== options.settings.workspaceId) { + throw new IntegrationError( + 'Authentication Invalid. Please Check Workspace Id & Token.', + ErrorCodes.INVALID_AUTHENTICATION, + 400 + ) + } + + if (!me.data.scopes.split(',').includes('DATA_ADMIN')) { + throw new IntegrationError( + 'The token provided must have admin privileges.', + ErrorCodes.INVALID_AUTHENTICATION, + 400 + ) + } + } + }, + + extendRequest({ settings }) { + return { + headers: { Authorization: `Bearer ${settings.accessToken}` } + } + }, + + onDelete: async (request, { settings, payload }) => { + return request(privacyEndpoint(settings.workspaceId), { + method: 'post', + json: { + customer: { + id: payload.userId + }, + source: 'segment' + } + }) + }, + + presets, + + actions: { + saveOrder, + saveUser, + saveBaseEvent, + saveCartEvent, + saveCheckoutEvent, + saveCollectionEvent, + saveCustomEvent, + saveFormEvent, + saveProductEvent, + saveSearchEvent + } +} + +export default destination diff --git a/packages/destination-actions/src/destinations/angler-ai/presets.ts b/packages/destination-actions/src/destinations/angler-ai/presets.ts new file mode 100644 index 0000000000..c1a4968a03 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/presets.ts @@ -0,0 +1,160 @@ +import type { DestinationDefinition } from '@segment/actions-core' +import { defaultValues } from '@segment/actions-core' +import saveBaseEvent from './saveBaseEvent' +import saveCartEvent from './saveCartEvent' +import saveCheckoutEvent from './saveCheckoutEvent' +import saveCollectionEvent from './saveCollectionEvent' +import saveFormEvent from './saveFormEvent' +import saveProductEvent from './saveProductEvent' +import saveSearchEvent from './saveSearchEvent' +import saveUser from './saveUser' + +export const presets: DestinationDefinition['presets'] = [ + { + name: 'Save User', + subscribe: 'type = "identify"', + partnerAction: 'saveUser', + mapping: defaultValues(saveUser.fields), + type: 'automatic' + }, + { + name: 'Save Event - Page Viewed', + subscribe: 'type = "page"', + partnerAction: 'saveBaseEvent', + mapping: { + ...defaultValues(saveBaseEvent.fields), + eventName: { '@template': 'page_viewed' } + }, + type: 'automatic' + }, + { + name: 'Save Event - Cart Viewed', + subscribe: 'event = "Cart Viewed"', + partnerAction: 'saveBaseEvent', + mapping: { + ...defaultValues(saveBaseEvent.fields), + eventName: { '@template': 'cart_viewed' } + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Address Info Submitted', + subscribe: 'event = "Checkout Address Info Submitted"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_address_info_submitted' + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Completed', + subscribe: 'event = "Order Completed"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_completed' + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Contact Info Submitted', + subscribe: 'event = "Checkout Contact Info Submitted"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_contact_info_submitted' + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Shipping Info Submitted', + subscribe: 'event = "Checkout Shipping Info Submitted"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_shipping_info_submitted' + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Started', + subscribe: 'event = "Checkout Started"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_started' + }, + type: 'automatic' + }, + { + name: 'Save Event - Checkout Payment Info Submitted', + subscribe: 'event = "Payment Info Entered"', + partnerAction: 'saveCheckoutEvent', + mapping: { + ...defaultValues(saveCheckoutEvent.fields), + eventName: 'checkout_payment_info_submitted' + }, + type: 'automatic' + }, + { + name: 'Save Event - Collection Viewed', + subscribe: 'event = "Product List Viewed"', + partnerAction: 'saveCollectionEvent', + mapping: { + ...defaultValues(saveCollectionEvent.fields), + eventName: 'collection_viewed' + }, + type: 'automatic' + }, + { + name: 'Save Event - Search Submitted', + subscribe: 'event = "Products Searched"', + partnerAction: 'saveSearchEvent', + mapping: { + ...defaultValues(saveSearchEvent.fields), + eventName: 'search_submitted' + }, + type: 'automatic' + }, + { + name: 'Save Event - Product Added To Cart', + subscribe: 'event = "Product Added"', + partnerAction: 'saveCartEvent', + mapping: { + ...defaultValues(saveCartEvent.fields), + eventName: 'product_added_to_cart' + }, + type: 'automatic' + }, + { + name: 'Save Event - Product Removed From Cart', + subscribe: 'event = "Product Removed"', + partnerAction: 'saveCartEvent', + mapping: { + ...defaultValues(saveCartEvent.fields), + eventName: 'product_removed_from_cart' + }, + type: 'automatic' + }, + { + name: 'Save Event - Product Viewed', + subscribe: 'event = "Product Viewed"', + partnerAction: 'saveProductEvent', + mapping: { + ...defaultValues(saveProductEvent.fields), + eventName: 'product_viewed' + }, + type: 'automatic' + }, + { + name: 'Save Event - Form Submitted', + subscribe: 'event = "Form Submitted"', + partnerAction: 'saveFormEvent', + mapping: { + ...defaultValues(saveFormEvent.fields), + eventName: 'form_submitted' + }, + type: 'automatic' + } +] diff --git a/packages/destination-actions/src/destinations/angler-ai/routes.ts b/packages/destination-actions/src/destinations/angler-ai/routes.ts new file mode 100644 index 0000000000..47d372ac97 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/routes.ts @@ -0,0 +1,29 @@ +export const baseURL = 'https://data.getangler.ai' + +export const testEndpoint = () => { + return `/v1/me` +} + +export const eventsEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/events` +} + +export const ordersEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/data/orders` +} + +export const customersEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/data/orders` +} + +export const lineItemsEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/data/line_items` +} + +export const productsEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/data/products` +} + +export const privacyEndpoint = (workspaceId: string) => { + return `/v1/workspaces/${workspaceId}/privacy/redact` +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..36b3bb5924 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,100 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveBaseEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "bq$C8Z$A", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": -55721452288081.92, + "currencyCode": "bq$C8Z$A", + }, + }, + "id": "bq$C8Z$A", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": -55721452288081.92, + }, + }, + "merchandise": Object { + "id": "bq$C8Z$A", + "image": Object { + "src": "bq$C8Z$A", + }, + "price": Object { + "amount": -55721452288081.92, + }, + "product": Object { + "title": "bq$C8Z$A", + "type": "bq$C8Z$A", + "untranslatedTitle": "bq$C8Z$A", + "url": "bq$C8Z$A", + "vendor": "bq$C8Z$A", + }, + "sku": "bq$C8Z$A", + "title": "bq$C8Z$A", + "untranslatedTitle": "bq$C8Z$A", + }, + "quantity": -55721452288081.92, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "bq$C8Z$A", + }, + ], + "customer": Object { + "dob": "bq$C8Z$A", + "email": "gokkah@fukeduz.kn", + "firstName": "bq$C8Z$A", + "id": "bq$C8Z$A", + "lastName": "bq$C8Z$A", + "phone": "bq$C8Z$A", + }, + }, + "event_id": "bq$C8Z$A", + "event_name": "page_viewed", + "fbc": "bq$C8Z$A", + "fpb": "bq$C8Z$A", + "ga": "bq$C8Z$A", + "identifiers": Array [], + "ip_address": "bq$C8Z$A", + "referrer": "bq$C8Z$A", + "timestamp": "bq$C8Z$A", + "url": "bq$C8Z$A", + "user_agent": "bq$C8Z$A", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveBaseEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "bq$C8Z$A", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "bq$C8Z$A", + "event_name": "page_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..ca08ce06e3 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveBaseEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveBaseEvent', { + event, + mapping: { + eventName: 'page_viewed' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..3b978c21c9 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/__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 = 'saveBaseEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveBaseEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/generated-types.ts new file mode 100644 index 0000000000..22e05b531d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/generated-types.ts @@ -0,0 +1,164 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * The name of the event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/index.ts new file mode 100644 index 0000000000..e7594a07fa --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/index.ts @@ -0,0 +1,42 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Base Event', + description: 'Send a base event that has the basic fields applicable to all events.', + fields: { + ...commonFields, + ...customerFields, + ...cartFields, + eventName: { + label: 'Event Name', + type: 'string', + description: 'The name of the event to track.', + required: true, + choices: [ + { label: 'page_viewed', value: 'page_viewed' }, + { label: 'cart_viewed', value: 'cart_viewed' } + ] + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/transform-payload.ts new file mode 100644 index 0000000000..c0526e976b --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveBaseEvent/transform-payload.ts @@ -0,0 +1,19 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCustomer(payload), + ...transformCart(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..f81db6674e --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveCartEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "C)6#KZenr)fGyu%KjQ", + "data": Object { + "cartLine": Object { + "cost": Object { + "totalAmount": Object { + "amount": 57986244453335.04, + }, + }, + "merchandise": Object { + "id": "C)6#KZenr)fGyu%KjQ", + "image": Object { + "src": "C)6#KZenr)fGyu%KjQ", + }, + "price": Object { + "amount": 57986244453335.04, + }, + "product": Object { + "title": "C)6#KZenr)fGyu%KjQ", + "type": "C)6#KZenr)fGyu%KjQ", + "untranslatedTitle": "C)6#KZenr)fGyu%KjQ", + "url": "C)6#KZenr)fGyu%KjQ", + "vendor": "C)6#KZenr)fGyu%KjQ", + }, + "sku": "C)6#KZenr)fGyu%KjQ", + "title": "C)6#KZenr)fGyu%KjQ", + "untranslatedTitle": "C)6#KZenr)fGyu%KjQ", + }, + "quantity": 57986244453335.04, + }, + "customData": Array [ + Object { + "name": "testType", + "value": "C)6#KZenr)fGyu%KjQ", + }, + ], + "customer": Object { + "dob": "C)6#KZenr)fGyu%KjQ", + "email": "gacan@pe.ss", + "firstName": "C)6#KZenr)fGyu%KjQ", + "id": "C)6#KZenr)fGyu%KjQ", + "lastName": "C)6#KZenr)fGyu%KjQ", + "phone": "C)6#KZenr)fGyu%KjQ", + }, + }, + "event_id": "C)6#KZenr)fGyu%KjQ", + "event_name": "product_removed_from_cart", + "fbc": "C)6#KZenr)fGyu%KjQ", + "fpb": "C)6#KZenr)fGyu%KjQ", + "ga": "C)6#KZenr)fGyu%KjQ", + "identifiers": Array [], + "ip_address": "C)6#KZenr)fGyu%KjQ", + "referrer": "C)6#KZenr)fGyu%KjQ", + "timestamp": "C)6#KZenr)fGyu%KjQ", + "url": "C)6#KZenr)fGyu%KjQ", + "user_agent": "C)6#KZenr)fGyu%KjQ", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveCartEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "C)6#KZenr)fGyu%KjQ", + "data": Object { + "cartLine": Object { + "cost": Object { + "totalAmount": Object {}, + }, + "merchandise": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "C)6#KZenr)fGyu%KjQ", + "event_name": "product_removed_from_cart", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..d549794bfd --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveCartEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveCartEvent', { + event, + mapping: { + eventName: 'product_added_to_cart' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..7d4fe27db7 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/__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 = 'saveCartEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveCartEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/generated-types.ts new file mode 100644 index 0000000000..8ce92e77b5 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/generated-types.ts @@ -0,0 +1,147 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart Line details + */ + cartLine?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + } + /** + * The name of the Cart Event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/index.ts new file mode 100644 index 0000000000..eb4de7d50a --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/index.ts @@ -0,0 +1,42 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartLineFields } from '../fields/cartLineFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Cart Event', + description: 'Save a cart event.', + fields: { + ...commonFields, + ...customerFields, + ...cartLineFields, + eventName: { + label: 'Cart Event Name', + type: 'string', + description: 'The name of the Cart Event to track.', + required: true, + choices: [ + { label: 'product_added_to_cart', value: 'product_added_to_cart' }, + { label: 'product_removed_from_cart', value: 'product_removed_from_cart' } + ] + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/transform-payload.ts new file mode 100644 index 0000000000..8bf43469f0 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCartEvent/transform-payload.ts @@ -0,0 +1,19 @@ +import { transformCartLine } from '../transformFields/transformCartLine' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCustomer(payload), + ...transformCartLine(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..d9b2efcab1 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,136 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveCheckoutEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "&yVQWLT2[LyiR]Lnd6^", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "checkout": Object { + "currencyCode": "&yVQWLT2[LyiR]Lnd6^", + "lineItems": Array [ + Object { + "discountAllocations": Array [ + Object { + "amount": Object { + "amount": 73487254164602.88, + }, + "discountApplication": Object { + "title": "&yVQWLT2[LyiR]Lnd6^", + "value": Object { + "amount": 73487254164602.88, + }, + }, + }, + ], + "id": "&yVQWLT2[LyiR]Lnd6^", + "quantity": 73487254164602.88, + "title": "&yVQWLT2[LyiR]Lnd6^", + "variant": Object { + "id": "&yVQWLT2[LyiR]Lnd6^", + "image": Object { + "src": "&yVQWLT2[LyiR]Lnd6^", + }, + "price": Object { + "amount": 73487254164602.88, + }, + "product": Object { + "id": "&yVQWLT2[LyiR]Lnd6^", + "title": "&yVQWLT2[LyiR]Lnd6^", + "type": "&yVQWLT2[LyiR]Lnd6^", + "untranslatedTitle": "&yVQWLT2[LyiR]Lnd6^", + "url": "&yVQWLT2[LyiR]Lnd6^", + "vendor": "&yVQWLT2[LyiR]Lnd6^", + }, + "sku": "&yVQWLT2[LyiR]Lnd6^", + "title": "&yVQWLT2[LyiR]Lnd6^", + "untranslatedTitle": "&yVQWLT2[LyiR]Lnd6^", + }, + }, + ], + "order": Object { + "id": "&yVQWLT2[LyiR]Lnd6^", + }, + "shippingLine": Object { + "price": Object { + "amount": 73487254164602.88, + }, + }, + "subtotalPrice": Object { + "amount": 73487254164602.88, + }, + "totalPrice": Object { + "amount": 73487254164602.88, + }, + "totalTax": Object { + "amount": 73487254164602.88, + }, + }, + "customData": Array [ + Object { + "name": "testType", + "value": "&yVQWLT2[LyiR]Lnd6^", + }, + ], + "customer": Object { + "dob": "&yVQWLT2[LyiR]Lnd6^", + "email": "eprer@gih.ne", + "firstName": "&yVQWLT2[LyiR]Lnd6^", + "id": "&yVQWLT2[LyiR]Lnd6^", + "lastName": "&yVQWLT2[LyiR]Lnd6^", + "phone": "&yVQWLT2[LyiR]Lnd6^", + }, + }, + "event_id": "&yVQWLT2[LyiR]Lnd6^", + "event_name": "checkout_started", + "fbc": "&yVQWLT2[LyiR]Lnd6^", + "fpb": "&yVQWLT2[LyiR]Lnd6^", + "ga": "&yVQWLT2[LyiR]Lnd6^", + "identifiers": Array [], + "ip_address": "&yVQWLT2[LyiR]Lnd6^", + "referrer": "&yVQWLT2[LyiR]Lnd6^", + "timestamp": "&yVQWLT2[LyiR]Lnd6^", + "url": "&yVQWLT2[LyiR]Lnd6^", + "user_agent": "&yVQWLT2[LyiR]Lnd6^", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveCheckoutEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "&yVQWLT2[LyiR]Lnd6^", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "checkout": Object { + "order": Object {}, + "shippingLine": Object { + "price": Object {}, + }, + "subtotalPrice": Object {}, + "totalPrice": Object {}, + "totalTax": Object {}, + }, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "&yVQWLT2[LyiR]Lnd6^", + "event_name": "checkout_started", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..a3482aee5f --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveCheckoutEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveCheckoutEvent', { + event, + mapping: { + eventName: 'checkout_started' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..4b6a03018d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/__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 = 'saveCheckoutEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveCheckoutEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/generated-types.ts new file mode 100644 index 0000000000..34933bbe11 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/generated-types.ts @@ -0,0 +1,184 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Checkout details + */ + checkout?: { + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + /** + * The ID of the order associated with this checkout. + */ + orderId?: string + /** + * A monetary value. + */ + subtotalPriceAmount?: number + /** + * A monetary value with currency. + */ + totalTaxAmount?: number + /** + * A monetary value. + */ + shippingLinePriceAmount?: number + } + /** + * Checkout Line Item details + */ + checkoutLineItems?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + /** + * The Discount Code applied to the item. + */ + discountTitle?: string + /** + * The Discount value applied to the item. + */ + discountValue?: number + }[] + /** + * The name of the Checkout Event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/index.ts new file mode 100644 index 0000000000..5e5e28c3a8 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/index.ts @@ -0,0 +1,45 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { checkoutFields } from '../fields/checkoutFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Checkout Event', + description: 'Save a checkout event.', + fields: { + ...commonFields, + ...customerFields, + ...checkoutFields, + eventName: { + label: 'Checkout Event Name', + type: 'string', + description: 'The name of the Checkout Event to track.', + required: true, + choices: [ + { label: 'checkout_address_info_submitted', value: 'checkout_address_info_submitted' }, + { label: 'checkout_completed', value: 'checkout_completed' }, + { label: 'checkout_contact_info_submitted', value: 'checkout_contact_info_submitted' }, + { label: 'checkout_shipping_info_submitted', value: 'checkout_shipping_info_submitted' }, + { label: 'checkout_started', value: 'checkout_started' } + ] + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/transform-payload.ts new file mode 100644 index 0000000000..985c7361a7 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCheckoutEvent/transform-payload.ts @@ -0,0 +1,21 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCheckout } from '../transformFields/transformCheckout' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCustomer(payload), + ...transformCart(payload), + ...transformCheckout(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..6ede20cdf8 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,127 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveCollectionEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "!rMDy$ShoCe*^$(%J2H", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 77185613761085.44, + "currencyCode": "!rMDy$ShoCe*^$(%J2H", + }, + }, + "id": "!rMDy$ShoCe*^$(%J2H", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 77185613761085.44, + }, + }, + "merchandise": Object { + "id": "!rMDy$ShoCe*^$(%J2H", + "image": Object { + "src": "!rMDy$ShoCe*^$(%J2H", + }, + "price": Object { + "amount": 77185613761085.44, + }, + "product": Object { + "title": "!rMDy$ShoCe*^$(%J2H", + "type": "!rMDy$ShoCe*^$(%J2H", + "untranslatedTitle": "!rMDy$ShoCe*^$(%J2H", + "url": "!rMDy$ShoCe*^$(%J2H", + "vendor": "!rMDy$ShoCe*^$(%J2H", + }, + "sku": "!rMDy$ShoCe*^$(%J2H", + "title": "!rMDy$ShoCe*^$(%J2H", + "untranslatedTitle": "!rMDy$ShoCe*^$(%J2H", + }, + "quantity": 77185613761085.44, + }, + ], + }, + "collection": Object { + "id": "!rMDy$ShoCe*^$(%J2H", + "productVariants": Array [ + Object { + "id": "!rMDy$ShoCe*^$(%J2H", + "image": Object { + "src": "!rMDy$ShoCe*^$(%J2H", + }, + "price": Object { + "amount": 77185613761085.44, + }, + "product": Object { + "id": "!rMDy$ShoCe*^$(%J2H", + "title": "!rMDy$ShoCe*^$(%J2H", + "type": "!rMDy$ShoCe*^$(%J2H", + "untranslatedTitle": "!rMDy$ShoCe*^$(%J2H", + "url": "!rMDy$ShoCe*^$(%J2H", + "vendor": "!rMDy$ShoCe*^$(%J2H", + }, + "sku": "!rMDy$ShoCe*^$(%J2H", + "title": "!rMDy$ShoCe*^$(%J2H", + "untranslatedTitle": "!rMDy$ShoCe*^$(%J2H", + }, + ], + "title": "!rMDy$ShoCe*^$(%J2H", + }, + "customData": Array [ + Object { + "name": "testType", + "value": "!rMDy$ShoCe*^$(%J2H", + }, + ], + "customer": Object { + "dob": "!rMDy$ShoCe*^$(%J2H", + "email": "moprub@peviggu.co.uk", + "firstName": "!rMDy$ShoCe*^$(%J2H", + "id": "!rMDy$ShoCe*^$(%J2H", + "lastName": "!rMDy$ShoCe*^$(%J2H", + "phone": "!rMDy$ShoCe*^$(%J2H", + }, + }, + "event_id": "!rMDy$ShoCe*^$(%J2H", + "event_name": "collection_viewed", + "fbc": "!rMDy$ShoCe*^$(%J2H", + "fpb": "!rMDy$ShoCe*^$(%J2H", + "ga": "!rMDy$ShoCe*^$(%J2H", + "identifiers": Array [], + "ip_address": "!rMDy$ShoCe*^$(%J2H", + "referrer": "!rMDy$ShoCe*^$(%J2H", + "timestamp": "!rMDy$ShoCe*^$(%J2H", + "url": "!rMDy$ShoCe*^$(%J2H", + "user_agent": "!rMDy$ShoCe*^$(%J2H", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveCollectionEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "!rMDy$ShoCe*^$(%J2H", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "collection": Object {}, + "customData": Array [], + "customer": Object {}, + }, + "event_id": "!rMDy$ShoCe*^$(%J2H", + "event_name": "collection_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..2823e19028 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveCollectionEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveCollectionEvent', { + event: { + ...event, + event: 'collection_viewed' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..c1291aeca8 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/__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 = 'saveCollectionEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveCollectionEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/generated-types.ts new file mode 100644 index 0000000000..f7ef17c262 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/generated-types.ts @@ -0,0 +1,222 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * Collection details + */ + collection?: { + /** + * A globally unique identifier for the collection. + */ + id?: string + /** + * The collection title. + */ + title?: string + } + /** + * A list of product variants associated with the collection. + */ + collectionProductVariants?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + }[] + /** + * The name of the Collection Event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/index.ts new file mode 100644 index 0000000000..3a3c219e65 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/index.ts @@ -0,0 +1,43 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { collectionFields } from '../fields/collectionFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Collection Event', + description: 'Save a collection event.', + fields: { + ...commonFields, + ...customerFields, + ...cartFields, + ...collectionFields, + eventName: { + label: 'Collection Event Name', + type: 'string', + description: 'The name of the Collection Event to track.', + required: true, + readOnly: true, + choices: [{ label: 'collection_viewed', value: 'collection_viewed' }], + default: 'collection_viewed' + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/transform-payload.ts new file mode 100644 index 0000000000..7e979aa5e1 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCollectionEvent/transform-payload.ts @@ -0,0 +1,21 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCollection } from '../transformFields/transformCollection' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCustomer(payload), + ...transformCart(payload), + ...transformCollection(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..5d33531aba --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,300 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveCustomEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "VjtX1zqO^*9PrF@2", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 33800216662507.52, + "currencyCode": "VjtX1zqO^*9PrF@2", + }, + }, + "id": "VjtX1zqO^*9PrF@2", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 33800216662507.52, + }, + }, + "merchandise": Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + "quantity": 33800216662507.52, + }, + ], + }, + "cartLine": Object { + "cost": Object { + "totalAmount": Object { + "amount": 33800216662507.52, + }, + }, + "merchandise": Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + "quantity": 33800216662507.52, + }, + "checkout": Object { + "currencyCode": "VjtX1zqO^*9PrF@2", + "lineItems": Array [ + Object { + "discountAllocations": Array [ + Object { + "amount": Object { + "amount": 33800216662507.52, + }, + "discountApplication": Object { + "title": "VjtX1zqO^*9PrF@2", + "value": Object { + "amount": 33800216662507.52, + }, + }, + }, + ], + "id": "VjtX1zqO^*9PrF@2", + "quantity": 33800216662507.52, + "title": "VjtX1zqO^*9PrF@2", + "variant": Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "id": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + }, + ], + "order": Object { + "id": "VjtX1zqO^*9PrF@2", + }, + "shippingLine": Object { + "price": Object { + "amount": 33800216662507.52, + }, + }, + "subtotalPrice": Object { + "amount": 33800216662507.52, + }, + "totalPrice": Object { + "amount": 33800216662507.52, + }, + "totalTax": Object { + "amount": 33800216662507.52, + }, + }, + "collection": Object { + "id": "VjtX1zqO^*9PrF@2", + "productVariants": Array [ + Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "id": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + ], + "title": "VjtX1zqO^*9PrF@2", + }, + "customData": Array [ + Object { + "name": "testType", + "value": "VjtX1zqO^*9PrF@2", + }, + ], + "customer": Object { + "dob": "VjtX1zqO^*9PrF@2", + "email": "co@museku.fr", + "firstName": "VjtX1zqO^*9PrF@2", + "id": "VjtX1zqO^*9PrF@2", + "lastName": "VjtX1zqO^*9PrF@2", + "phone": "VjtX1zqO^*9PrF@2", + }, + "form": Object { + "action": "VjtX1zqO^*9PrF@2", + "elements": Array [ + Object { + "id": "VjtX1zqO^*9PrF@2", + "name": "VjtX1zqO^*9PrF@2", + "tagName": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "value": "VjtX1zqO^*9PrF@2", + }, + ], + "id": "VjtX1zqO^*9PrF@2", + }, + "productVariant": Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "id": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + "searchResult": Object { + "productVariants": Array [ + Object { + "id": "VjtX1zqO^*9PrF@2", + "image": Object { + "src": "VjtX1zqO^*9PrF@2", + }, + "price": Object { + "amount": 33800216662507.52, + }, + "product": Object { + "id": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "type": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "vendor": "VjtX1zqO^*9PrF@2", + }, + "sku": "VjtX1zqO^*9PrF@2", + "title": "VjtX1zqO^*9PrF@2", + "untranslatedTitle": "VjtX1zqO^*9PrF@2", + }, + ], + "query": "VjtX1zqO^*9PrF@2", + }, + }, + "event_id": "VjtX1zqO^*9PrF@2", + "event_name": "product_removed_from_cart", + "fbc": "VjtX1zqO^*9PrF@2", + "fpb": "VjtX1zqO^*9PrF@2", + "ga": "VjtX1zqO^*9PrF@2", + "identifiers": Array [], + "ip_address": "VjtX1zqO^*9PrF@2", + "referrer": "VjtX1zqO^*9PrF@2", + "timestamp": "VjtX1zqO^*9PrF@2", + "url": "VjtX1zqO^*9PrF@2", + "user_agent": "VjtX1zqO^*9PrF@2", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveCustomEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "VjtX1zqO^*9PrF@2", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "cartLine": Object { + "cost": Object { + "totalAmount": Object {}, + }, + "merchandise": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "checkout": Object { + "order": Object {}, + "shippingLine": Object { + "price": Object {}, + }, + "subtotalPrice": Object {}, + "totalPrice": Object {}, + "totalTax": Object {}, + }, + "collection": Object {}, + "customData": Array [], + "customer": Object {}, + "form": Object { + "id": "VjtX1zqO^*9PrF@2", + }, + "productVariant": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + "searchResult": Object {}, + }, + "event_id": "VjtX1zqO^*9PrF@2", + "event_name": "product_removed_from_cart", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..0920e22db2 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/index.test.ts @@ -0,0 +1,36 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveCustomEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveCustomEvent', { + event, + mapping: { + eventId: '1234567890', + eventName: 'custom_event', + customEventName: 'custom_event_name', + identifiers: { clientId: '1234567890' } + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..1a6827d0f3 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/__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 = 'saveCustomEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveCustomEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/generated-types.ts new file mode 100644 index 0000000000..78f4d57b24 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/generated-types.ts @@ -0,0 +1,488 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * Cart Line details + */ + cartLine?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + } + /** + * Checkout details + */ + checkout?: { + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + /** + * The ID of the order associated with this checkout. + */ + orderId?: string + /** + * A monetary value. + */ + subtotalPriceAmount?: number + /** + * A monetary value with currency. + */ + totalTaxAmount?: number + /** + * A monetary value. + */ + shippingLinePriceAmount?: number + } + /** + * Checkout Line Item details + */ + checkoutLineItems?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + /** + * The Discount Code applied to the item. + */ + discountTitle?: string + /** + * The Discount value applied to the item. + */ + discountValue?: number + }[] + /** + * Collection details + */ + collection?: { + /** + * A globally unique identifier for the collection. + */ + id?: string + /** + * The collection title. + */ + title?: string + } + /** + * A list of product variants associated with the collection. + */ + collectionProductVariants?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + }[] + /** + * The id attribute of an element. + */ + id?: string + /** + * The action attribute of a form element. + */ + action?: string + /** + * A list of elements associated with the form. + */ + elements?: { + /** + * The id attribute of an element. + */ + id?: string + /** + * The name attribute of an element. + */ + name?: string + /** + * A string representation of the tag of an element. + */ + tagName?: string + /** + * The type attribute of an element. Often relevant for an input or button element. + */ + type?: string + /** + * The value attribute of an element. Often relevant for an input element. + */ + value?: string + }[] + /** + * Product Variant details + */ + productVariant?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + } + /** + * Search results details + */ + searchResults?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + }[] + /** + * The search query that was executed. + */ + query?: string + /** + * The name of the event to track. + */ + eventName: string + /** + * Additional name for custom events if 'event_name' is 'custom_event'. + */ + customEventName?: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/index.ts new file mode 100644 index 0000000000..060894f1ef --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/index.ts @@ -0,0 +1,88 @@ +import type { ActionDefinition, InputField } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { cartLineFields } from '../fields/cartLineFields' +import { checkoutFields } from '../fields/checkoutFields' +import { collectionFields } from '../fields/collectionFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import { formFields } from '../fields/formFields' +import { productVariantFields } from '../fields/productVariantFields' +import { searchFields } from '../fields/searchFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +function removeDefaults(fields: Record) { + return Object.entries(fields).reduce((acc, [key, field]) => { + const { default: _, ...fieldWithoutDefault } = field + return { ...acc, [key]: fieldWithoutDefault } + }, {}) +} + +const action: ActionDefinition = { + title: 'Save Custom Event', + description: 'Save a custom event that may have any fields.', + fields: { + ...removeDefaults(commonFields), + ...removeDefaults(customerFields), + ...removeDefaults(cartFields), + ...removeDefaults(cartLineFields), + ...removeDefaults(checkoutFields), + ...removeDefaults(collectionFields), + ...removeDefaults(formFields), + ...removeDefaults(productVariantFields), + ...removeDefaults(searchFields), + eventName: { + label: 'Event Name', + type: 'string', + description: 'The name of the event to track.', + required: true, + choices: [ + { label: 'page_viewed', value: 'page_viewed' }, + { label: 'cart_viewed', value: 'cart_viewed' }, + { label: 'checkout_address_info_submitted', value: 'checkout_address_info_submitted' }, + { label: 'checkout_completed', value: 'checkout_completed' }, + { label: 'checkout_contact_info_submitted', value: 'checkout_contact_info_submitted' }, + { label: 'checkout_shipping_info_submitted', value: 'checkout_shipping_info_submitted' }, + { label: 'checkout_started', value: 'checkout_started' }, + { label: 'collection_viewed', value: 'collection_viewed' }, + { label: 'payment_info_submitted', value: 'payment_info_submitted' }, + { label: 'product_added_to_cart', value: 'product_added_to_cart' }, + { label: 'product_removed_from_cart', value: 'product_removed_from_cart' }, + { label: 'product_viewed', value: 'product_viewed' }, + { label: 'search_submitted', value: 'search_submitted' }, + { label: 'form_submitted', value: 'form_submitted' }, + { label: 'custom_event', value: 'custom_event' } + ] + }, + customEventName: { + label: 'Custom Event Name', + type: 'string', + description: "Additional name for custom events if 'event_name' is 'custom_event'.", + depends_on: { + conditions: [ + { + fieldKey: 'eventName', + value: 'custom_event', + operator: 'is' + } + ] + } + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/transform-payload.ts new file mode 100644 index 0000000000..d00540b631 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveCustomEvent/transform-payload.ts @@ -0,0 +1,31 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCartLine } from '../transformFields/transformCartLine' +import { transformCheckout } from '../transformFields/transformCheckout' +import { transformCollection } from '../transformFields/transformCollection' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { transformForm } from '../transformFields/transformForm' +import { transformProductVariant } from '../transformFields/transformProductVariant' +import { transformSearch } from '../transformFields/transformSearch' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCustomer(payload), + ...transformCart(payload), + ...transformCartLine(payload), + ...transformCheckout(payload), + ...transformCollection(payload), + ...transformForm(payload), + ...transformProductVariant(payload), + ...transformSearch(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..4d10ac97ac --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,116 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveFormEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "3qODCwqyQBu%vq^Yajvl", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 85712588620431.36, + "currencyCode": "3qODCwqyQBu%vq^Yajvl", + }, + }, + "id": "3qODCwqyQBu%vq^Yajvl", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 85712588620431.36, + }, + }, + "merchandise": Object { + "id": "3qODCwqyQBu%vq^Yajvl", + "image": Object { + "src": "3qODCwqyQBu%vq^Yajvl", + }, + "price": Object { + "amount": 85712588620431.36, + }, + "product": Object { + "title": "3qODCwqyQBu%vq^Yajvl", + "type": "3qODCwqyQBu%vq^Yajvl", + "untranslatedTitle": "3qODCwqyQBu%vq^Yajvl", + "url": "3qODCwqyQBu%vq^Yajvl", + "vendor": "3qODCwqyQBu%vq^Yajvl", + }, + "sku": "3qODCwqyQBu%vq^Yajvl", + "title": "3qODCwqyQBu%vq^Yajvl", + "untranslatedTitle": "3qODCwqyQBu%vq^Yajvl", + }, + "quantity": 85712588620431.36, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "3qODCwqyQBu%vq^Yajvl", + }, + ], + "customer": Object { + "dob": "3qODCwqyQBu%vq^Yajvl", + "email": "wof@ohaow.cv", + "firstName": "3qODCwqyQBu%vq^Yajvl", + "id": "3qODCwqyQBu%vq^Yajvl", + "lastName": "3qODCwqyQBu%vq^Yajvl", + "phone": "3qODCwqyQBu%vq^Yajvl", + }, + "form": Object { + "action": "3qODCwqyQBu%vq^Yajvl", + "elements": Array [ + Object { + "id": "3qODCwqyQBu%vq^Yajvl", + "name": "3qODCwqyQBu%vq^Yajvl", + "tagName": "3qODCwqyQBu%vq^Yajvl", + "type": "3qODCwqyQBu%vq^Yajvl", + "value": "3qODCwqyQBu%vq^Yajvl", + }, + ], + "id": "3qODCwqyQBu%vq^Yajvl", + }, + }, + "event_id": "3qODCwqyQBu%vq^Yajvl", + "event_name": "form_submitted", + "fbc": "3qODCwqyQBu%vq^Yajvl", + "fpb": "3qODCwqyQBu%vq^Yajvl", + "ga": "3qODCwqyQBu%vq^Yajvl", + "identifiers": Array [], + "ip_address": "3qODCwqyQBu%vq^Yajvl", + "referrer": "3qODCwqyQBu%vq^Yajvl", + "timestamp": "3qODCwqyQBu%vq^Yajvl", + "url": "3qODCwqyQBu%vq^Yajvl", + "user_agent": "3qODCwqyQBu%vq^Yajvl", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveFormEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "3qODCwqyQBu%vq^Yajvl", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "form": Object { + "id": "3qODCwqyQBu%vq^Yajvl", + }, + }, + "event_id": "3qODCwqyQBu%vq^Yajvl", + "event_name": "form_submitted", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..c1d5bd1865 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveFormEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveFormEvent', { + event: { + ...event, + event: 'form_submitted' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..c77517dd5e --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/__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 = 'saveFormEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveFormEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/generated-types.ts new file mode 100644 index 0000000000..5a451214e2 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/generated-types.ts @@ -0,0 +1,197 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * The id attribute of an element. + */ + id?: string + /** + * The action attribute of a form element. + */ + action?: string + /** + * A list of elements associated with the form. + */ + elements?: { + /** + * The id attribute of an element. + */ + id?: string + /** + * The name attribute of an element. + */ + name?: string + /** + * A string representation of the tag of an element. + */ + tagName?: string + /** + * The type attribute of an element. Often relevant for an input or button element. + */ + type?: string + /** + * The value attribute of an element. Often relevant for an input element. + */ + value?: string + }[] + /** + * The name of the Form Event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/index.ts new file mode 100644 index 0000000000..5fab00f141 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/index.ts @@ -0,0 +1,43 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import { formFields } from '../fields/formFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Form Event', + description: 'Save a form event.', + fields: { + ...commonFields, + ...customerFields, + ...cartFields, + ...formFields, + eventName: { + label: 'Form Event Name', + type: 'string', + description: 'The name of the Form Event to track.', + required: true, + readOnly: true, + choices: [{ label: 'form_submitted', value: 'form_submitted' }], + default: 'form_submitted' + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/transform-payload.ts new file mode 100644 index 0000000000..90ae5cc9a5 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveFormEvent/transform-payload.ts @@ -0,0 +1,21 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { transformForm } from '../transformFields/transformForm' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCart(payload), + ...transformCustomer(payload), + ...transformForm(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..d95e69c852 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,149 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveOrder destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "additional_fields": Array [ + Object { + "name": "UIbymzz8amIPzalS", + "value": "UIbymzz8amIPzalS", + }, + ], + "billing_address": Object { + "address1": "UIbymzz8amIPzalS", + "address2": "UIbymzz8amIPzalS", + "city": "UIbymzz8amIPzalS", + "company": "UIbymzz8amIPzalS", + "country": "UIbymzz8amIPzalS", + "country_code": "UIbymzz8amIPzalS", + "country_name": "UIbymzz8amIPzalS", + "customer_id": "UIbymzz8amIPzalS", + "default": false, + "first_name": "UIbymzz8amIPzalS", + "hashed_address1": "UIbymzz8amIPzalS", + "hashed_address2": "UIbymzz8amIPzalS", + "hashed_city": "UIbymzz8amIPzalS", + "hashed_country_code": "UIbymzz8amIPzalS", + "hashed_first_name": "UIbymzz8amIPzalS", + "hashed_last_name": "UIbymzz8amIPzalS", + "hashed_phone": "UIbymzz8amIPzalS", + "hashed_zip": "UIbymzz8amIPzalS", + "id": "UIbymzz8amIPzalS", + "last_name": "UIbymzz8amIPzalS", + "name": "UIbymzz8amIPzalS", + "phone": "UIbymzz8amIPzalS", + "province": "UIbymzz8amIPzalS", + "province_code": "UIbymzz8amIPzalS", + "zip": "UIbymzz8amIPzalS", + }, + "browser_ip": "UIbymzz8amIPzalS", + "buyer_accepts_marketing": false, + "checkout_id": "UIbymzz8amIPzalS", + "client_details": Object { + "browser_ip": "UIbymzz8amIPzalS", + "user_agent": "UIbymzz8amIPzalS", + }, + "confirmed": false, + "contact_email": "UIbymzz8amIPzalS", + "created_at": "UIbymzz8amIPzalS", + "currency": "CZK", + "current_subtotal_price": "UIbymzz8amIPzalS", + "current_total_discounts": "UIbymzz8amIPzalS", + "current_total_price": "UIbymzz8amIPzalS", + "current_total_tax": "UIbymzz8amIPzalS", + "customer_id": "UIbymzz8amIPzalS", + "discount_applications": Array [ + Object { + "allocation_method": "UIbymzz8amIPzalS", + "code": "UIbymzz8amIPzalS", + "target_selection": "UIbymzz8amIPzalS", + "target_type": "UIbymzz8amIPzalS", + "type": "UIbymzz8amIPzalS", + "value": "UIbymzz8amIPzalS", + "value_type": "UIbymzz8amIPzalS", + }, + ], + "discount_codes": Array [ + Object { + "amount": "UIbymzz8amIPzalS", + "code": "UIbymzz8amIPzalS", + "type": "UIbymzz8amIPzalS", + }, + ], + "email": "ev@bezehu.co.uk", + "estimated_taxes": false, + "financial_status": "UIbymzz8amIPzalS", + "fulfillment_status": "UIbymzz8amIPzalS", + "gateway": "UIbymzz8amIPzalS", + "id": "UIbymzz8amIPzalS", + "landing_site": "UIbymzz8amIPzalS", + "landing_site_ref": "UIbymzz8amIPzalS", + "name": "UIbymzz8amIPzalS", + "order_number": 4357582131036160, + "phone": "UIbymzz8amIPzalS", + "processed_at": "UIbymzz8amIPzalS", + "processing_method": "UIbymzz8amIPzalS", + "reference": "UIbymzz8amIPzalS", + "referring_site": "UIbymzz8amIPzalS", + "shipping_address": Object { + "address1": "UIbymzz8amIPzalS", + "address2": "UIbymzz8amIPzalS", + "city": "UIbymzz8amIPzalS", + "company": "UIbymzz8amIPzalS", + "country": "UIbymzz8amIPzalS", + "country_code": "UIbymzz8amIPzalS", + "country_name": "UIbymzz8amIPzalS", + "customer_id": "UIbymzz8amIPzalS", + "default": false, + "first_name": "UIbymzz8amIPzalS", + "hashed_address1": "UIbymzz8amIPzalS", + "hashed_address2": "UIbymzz8amIPzalS", + "hashed_city": "UIbymzz8amIPzalS", + "hashed_country_code": "UIbymzz8amIPzalS", + "hashed_first_name": "UIbymzz8amIPzalS", + "hashed_last_name": "UIbymzz8amIPzalS", + "hashed_phone": "UIbymzz8amIPzalS", + "hashed_zip": "UIbymzz8amIPzalS", + "id": "UIbymzz8amIPzalS", + "last_name": "UIbymzz8amIPzalS", + "name": "UIbymzz8amIPzalS", + "phone": "UIbymzz8amIPzalS", + "province": "UIbymzz8amIPzalS", + "province_code": "UIbymzz8amIPzalS", + "zip": "UIbymzz8amIPzalS", + }, + "source_identifier": "UIbymzz8amIPzalS", + "source_name": "UIbymzz8amIPzalS", + "source_url": "UIbymzz8amIPzalS", + "subtotal_price": "UIbymzz8amIPzalS", + "tags": "UIbymzz8amIPzalS", + "taxes_included": false, + "total_discounts": "UIbymzz8amIPzalS", + "total_line_items_price": "UIbymzz8amIPzalS", + "total_outstanding": "UIbymzz8amIPzalS", + "total_price": "UIbymzz8amIPzalS", + "total_price_usd": "UIbymzz8amIPzalS", + "total_tax": "UIbymzz8amIPzalS", + "updated_at": "UIbymzz8amIPzalS", + "user_id": "UIbymzz8amIPzalS", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveOrder destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "checkout_id": "UIbymzz8amIPzalS", + "customer_id": "UIbymzz8amIPzalS", + "id": "UIbymzz8amIPzalS", + "source_identifier": "UIbymzz8amIPzalS", + "user_id": "UIbymzz8amIPzalS", + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/index.test.ts new file mode 100644 index 0000000000..57ee72499b --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/index.test.ts @@ -0,0 +1,32 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, ordersEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveOrder', () => { + const event = createTestEvent({ + properties: { id: 'test_event_id' } + }) + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = ordersEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveOrder', { + event, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..a6bb9f58b4 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveOrder/__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 = 'saveOrder' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveOrder/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveOrder/generated-types.ts new file mode 100644 index 0000000000..43d55bba6b --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveOrder/generated-types.ts @@ -0,0 +1,454 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The mailing address associated with the payment method. + */ + billing_address?: { + /** + * A unique identifier for the address. + */ + id?: string + /** + * The customer's mailing address. + */ + address1?: string + /** + * An additional field for the customer's mailing address. + */ + address2?: string + /** + * The customer's city, town, or village. + */ + city?: string + /** + * The customer's company. + */ + company?: string + /** + * The customer's country. + */ + country?: string + /** + * The two-letter country code corresponding to the customer's country + */ + country_code?: string + /** + * The customer's normalized country name. + */ + country_name?: string + /** + * A unique identifier for the customer. + */ + customer_id?: string + /** + * Whether this address is the default address for the customer. + */ + default?: boolean + /** + * The customer's first name. + */ + first_name?: string + /** + * The customer's last name. + */ + last_name?: string + /** + * The customer's first and last names. + */ + name?: string + /** + * The customer's phone number at this address. + */ + phone?: string + /** + * The customer's region name. Typically a province, a state, or a prefecture + */ + province?: string + /** + * The code for the region of the address, such as the province, state, or district. For example QC for Quebec, Canada. + */ + province_code?: string + /** + * The customer's postal code, also known as zip, postcode, Eircode, etc + */ + zip?: string + /** + * Hashed value of first name in SHA256 (lower case). + */ + hashed_first_name?: string + /** + * Hashed value of last name in SHA256 (lower case). + */ + hashed_last_name?: string + /** + * Hashed value of phone in SHA256 (lower case). + */ + hashed_phone?: string + /** + * Hashed value of address1 in SHA256 (lower case). + */ + hashed_address1?: string + /** + * Hashed value of address2 in SHA256 (lower case). + */ + hashed_address2?: string + /** + * Hashed value of city in SHA256 (lower case). + */ + hashed_city?: string + /** + * Hashed value of zip in SHA256 (lower case). + */ + hashed_zip?: string + /** + * Hashed value of country code in SHA256 (lower case). + */ + hashed_country_code?: string + } + /** + * The IP address of the browser used by the customer when they placed the order. Both IPv4 and IPv6 are supported. + */ + browser_ip?: string + /** + * Whether the customer consented to receive email updates from the shop. + */ + buyer_accepts_marketing?: boolean + /** + * The ID of the checkout. + */ + checkout_id?: string + /** + * Information about the browser that the customer used when they placed their order. + */ + client_details?: { + /** + * The browser IP address. + */ + browser_ip?: string + /** + * Details of the browsing client, including software and operating versions. + */ + user_agent?: string + } + /** + * Confirmed + */ + confirmed?: boolean + /** + * Contact Email + */ + contact_email?: string + /** + * The autogenerated date and time (ISO 8601 format) when the order was created. + */ + created_at?: string + /** + * The three-letter code (ISO 4217 format) for the currency that the customer used when they paid for their last order. + */ + currency?: string + /** + * The current subtotal price of the order in the shop currency. The value of this field reflects order edits, returns, and refunds. + */ + current_subtotal_price?: string + /** + * The current total discounts on the order in the shop currency. The value of this field reflects order edits, returns, and refunds. + */ + current_total_discounts?: string + /** + * The current total price of the order in the shop currency. The value of this field reflects order edits, returns, and refunds. + */ + current_total_price?: string + /** + * The current total taxes charged on the order in the shop currency. The value of this field reflects order edits, returns, or refunds. + */ + current_total_tax?: string + /** + * A unique identifier for the customer. + */ + customer_id?: string + /** + * An ordered list of stacked discount applications. The discount_applications property includes 3 types: discount_code, manual, and script. All 3 types share a common structure and have some type specific attributes. + */ + discount_applications?: { + /** + * The type of line on the order that the discount is applicable on. + */ + target_type?: string + /** + * The discount application type. + */ + type?: string + /** + * The value of the discount application as a decimal. This represents the intention of the discount application. + */ + value?: string + /** + * The type of the value. + */ + value_type?: string + /** + * The method by which the discount application value has been allocated to entitled lines. + */ + allocation_method?: string + /** + * The lines on the order, of the type defined by target_type, that the discount is allocated over. + */ + target_selection?: string + /** + * The discount code that was used to apply the discount. Available only for discount code applications. + */ + code?: string + }[] + /** + * A list of discounts applied to the order. + */ + discount_codes?: { + /** + * When the associated discount application is of type code, this property returns the discount code that was entered at checkout. Otherwise this property returns the title of the discount that was applied. + */ + code?: string + /** + * The amount that's deducted from the order total. When you create an order, this value is the percentage or monetary amount to deduct. After the order is created, this property returns the calculated amount. + */ + amount?: string + /** + * The type of discount. + */ + type?: string + }[] + /** + * The customer's email address. + */ + email?: string + /** + * Whether taxes on the order are estimated. Many factors can change between the time a customer places an order and the time the order is shipped, which could affect the calculation of taxes. + */ + estimated_taxes?: boolean + /** + * The status of payments associated with the order. + */ + financial_status?: string + /** + * The order's status in terms of fulfilled line items. + */ + fulfillment_status?: string + /** + * The payment gateway used. + */ + gateway?: string + /** + * The ID of the order, used for API purposes. + */ + id: string + /** + * The URL for the page where the buyer landed when they entered the shop. + */ + landing_site?: string + /** + * Landing Site Ref + */ + landing_site_ref?: string + /** + * The order name. + */ + name?: string + /** + * The order position in the shop count of orders starting at 1001. Order numbers are sequential and start at 1001. + */ + order_number?: number + /** + * The customer's phone number for receiving SMS notifications. + */ + phone?: string + /** + * The date and time (ISO 8601 format) when an order was processed. + */ + processed_at?: string + /** + * How the payment was processed. + */ + processing_method?: string + /** + * Reference + */ + reference?: string + /** + * The website where the customer clicked a link to the shop. + */ + referring_site?: string + /** + * The mailing address associated with the payment method. + */ + shipping_address?: { + /** + * A unique identifier for the address. + */ + id?: string + /** + * The customer's mailing address. + */ + address1?: string + /** + * An additional field for the customer's mailing address. + */ + address2?: string + /** + * The customer's city, town, or village. + */ + city?: string + /** + * The customer's company. + */ + company?: string + /** + * The customer's country. + */ + country?: string + /** + * The two-letter country code corresponding to the customer's country + */ + country_code?: string + /** + * The customer's normalized country name. + */ + country_name?: string + /** + * A unique identifier for the customer. + */ + customer_id?: string + /** + * Whether this address is the default address for the customer. + */ + default?: boolean + /** + * The customer's first name. + */ + first_name?: string + /** + * The customer's last name. + */ + last_name?: string + /** + * The customer's first and last names. + */ + name?: string + /** + * The customer's phone number at this address. + */ + phone?: string + /** + * The customer's region name. Typically a province, a state, or a prefecture + */ + province?: string + /** + * The code for the region of the address, such as the province, state, or district. For example QC for Quebec, Canada. + */ + province_code?: string + /** + * The customer's postal code, also known as zip, postcode, Eircode, etc + */ + zip?: string + /** + * Hashed value of first name in SHA256 (lower case). + */ + hashed_first_name?: string + /** + * Hashed value of last name in SHA256 (lower case). + */ + hashed_last_name?: string + /** + * Hashed value of phone in SHA256 (lower case). + */ + hashed_phone?: string + /** + * Hashed value of address1 in SHA256 (lower case). + */ + hashed_address1?: string + /** + * Hashed value of address2 in SHA256 (lower case). + */ + hashed_address2?: string + /** + * Hashed value of city in SHA256 (lower case). + */ + hashed_city?: string + /** + * Hashed value of zip in SHA256 (lower case). + */ + hashed_zip?: string + /** + * Hashed value of country code in SHA256 (lower case). + */ + hashed_country_code?: string + } + /** + * The ID of the order placed on the originating platform. + */ + source_identifier?: string + /** + * The source of the checkout. + */ + source_name?: string + /** + * A valid URL to the original order on the originating surface. + */ + source_url?: string + /** + * The price of the order in the shop currency after discounts but before shipping, duties, taxes, and tips. + */ + subtotal_price?: string + /** + * Tags attached to the order, formatted as a string of comma-separated values. Tags are additional short descriptors, commonly used for filtering and searching. Each individual tag is limited to 40 characters in length. + */ + tags?: string + /** + * Whether taxes are included in the order subtotal. + */ + taxes_included?: boolean + /** + * The total discounts applied to the price of the order in the shop currency. + */ + total_discounts?: string + /** + * The sum of all line item prices in the shop currency. + */ + total_line_items_price?: string + /** + * The total outstanding amount of the order in the shop currency. + */ + total_outstanding?: string + /** + * The sum of all line item prices, discounts, shipping, taxes, and tips in the shop currency. Must be positive. + */ + total_price?: string + /** + * The sum of all line item prices, discounts, shipping, taxes, and tips in the shop currency in USD + */ + total_price_usd?: string + /** + * The sum of all the taxes applied to the order in the shop currency. Must be positive. + */ + total_tax?: string + /** + * The ID of the user logged into Shopify POS who processed the order, if applicable. + */ + user_id?: string + /** + * The date and time (ISO 8601 format) when the order was last modified. + */ + updated_at?: string + /** + * Extra properties. + */ + additional_fields?: { + /** + * Extra property name. + */ + name?: string + /** + * Extra property value. + */ + value?: string + }[] +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveOrder/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveOrder/index.ts new file mode 100644 index 0000000000..0251cf88c3 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveOrder/index.ts @@ -0,0 +1,543 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { addressDefaultFields, addressProperties } from '../fields/addressFields' +import type { Settings } from '../generated-types' +import { baseURL, ordersEndpoint } from '../routes' +import type { Payload } from './generated-types' + +const action: ActionDefinition = { + title: 'Save Order', + description: + 'Send an order to Angler. Use this Mapping for transactions which may not originate from the browser. E.g. recurring subscriptions.', + fields: { + billing_address: { + type: 'object', + label: 'Billing Address', + description: 'The mailing address associated with the payment method.', + properties: addressProperties, + default: addressDefaultFields('$.properties.billing_address') + }, + browser_ip: { + type: 'string', + label: 'Browser IP', + description: + 'The IP address of the browser used by the customer when they placed the order. Both IPv4 and IPv6 are supported.', + default: { + '@path': '$.context.ip' + } + }, + buyer_accepts_marketing: { + type: 'boolean', + label: 'Buyer Accepts Marketing', + description: 'Whether the customer consented to receive email updates from the shop.', + default: { + '@if': { + exists: { '@path': '$.properties.buyer_accepts_marketing' }, + then: { '@path': '$.properties.buyer_accepts_marketing' }, + else: { '@path': '$.traits.accepts_marketing' } + } + } + }, + checkout_id: { + type: 'string', + label: 'Checkout ID', + description: 'The ID of the checkout.', + default: { + '@path': '$.properties.checkout_id' + } + }, + client_details: { + type: 'object', + label: 'Client Details', + description: 'Information about the browser that the customer used when they placed their order.', + properties: { + browser_ip: { + type: 'string', + label: 'Browser IP', + description: 'The browser IP address.' + }, + user_agent: { + type: 'string', + label: 'User Agent', + description: 'Details of the browsing client, including software and operating versions.' + } + }, + default: { + accept_language: { '@path': '$.context.locale' }, + browser_height: { '@path': '$.context.screen.height' }, + browser_ip: { '@path': '$.context.ip' }, + browser_width: { '@path': '$.context.screen.width' }, + session_hash: { '@path': '$.properties.session_hash' }, + user_agent: { '@path': '$.context.userAgent' } + } + }, + confirmed: { + type: 'boolean', + label: 'Confirmed', + description: 'Confirmed', + default: { + '@path': '$.properties.confirmed' + } + }, + contact_email: { + type: 'string', + label: 'Contact Email', + description: 'Contact Email', + default: { + '@if': { + exists: { '@path': '$.properties.contact_email' }, + then: { '@path': '$.properties.contact_email' }, + else: { '@path': '$.traits.email' } + } + } + }, + created_at: { + type: 'string', + label: 'Created At', + description: 'The autogenerated date and time (ISO 8601 format) when the order was created.', + default: { + '@path': '$.properties.created_at' + } + }, + currency: { + type: 'string', + label: 'Currency', + description: + 'The three-letter code (ISO 4217 format) for the currency that the customer used when they paid for their last order.', + default: { + '@path': '$.properties.currency' + } + }, + current_subtotal_price: { + type: 'string', + label: 'Current Subtotal Price', + description: + 'The current subtotal price of the order in the shop currency. The value of this field reflects order edits, returns, and refunds.', + default: { + '@path': '$.properties.current_subtotal_price' + } + }, + current_total_discounts: { + type: 'string', + label: 'Current Total Discounts', + description: + 'The current total discounts on the order in the shop currency. The value of this field reflects order edits, returns, and refunds.', + default: { + '@path': '$.properties.current_total_discounts' + } + }, + current_total_price: { + type: 'string', + label: 'Current Total Price', + description: + 'The current total price of the order in the shop currency. The value of this field reflects order edits, returns, and refunds.', + default: { + '@path': '$.properties.current_total_price' + } + }, + current_total_tax: { + type: 'string', + label: 'Current Total Tax', + description: + 'The current total taxes charged on the order in the shop currency. The value of this field reflects order edits, returns, or refunds.', + default: { + '@path': '$.properties.current_total_tax' + } + }, + customer_id: { + type: 'string', + label: 'Customer ID', + description: 'A unique identifier for the customer.', + default: { + '@if': { + exists: { '@path': '$.userId' }, + then: { '@path': '$.userId' }, + else: { '@path': '$.traits.id' } + } + } + }, + discount_applications: { + type: 'object', + multiple: true, + label: 'Discount Applications', + description: + 'An ordered list of stacked discount applications. The discount_applications property includes 3 types: discount_code, manual, and script. All 3 types share a common structure and have some type specific attributes.', + properties: { + target_type: { + type: 'string', + label: 'Target Type', + description: 'The type of line on the order that the discount is applicable on.' + }, + type: { + type: 'string', + label: 'Type', + description: 'The discount application type.' + }, + value: { + type: 'string', + label: 'Value', + description: + 'The value of the discount application as a decimal. This represents the intention of the discount application.' + }, + value_type: { + type: 'string', + label: 'Value Type', + description: 'The type of the value.' + }, + allocation_method: { + type: 'string', + label: 'Allocation Method', + description: 'The method by which the discount application value has been allocated to entitled lines.' + }, + target_selection: { + type: 'string', + label: 'Target Selection', + description: + 'The lines on the order, of the type defined by target_type, that the discount is allocated over.' + }, + code: { + type: 'string', + label: 'Code', + description: + 'The discount code that was used to apply the discount. Available only for discount code applications.' + } + }, + default: { + '@arrayPath': [ + '$.properties.discount_applications', + { + target_type: { '@path': '$.target_type' }, + type: { '@path': '$.type' }, + value: { '@path': '$.value' }, + value_type: { '@path': '$.value_type' }, + allocation_method: { '@path': '$.allocation_method' }, + target_selection: { '@path': '$.target_selection' }, + code: { '@path': '$.code' } + } + ] + } + }, + discount_codes: { + type: 'object', + multiple: true, + label: 'Discount Codes', + description: 'A list of discounts applied to the order.', + properties: { + code: { + type: 'string', + label: 'Code', + description: + 'When the associated discount application is of type code, this property returns the discount code that was entered at checkout. Otherwise this property returns the title of the discount that was applied.' + }, + amount: { + type: 'string', + label: 'Amount', + description: + "The amount that's deducted from the order total. When you create an order, this value is the percentage or monetary amount to deduct. After the order is created, this property returns the calculated amount." + }, + type: { + type: 'string', + label: 'Type', + description: 'The type of discount.' + } + }, + default: { + '@arrayPath': [ + '$.properties.discount_codes', + { + code: { '@path': '$.code' }, + amount: { '@path': '$.amount' }, + type: { '@path': '$.type' } + } + ] + } + }, + email: { + type: 'string', + label: 'Email', + description: "The customer's email address.", + default: { + '@if': { + exists: { '@path': '$.properties.email' }, + then: { '@path': '$.properties.email' }, + else: { '@path': '$.traits.email' } + } + } + }, + estimated_taxes: { + type: 'boolean', + label: 'Estimated Taxes', + description: + 'Whether taxes on the order are estimated. Many factors can change between the time a customer places an order and the time the order is shipped, which could affect the calculation of taxes.', + default: { + '@path': '$.properties.estimated_taxes' + } + }, + financial_status: { + type: 'string', + label: 'Financial Status', + description: 'The status of payments associated with the order.', + default: { + '@path': '$.properties.financial_status' + } + }, + fulfillment_status: { + type: 'string', + label: 'Fulfillment Status', + description: "The order's status in terms of fulfilled line items.", + default: { + '@path': '$.properties.fulfillment_status' + } + }, + gateway: { + type: 'string', + label: 'Gateway', + description: 'The payment gateway used.', + default: { + '@path': '$.properties.gateway' + } + }, + id: { + required: true, + type: 'string', + label: 'ID', + description: 'The ID of the order, used for API purposes.', + default: { + '@path': '$.properties.id' + } + }, + landing_site: { + type: 'string', + label: 'Landing Site', + description: 'The URL for the page where the buyer landed when they entered the shop.', + default: { + '@path': '$.properties.landing_site' + } + }, + landing_site_ref: { + type: 'string', + label: 'Landing Site Ref', + description: 'Landing Site Ref', + default: { + '@path': '$.properties.landing_site_ref' + } + }, + name: { + type: 'string', + label: 'Name', + description: 'The order name.', + default: { + '@path': '$.properties.name' + } + }, + order_number: { + type: 'integer', + label: 'Order Number', + description: + 'The order position in the shop count of orders starting at 1001. Order numbers are sequential and start at 1001.', + default: { + '@path': '$.properties.order_number' + } + }, + phone: { + type: 'string', + label: 'Phone', + description: "The customer's phone number for receiving SMS notifications.", + default: { + '@path': '$.properties.phone' + } + }, + processed_at: { + type: 'string', + label: 'Processed At', + description: 'The date and time (ISO 8601 format) when an order was processed.', + default: { + '@path': '$.properties.processed_at' + } + }, + processing_method: { + type: 'string', + label: 'Processing Method', + description: 'How the payment was processed.', + default: { + '@path': '$.properties.processing_method' + } + }, + reference: { + type: 'string', + label: 'Reference', + description: 'Reference', + default: { + '@path': '$.properties.reference' + } + }, + referring_site: { + type: 'string', + label: 'Referring Site', + description: 'The website where the customer clicked a link to the shop.', + default: { + '@path': '$.properties.referring_site' + } + }, + shipping_address: { + type: 'object', + label: 'Shipping Address', + description: 'The mailing address associated with the payment method.', + properties: addressProperties, + default: addressDefaultFields('$.properties.shipping_address') + }, + source_identifier: { + type: 'string', + label: 'Source Identifier', + description: 'The ID of the order placed on the originating platform.', + default: { + '@path': '$.properties.source_identifier' + } + }, + source_name: { + type: 'string', + label: 'Source Name', + description: 'The source of the checkout.', + default: { + '@path': '$.properties.source_name' + } + }, + source_url: { + type: 'string', + label: 'Source URL', + description: 'A valid URL to the original order on the originating surface.', + default: { + '@path': '$.properties.source_url' + } + }, + subtotal_price: { + type: 'string', + label: 'Subtotal Price', + description: + 'The price of the order in the shop currency after discounts but before shipping, duties, taxes, and tips.', + default: { + '@path': '$.properties.subtotal_price' + } + }, + tags: { + type: 'string', + label: 'Tags', + description: + 'Tags attached to the order, formatted as a string of comma-separated values. Tags are additional short descriptors, commonly used for filtering and searching. Each individual tag is limited to 40 characters in length.', + default: { + '@path': '$.properties.tags' + } + }, + taxes_included: { + type: 'boolean', + label: 'Taxes Included', + description: 'Whether taxes are included in the order subtotal.', + default: { + '@path': '$.properties.taxes_included' + } + }, + total_discounts: { + type: 'string', + label: 'Total Discounts', + description: 'The total discounts applied to the price of the order in the shop currency.', + default: { + '@path': '$.properties.total_discounts' + } + }, + total_line_items_price: { + type: 'string', + label: 'Total Line Items Price', + description: 'The sum of all line item prices in the shop currency.', + default: { + '@path': '$.properties.total_line_items_price' + } + }, + total_outstanding: { + type: 'string', + label: 'Total Outstanding', + description: 'The total outstanding amount of the order in the shop currency.', + default: { + '@path': '$.properties.total_outstanding' + } + }, + total_price: { + type: 'string', + label: 'Total Price', + description: + 'The sum of all line item prices, discounts, shipping, taxes, and tips in the shop currency. Must be positive.', + default: { + '@path': '$.properties.total_price' + } + }, + total_price_usd: { + type: 'string', + label: 'Total Price USD', + description: 'The sum of all line item prices, discounts, shipping, taxes, and tips in the shop currency in USD', + default: { + '@path': '$.properties.total_price_usd' + } + }, + total_tax: { + type: 'string', + label: 'Total Tax', + description: 'The sum of all the taxes applied to the order in the shop currency. Must be positive.', + default: { + '@path': '$.properties.total_tax' + } + }, + user_id: { + type: 'string', + label: 'User ID', + description: 'The ID of the user logged into Shopify POS who processed the order, if applicable.', + default: { + '@path': '$.properties.user_id' + } + }, + updated_at: { + type: 'string', + label: 'Updated At', + description: 'The date and time (ISO 8601 format) when the order was last modified.', + default: { + '@path': '$.properties.updated_at' + } + }, + additional_fields: { + type: 'object', + multiple: true, + label: 'Additional Fields', + description: 'Extra properties.', + properties: { + name: { + type: 'string', + label: 'Name', + description: 'Extra property name.' + }, + value: { + type: 'string', + label: 'String', + description: 'Extra property value.' + } + }, + default: { + '@arrayPath': [ + '$.properties.additional_fields', + { + name: { '@path': '$.name' }, + value: { '@path': '$.value' } + } + ] + } + } + }, + perform: (request, data) => { + const payload = { + src: 'SEGMENT', + data: [data.payload] + } + return request(baseURL + ordersEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..e21dd87e3e --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveProductEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "CFQcvY4UNbVp*xK", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 29115173012766.72, + "currencyCode": "CFQcvY4UNbVp*xK", + }, + }, + "id": "CFQcvY4UNbVp*xK", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 29115173012766.72, + }, + }, + "merchandise": Object { + "id": "CFQcvY4UNbVp*xK", + "image": Object { + "src": "CFQcvY4UNbVp*xK", + }, + "price": Object { + "amount": 29115173012766.72, + }, + "product": Object { + "title": "CFQcvY4UNbVp*xK", + "type": "CFQcvY4UNbVp*xK", + "untranslatedTitle": "CFQcvY4UNbVp*xK", + "url": "CFQcvY4UNbVp*xK", + "vendor": "CFQcvY4UNbVp*xK", + }, + "sku": "CFQcvY4UNbVp*xK", + "title": "CFQcvY4UNbVp*xK", + "untranslatedTitle": "CFQcvY4UNbVp*xK", + }, + "quantity": 29115173012766.72, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "CFQcvY4UNbVp*xK", + }, + ], + "customer": Object { + "dob": "CFQcvY4UNbVp*xK", + "email": "bunlajis@jah.vn", + "firstName": "CFQcvY4UNbVp*xK", + "id": "CFQcvY4UNbVp*xK", + "lastName": "CFQcvY4UNbVp*xK", + "phone": "CFQcvY4UNbVp*xK", + }, + "productVariant": Object { + "id": "CFQcvY4UNbVp*xK", + "image": Object { + "src": "CFQcvY4UNbVp*xK", + }, + "price": Object { + "amount": 29115173012766.72, + }, + "product": Object { + "id": "CFQcvY4UNbVp*xK", + "title": "CFQcvY4UNbVp*xK", + "type": "CFQcvY4UNbVp*xK", + "untranslatedTitle": "CFQcvY4UNbVp*xK", + "url": "CFQcvY4UNbVp*xK", + "vendor": "CFQcvY4UNbVp*xK", + }, + "sku": "CFQcvY4UNbVp*xK", + "title": "CFQcvY4UNbVp*xK", + "untranslatedTitle": "CFQcvY4UNbVp*xK", + }, + }, + "event_id": "CFQcvY4UNbVp*xK", + "event_name": "product_viewed", + "fbc": "CFQcvY4UNbVp*xK", + "fpb": "CFQcvY4UNbVp*xK", + "ga": "CFQcvY4UNbVp*xK", + "identifiers": Array [], + "ip_address": "CFQcvY4UNbVp*xK", + "referrer": "CFQcvY4UNbVp*xK", + "timestamp": "CFQcvY4UNbVp*xK", + "url": "CFQcvY4UNbVp*xK", + "user_agent": "CFQcvY4UNbVp*xK", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveProductEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "CFQcvY4UNbVp*xK", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "productVariant": Object { + "image": Object {}, + "price": Object {}, + "product": Object {}, + }, + }, + "event_id": "CFQcvY4UNbVp*xK", + "event_name": "product_viewed", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..f580e24a68 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveProductEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveProductEvent', { + event: { + ...event, + event: 'product_viewed' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..889a7f9744 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/__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 = 'saveProductEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveProductEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/generated-types.ts new file mode 100644 index 0000000000..80d8996651 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/generated-types.ts @@ -0,0 +1,209 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * Product Variant details + */ + productVariant?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + } + /** + * The name of the Product event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/index.ts new file mode 100644 index 0000000000..9239d7d68e --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/index.ts @@ -0,0 +1,43 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import { productVariantFields } from '../fields/productVariantFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Product Event', + description: 'Save a product event.', + fields: { + ...commonFields, + ...customerFields, + ...cartFields, + ...productVariantFields, + eventName: { + label: 'Product Event Name', + type: 'string', + description: 'The name of the Product event to track.', + required: true, + readOnly: true, + choices: [{ label: 'product_viewed', value: 'product_viewed' }], + default: 'product_viewed' + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/transform-payload.ts new file mode 100644 index 0000000000..dd22942eb6 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveProductEvent/transform-payload.ts @@ -0,0 +1,21 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { transformProductVariant } from '../transformFields/transformProductVariant' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCart(payload), + ...transformCustomer(payload), + ...transformProductVariant(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..48b2f94ba9 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,126 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveSearchEvent destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "WmPxjqg1oQsz%", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object { + "amount": 3667235721707.52, + "currencyCode": "WmPxjqg1oQsz%", + }, + }, + "id": "WmPxjqg1oQsz%", + "lines": Array [ + Object { + "cost": Object { + "totalAmount": Object { + "amount": 3667235721707.52, + }, + }, + "merchandise": Object { + "id": "WmPxjqg1oQsz%", + "image": Object { + "src": "WmPxjqg1oQsz%", + }, + "price": Object { + "amount": 3667235721707.52, + }, + "product": Object { + "title": "WmPxjqg1oQsz%", + "type": "WmPxjqg1oQsz%", + "untranslatedTitle": "WmPxjqg1oQsz%", + "url": "WmPxjqg1oQsz%", + "vendor": "WmPxjqg1oQsz%", + }, + "sku": "WmPxjqg1oQsz%", + "title": "WmPxjqg1oQsz%", + "untranslatedTitle": "WmPxjqg1oQsz%", + }, + "quantity": 3667235721707.52, + }, + ], + }, + "customData": Array [ + Object { + "name": "testType", + "value": "WmPxjqg1oQsz%", + }, + ], + "customer": Object { + "dob": "WmPxjqg1oQsz%", + "email": "guktapi@cut.ms", + "firstName": "WmPxjqg1oQsz%", + "id": "WmPxjqg1oQsz%", + "lastName": "WmPxjqg1oQsz%", + "phone": "WmPxjqg1oQsz%", + }, + "searchResult": Object { + "productVariants": Array [ + Object { + "id": "WmPxjqg1oQsz%", + "image": Object { + "src": "WmPxjqg1oQsz%", + }, + "price": Object { + "amount": 3667235721707.52, + }, + "product": Object { + "id": "WmPxjqg1oQsz%", + "title": "WmPxjqg1oQsz%", + "type": "WmPxjqg1oQsz%", + "untranslatedTitle": "WmPxjqg1oQsz%", + "url": "WmPxjqg1oQsz%", + "vendor": "WmPxjqg1oQsz%", + }, + "sku": "WmPxjqg1oQsz%", + "title": "WmPxjqg1oQsz%", + "untranslatedTitle": "WmPxjqg1oQsz%", + }, + ], + "query": "WmPxjqg1oQsz%", + }, + }, + "event_id": "WmPxjqg1oQsz%", + "event_name": "search_submitted", + "fbc": "WmPxjqg1oQsz%", + "fpb": "WmPxjqg1oQsz%", + "ga": "WmPxjqg1oQsz%", + "identifiers": Array [], + "ip_address": "WmPxjqg1oQsz%", + "referrer": "WmPxjqg1oQsz%", + "timestamp": "WmPxjqg1oQsz%", + "url": "WmPxjqg1oQsz%", + "user_agent": "WmPxjqg1oQsz%", + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveSearchEvent destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "client_id": "WmPxjqg1oQsz%", + "data": Object { + "cart": Object { + "cost": Object { + "totalAmount": Object {}, + }, + }, + "customData": Array [], + "customer": Object {}, + "searchResult": Object {}, + }, + "event_id": "WmPxjqg1oQsz%", + "event_name": "search_submitted", + "identifiers": Array [], + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/index.test.ts new file mode 100644 index 0000000000..cadfe4067c --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/index.test.ts @@ -0,0 +1,33 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, eventsEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveSearchEvent', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = eventsEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveSearchEvent', { + event: { + ...event, + event: 'search_submitted' + }, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..fe001fccb1 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/__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 = 'saveSearchEvent' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveSearchEvent/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/generated-types.ts new file mode 100644 index 0000000000..c3078ca112 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/generated-types.ts @@ -0,0 +1,213 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * A unique event identifier. + */ + eventId: string + /** + * The IP address of the user. + */ + ipAddress?: string + /** + * The user agent of the device sending the event. + */ + userAgent?: string + /** + * The timestamp when the event was triggered. + */ + timestamp?: string + /** + * Identifiers for the user + */ + identifiers: { + /** + * Segment User ID. + */ + userId?: string + /** + * Segment anonymous ID. + */ + anonymousId?: string + /** + * Client ID. + */ + clientId: string + /** + * Facebook Pixel ID. This is a cookie which is unique to each user. + */ + fbp?: string + /** + * Facebook Click ID. This is a cookie which is unique to each user. + */ + fbc?: string + /** + * Google Analytics ID. This is a cookie which is unique to each user. + */ + ga?: string + [k: string]: unknown + } + /** + * Page details to send with the event + */ + page?: { + /** + * The URL where the event occurred. + */ + url?: string + /** + * The referring URL if applicable. + */ + referrer?: string + } + /** + * Custom attributes for the event. Data should be specified as key:value pairs + */ + customAttributes?: { + [k: string]: unknown + } + /** + * Customer details + */ + customer?: { + /** + * The customer's email address. + */ + email?: string + /** + * The customer's first name. + */ + firstName?: string + /** + * The customer's last name. + */ + lastName?: string + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The customer's date of birth. + */ + dob?: string + } + /** + * Cart details + */ + cart?: { + /** + * A globally unique identifier for the cart. + */ + id?: string + /** + * Decimal money amount. + */ + totalAmount?: number + /** + * The currency code of the money. + */ + currencyCode?: string + } + /** + * Cart Line Item details + */ + cartLines?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + /** + * Quantity of the item + */ + quantity?: number + }[] + /** + * Search results details + */ + searchResults?: { + /** + * A globally unique identifier for the item. + */ + id?: string + /** + * Identifier for the variant of the product + */ + variantId?: string + /** + * The location of the image as a URL. + */ + imageSrc?: string + /** + * The price of the product variant. + */ + priceAmount?: number + /** + * The SKU (stock keeping unit) associated with the variant. + */ + sku?: string + /** + * The product variant's title. + */ + title?: string + /** + * The product variant's untranslated title. + */ + untranslatedTitle?: string + /** + * The product's vendor name. + */ + vendor?: string + /** + * The product type specified by the merchant. + */ + type?: string + /** + * The relative URL of the product. + */ + url?: string + }[] + /** + * The search query that was executed. + */ + query?: string + /** + * The name of the Search event to track. + */ + eventName: string +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/index.ts new file mode 100644 index 0000000000..cbf7bc9c60 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/index.ts @@ -0,0 +1,43 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { cartFields } from '../fields/cartFields' +import { commonFields } from '../fields/commonFields' +import { customerFields } from '../fields/customerFields' +import { searchFields } from '../fields/searchFields' +import type { Settings } from '../generated-types' +import { baseURL, eventsEndpoint } from '../routes' +import type { Payload } from './generated-types' +import { transformPayload } from './transform-payload' + +const action: ActionDefinition = { + title: 'Save Search Event', + description: 'Save a search event.', + fields: { + ...commonFields, + ...customerFields, + ...cartFields, + ...searchFields, + eventName: { + label: 'Search Event Name', + type: 'string', + description: 'The name of the Search event to track.', + required: true, + readOnly: true, + choices: [{ label: 'search_submitted', value: 'search_submitted' }], + default: 'search_submitted' + } + }, + perform: (request, data) => { + const transformedPayload = transformPayload(data.payload) + + const payload = { + src: 'SEGMENT', + data: [transformedPayload] + } + return request(baseURL + eventsEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/transform-payload.ts b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/transform-payload.ts new file mode 100644 index 0000000000..19719022f7 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveSearchEvent/transform-payload.ts @@ -0,0 +1,21 @@ +import { transformCart } from '../transformFields/transformCart' +import { transformCommonFields } from '../transformFields/transformCommonFields' +import { transformCustomer } from '../transformFields/transformCustomer' +import { transformSearch } from '../transformFields/transformSearch' +import { Payload } from './generated-types' + +export function transformPayload(payload: Payload) { + const commonFields = transformCommonFields(payload) + + const result = { + ...commonFields, + data: { + ...commonFields.data, + ...transformCart(payload), + ...transformCustomer(payload), + ...transformSearch(payload) + } + } + + return result +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/__snapshots__/snapshot.test.ts.snap new file mode 100644 index 0000000000..cde1d393c0 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/__snapshots__/snapshot.test.ts.snap @@ -0,0 +1,121 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Testing snapshot for AnglerAi's saveUser destination action: all fields 1`] = ` +Object { + "data": Array [ + Object { + "addresses": Array [ + Object { + "address1": "^o*Om", + "address2": "^o*Om", + "city": "^o*Om", + "company": "^o*Om", + "country": "^o*Om", + "country_code": "^o*Om", + "country_name": "^o*Om", + "customer_id": "^o*Om", + "default": true, + "first_name": "^o*Om", + "hashed_address1": "^o*Om", + "hashed_address2": "^o*Om", + "hashed_city": "^o*Om", + "hashed_country_code": "^o*Om", + "hashed_first_name": "^o*Om", + "hashed_last_name": "^o*Om", + "hashed_phone": "^o*Om", + "hashed_zip": "^o*Om", + "id": "^o*Om", + "last_name": "^o*Om", + "name": "^o*Om", + "phone": "^o*Om", + "province": "^o*Om", + "province_code": "^o*Om", + "zip": "^o*Om", + }, + ], + "default_address": Object { + "address1": "^o*Om", + "address2": "^o*Om", + "city": "^o*Om", + "company": "^o*Om", + "country": "^o*Om", + "country_code": "^o*Om", + "country_name": "^o*Om", + "customer_id": "^o*Om", + "default": true, + "first_name": "^o*Om", + "hashed_address1": "^o*Om", + "hashed_address2": "^o*Om", + "hashed_city": "^o*Om", + "hashed_country_code": "^o*Om", + "hashed_first_name": "^o*Om", + "hashed_last_name": "^o*Om", + "hashed_phone": "^o*Om", + "hashed_zip": "^o*Om", + "id": "^o*Om", + "last_name": "^o*Om", + "name": "^o*Om", + "phone": "^o*Om", + "province": "^o*Om", + "province_code": "^o*Om", + "zip": "^o*Om", + }, + "email_marketing_consent": Object { + "consent_updated_at": "^o*Om", + "opt_in_level": "^o*Om", + "state": "^o*Om", + }, + "metafield": Object { + "key": "^o*Om", + "namespace": "^o*Om", + "type": "^o*Om", + "value": "^o*Om", + }, + "sms_marketing_consent": Object { + "consent_collected_from": "^o*Om", + "consent_updated_at": "^o*Om", + "opt_in_level": "^o*Om", + "state": "^o*Om", + }, + "user": Object { + "accepts_marketing": true, + "accepts_marketing_updated_at": "^o*Om", + "created_at": "^o*Om", + "currency": "AZN", + "email": "daz@mo.tw", + "first_name": "^o*Om", + "hashed_email": "^o*Om", + "hashed_first_name": "^o*Om", + "hashed_last_name": "^o*Om", + "hashed_phone": "^o*Om", + "id": "^o*Om", + "last_name": "^o*Om", + "last_order_id": "^o*Om", + "last_order_name": "^o*Om", + "marketing_opt_in_level": "^o*Om", + "note": "^o*Om", + "orders_count": -79975814602424.31, + "phone": "^o*Om", + "state": "ENABLED", + "tax_exempt": true, + "total_spent": "^o*Om", + "updated_at": "^o*Om", + "verified_email": true, + }, + }, + ], + "src": "SEGMENT", +} +`; + +exports[`Testing snapshot for AnglerAi's saveUser destination action: required fields 1`] = ` +Object { + "data": Array [ + Object { + "email_marketing_consent": Object {}, + "sms_marketing_consent": Object {}, + }, + ], + "src": "SEGMENT", +} +`; diff --git a/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/index.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/index.test.ts new file mode 100644 index 0000000000..eb79d5b0f4 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/index.test.ts @@ -0,0 +1,30 @@ +import nock from 'nock' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' +import Destination from '../../index' +import { baseURL, customersEndpoint } from '../../routes' + +const testDestination = createTestIntegration(Destination) + +describe('AnglerAi.saveUser', () => { + const event = createTestEvent() + + const workspaceId = 'test_workspace' + const accessToken = 'test_token' + + it('should work with default mappings', async () => { + const endpointURL = customersEndpoint(workspaceId) + nock(baseURL).post(endpointURL).reply(201) + + const response = await testDestination.testAction('saveUser', { + event, + useDefaultMappings: true, + settings: { + workspaceId, + accessToken + } + }) + expect(response.length).toBe(1) + expect(new URL(response[0].url).pathname).toBe(endpointURL) + expect(response[0].status).toBe(201) + }) +}) diff --git a/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/snapshot.test.ts b/packages/destination-actions/src/destinations/angler-ai/saveUser/__tests__/snapshot.test.ts new file mode 100644 index 0000000000..79b34eac71 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveUser/__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 = 'saveUser' +const destinationSlug = 'AnglerAi' +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/angler-ai/saveUser/generated-types.ts b/packages/destination-actions/src/destinations/angler-ai/saveUser/generated-types.ts new file mode 100644 index 0000000000..73d31d2339 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveUser/generated-types.ts @@ -0,0 +1,371 @@ +// Generated file. DO NOT MODIFY IT BY HAND. + +export interface Payload { + /** + * The user object. + */ + user?: { + /** + * Whether the customer has consented to receive marketing material by email. + */ + accepts_marketing?: boolean + /** + * The date and time (ISO 8601 format) when the customer consented or objected to receiving marketing material by email. + */ + accepts_marketing_updated_at?: string + /** + * The three-letter code (ISO 4217 format) for the currency that the customer used when they paid for their last order. + */ + currency?: string + /** + * The date and time (ISO 8601 format) when the customer was created. + */ + created_at?: string + /** + * The unique email address of the customer. + */ + email?: string + /** + * Hashed customer's email in SHA256 (lower case). + */ + hashed_email?: string + /** + * Hashed customer's first name in SHA256 (lower case). + */ + hashed_first_name?: string + /** + * Hashed customer's last name in SHA256 (lower case). + */ + hashed_last_name?: string + /** + * Hashed customer's phone in SHA256 (lower case). + */ + hashed_phone?: string + /** + * The customer's first name. + */ + first_name?: string + /** + * A unique identifier for the customer. + */ + id?: string + /** + * The customer's last name. + */ + last_name?: string + /** + * The ID of the customer's last order. + */ + last_order_id?: string + /** + * The name of the customer's last order. + */ + last_order_name?: string + /** + * The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by email. + */ + marketing_opt_in_level?: string + /** + * A note about the customer. + */ + note?: string + /** + * The number of orders associated with this customer. + */ + orders_count?: number + /** + * The unique phone number (E.164 format) for this customer. + */ + phone?: string + /** + * The state of the customer's account with a shop. + */ + state?: string + /** + * Whether the customer is exempt from paying taxes on their order. + */ + tax_exempt?: boolean + /** + * The total amount of money that the customer has spent across their order history. + */ + total_spent?: string + /** + * The date and time (ISO 8601 format) when the customer information was last updated. + */ + updated_at?: string + /** + * Whether the customer has verified their email address. + */ + verified_email?: boolean + [k: string]: unknown + } + /** + * A list of the ten most recently updated addresses for the customer. + */ + addresses?: { + /** + * A unique identifier for the address. + */ + id?: string + /** + * The customer's mailing address. + */ + address1?: string + /** + * An additional field for the customer's mailing address. + */ + address2?: string + /** + * The customer's city, town, or village. + */ + city?: string + /** + * The customer's company. + */ + company?: string + /** + * The customer's country. + */ + country?: string + /** + * The two-letter country code corresponding to the customer's country + */ + country_code?: string + /** + * The customer's normalized country name. + */ + country_name?: string + /** + * A unique identifier for the customer. + */ + customer_id?: string + /** + * Whether this address is the default address for the customer. + */ + default?: boolean + /** + * The customer's first name. + */ + first_name?: string + /** + * The customer's last name. + */ + last_name?: string + /** + * The customer's first and last names. + */ + name?: string + /** + * The customer's phone number at this address. + */ + phone?: string + /** + * The customer's region name. Typically a province, a state, or a prefecture + */ + province?: string + /** + * The code for the region of the address, such as the province, state, or district. For example QC for Quebec, Canada. + */ + province_code?: string + /** + * The customer's postal code, also known as zip, postcode, Eircode, etc + */ + zip?: string + /** + * Hashed value of first name in SHA256 (lower case). + */ + hashed_first_name?: string + /** + * Hashed value of last name in SHA256 (lower case). + */ + hashed_last_name?: string + /** + * Hashed value of phone in SHA256 (lower case). + */ + hashed_phone?: string + /** + * Hashed value of address1 in SHA256 (lower case). + */ + hashed_address1?: string + /** + * Hashed value of address2 in SHA256 (lower case). + */ + hashed_address2?: string + /** + * Hashed value of city in SHA256 (lower case). + */ + hashed_city?: string + /** + * Hashed value of zip in SHA256 (lower case). + */ + hashed_zip?: string + /** + * Hashed value of country code in SHA256 (lower case). + */ + hashed_country_code?: string + }[] + /** + * The mailing address associated with the payment method. + */ + default_address?: { + /** + * A unique identifier for the address. + */ + id?: string + /** + * The customer's mailing address. + */ + address1?: string + /** + * An additional field for the customer's mailing address. + */ + address2?: string + /** + * The customer's city, town, or village. + */ + city?: string + /** + * The customer's company. + */ + company?: string + /** + * The customer's country. + */ + country?: string + /** + * The two-letter country code corresponding to the customer's country + */ + country_code?: string + /** + * The customer's normalized country name. + */ + country_name?: string + /** + * A unique identifier for the customer. + */ + customer_id?: string + /** + * Whether this address is the default address for the customer. + */ + default?: boolean + /** + * The customer's first name. + */ + first_name?: string + /** + * The customer's last name. + */ + last_name?: string + /** + * The customer's first and last names. + */ + name?: string + /** + * The customer's phone number at this address. + */ + phone?: string + /** + * The customer's region name. Typically a province, a state, or a prefecture + */ + province?: string + /** + * The code for the region of the address, such as the province, state, or district. For example QC for Quebec, Canada. + */ + province_code?: string + /** + * The customer's postal code, also known as zip, postcode, Eircode, etc + */ + zip?: string + /** + * Hashed value of first name in SHA256 (lower case). + */ + hashed_first_name?: string + /** + * Hashed value of last name in SHA256 (lower case). + */ + hashed_last_name?: string + /** + * Hashed value of phone in SHA256 (lower case). + */ + hashed_phone?: string + /** + * Hashed value of address1 in SHA256 (lower case). + */ + hashed_address1?: string + /** + * Hashed value of address2 in SHA256 (lower case). + */ + hashed_address2?: string + /** + * Hashed value of city in SHA256 (lower case). + */ + hashed_city?: string + /** + * Hashed value of zip in SHA256 (lower case). + */ + hashed_zip?: string + /** + * Hashed value of country code in SHA256 (lower case). + */ + hashed_country_code?: string + } + /** + * The marketing consent information when the customer consented to receiving marketing material by email. + */ + email_marketing_consent?: { + /** + * The current email marketing state for the customer. + */ + state?: string + /** + * The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by email. + */ + opt_in_level?: string + /** + * The date and time when the customer consented to receive marketing material by email. If no date is provided, then the date and time when the consent information was sent is used. + */ + consent_updated_at?: string + } + /** + * Attaches additional metadata to a shop's resources. + */ + metafield?: { + /** + * An identifier for the metafield. + */ + key?: string + /** + * A container for a set of metadata. Namespaces help distinguish between metadata that you created and metadata created by another individual with a similar namespace. + */ + namespace?: string + /** + * Information to be stored as metadata. + */ + value?: string + /** + * The type. + */ + type?: string + } + /** + * The marketing consent information when the customer consented to receiving marketing material by SMS. + */ + sms_marketing_consent?: { + /** + * The state of the SMS marketing consent. + */ + state?: string + /** + * The marketing subscription opt-in level, as described in the M3AAWG Sender Best Common Practices, that the customer gave when they consented to receive marketing material by SMS. + */ + opt_in_level?: string + /** + * The date and time when the customer consented to receive marketing material by SMS. If no date is provided, then the date and time when the consent information was sent is used. + */ + consent_updated_at?: string + /** + * The source for whether the customer has consented to receive marketing material by SMS. + */ + consent_collected_from?: string + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/saveUser/index.ts b/packages/destination-actions/src/destinations/angler-ai/saveUser/index.ts new file mode 100644 index 0000000000..99eb628db2 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/saveUser/index.ts @@ -0,0 +1,25 @@ +import type { ActionDefinition } from '@segment/actions-core' +import { userFields } from '../fields/userFields' +import type { Settings } from '../generated-types' +import { baseURL, customersEndpoint } from '../routes' +import type { Payload } from './generated-types' + +const action: ActionDefinition = { + title: 'Save User', + description: 'Send a customer to Angler.', + fields: { + ...userFields + }, + perform: (request, data) => { + const payload = { + src: 'SEGMENT', + data: [data.payload] + } + return request(baseURL + customersEndpoint(data.settings.workspaceId), { + method: 'post', + json: payload + }) + } +} + +export default action diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCart.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCart.ts new file mode 100644 index 0000000000..a25ea07c4e --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCart.ts @@ -0,0 +1,42 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCart(payload: Payload) { + return { + cart: { + cost: { + totalAmount: { + amount: payload.cart?.totalAmount, + currencyCode: payload.cart?.currencyCode + } + }, + id: payload.cart?.id, + lines: payload.cartLines?.map((cartLine) => ({ + cost: { + totalAmount: { + amount: cartLine.priceAmount + } + }, + merchandise: { + id: cartLine.variantId, + image: { + src: cartLine.imageSrc + }, + price: { + amount: cartLine.priceAmount + }, + product: { + title: cartLine.title, + untranslatedTitle: cartLine.untranslatedTitle, + vendor: cartLine.vendor, + type: cartLine.type, + url: cartLine.url + }, + sku: cartLine.sku, + title: cartLine.title, + untranslatedTitle: cartLine.untranslatedTitle + }, + quantity: cartLine.quantity + })) + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCartLine.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCartLine.ts new file mode 100644 index 0000000000..aa36bb6bd7 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCartLine.ts @@ -0,0 +1,33 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCartLine(payload: Payload) { + return { + cartLine: { + cost: { + totalAmount: { + amount: payload.cartLine?.priceAmount + } + }, + merchandise: { + id: payload.cartLine?.variantId, + image: { + src: payload.cartLine?.imageSrc + }, + price: { + amount: payload.cartLine?.priceAmount + }, + product: { + title: payload.cartLine?.title, + untranslatedTitle: payload.cartLine?.untranslatedTitle, + vendor: payload.cartLine?.vendor, + type: payload.cartLine?.type, + url: payload.cartLine?.url + }, + sku: payload.cartLine?.sku, + title: payload.cartLine?.title, + untranslatedTitle: payload.cartLine?.untranslatedTitle + }, + quantity: payload.cartLine?.quantity + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCheckout.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCheckout.ts new file mode 100644 index 0000000000..395bd6737d --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCheckout.ts @@ -0,0 +1,64 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCheckout(payload: Payload) { + return { + checkout: { + currencyCode: payload.checkout?.currencyCode, + lineItems: payload.checkoutLineItems?.map((lineItem) => ({ + discountAllocations: [ + { + amount: { + amount: lineItem.discountValue + }, + discountApplication: { + title: lineItem.discountTitle, + value: { + amount: lineItem.discountValue + } + } + } + ], + id: lineItem.id, + quantity: lineItem.quantity, + title: lineItem.title, + variant: { + id: lineItem.variantId, + image: { + src: lineItem.imageSrc + }, + price: { + amount: lineItem.priceAmount + }, + product: { + id: lineItem.variantId, + title: lineItem.title, + untranslatedTitle: lineItem.untranslatedTitle, + vendor: lineItem.vendor, + type: lineItem.type, + url: lineItem.url + }, + sku: lineItem.sku, + title: lineItem.title, + untranslatedTitle: lineItem.untranslatedTitle + } + })), + order: { + id: payload.checkout?.orderId + }, + shippingLine: { + price: { + amount: payload.checkout?.shippingLinePriceAmount + } + }, + subtotalPrice: { + amount: payload.checkout?.subtotalPriceAmount + }, + totalPrice: { + amount: payload.checkout?.totalAmount + }, + totalTax: { + amount: payload.checkout?.totalTaxAmount + } + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCollection.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCollection.ts new file mode 100644 index 0000000000..7c5b84155f --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCollection.ts @@ -0,0 +1,30 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCollection(payload: Payload) { + return { + collection: { + id: payload.collection?.id, + title: payload.collection?.title, + productVariants: payload.collectionProductVariants?.map((collectionProductVariant) => ({ + id: collectionProductVariant.variantId, + image: { + src: collectionProductVariant.imageSrc + }, + price: { + amount: collectionProductVariant.priceAmount + }, + product: { + id: collectionProductVariant.id, + title: collectionProductVariant.title, + untranslatedTitle: collectionProductVariant.untranslatedTitle, + vendor: collectionProductVariant.vendor, + type: collectionProductVariant.type, + url: collectionProductVariant.url + }, + sku: collectionProductVariant.sku, + title: collectionProductVariant.title, + untranslatedTitle: collectionProductVariant.untranslatedTitle + })) + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCommonFields.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCommonFields.ts new file mode 100644 index 0000000000..501efba6e0 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCommonFields.ts @@ -0,0 +1,30 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCommonFields(payload: Payload) { + return { + event_id: payload.eventId, + event_name: payload.eventName, + ip_address: payload.ipAddress, + user_agent: payload.userAgent, + timestamp: payload.timestamp, + fpb: payload.identifiers.fbp, + fbc: payload.identifiers.fbc, + ga: payload.identifiers.ga, + identifiers: Object.keys(payload.identifiers).reduce((acc: { name: string; value: string }[], key) => { + const omitKeys = ['userId', 'anonymousId', 'clientId', 'fbp', 'fbc', 'ga'] + if (omitKeys.includes(key)) { + return acc + } + return [...acc, { name: key, value: String(payload.identifiers[key]) }] + }, []), + url: payload.page?.url, + client_id: payload.identifiers.clientId, + referrer: payload.page?.referrer, + data: { + customData: Object.entries(payload.customAttributes || {}).map(([key, value]) => ({ + name: key, + value + })) + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCustomer.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCustomer.ts new file mode 100644 index 0000000000..9245968fb3 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformCustomer.ts @@ -0,0 +1,14 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformCustomer(payload: Payload) { + return { + customer: { + id: payload.identifiers.userId, + email: payload.customer?.email, + firstName: payload.customer?.firstName, + lastName: payload.customer?.lastName, + phone: payload.customer?.phone, + dob: payload.customer?.dob + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformForm.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformForm.ts new file mode 100644 index 0000000000..003974ab76 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformForm.ts @@ -0,0 +1,17 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformForm(payload: Payload) { + return { + form: { + id: payload.id, + action: payload.action, + elements: payload.elements?.map((element) => ({ + id: element.id, + name: element.name, + tagName: element.tagName, + type: element.type, + value: element.value + })) + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformProductVariant.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformProductVariant.ts new file mode 100644 index 0000000000..834b1eab52 --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformProductVariant.ts @@ -0,0 +1,26 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformProductVariant(payload: Payload) { + return { + productVariant: { + id: payload.productVariant?.variantId, + image: { + src: payload.productVariant?.imageSrc + }, + price: { + amount: payload.productVariant?.priceAmount + }, + product: { + id: payload.productVariant?.id, + title: payload.productVariant?.title, + untranslatedTitle: payload.productVariant?.untranslatedTitle, + vendor: payload.productVariant?.vendor, + type: payload.productVariant?.type, + url: payload.productVariant?.url + }, + sku: payload.productVariant?.sku, + title: payload.productVariant?.title, + untranslatedTitle: payload.productVariant?.untranslatedTitle + } + } +} diff --git a/packages/destination-actions/src/destinations/angler-ai/transformFields/transformSearch.ts b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformSearch.ts new file mode 100644 index 0000000000..635bd6645c --- /dev/null +++ b/packages/destination-actions/src/destinations/angler-ai/transformFields/transformSearch.ts @@ -0,0 +1,29 @@ +import { Payload } from '../saveCustomEvent/generated-types' + +export function transformSearch(payload: Payload) { + return { + searchResult: { + query: payload.query, + productVariants: payload.searchResults?.map((productVariant) => ({ + id: productVariant.variantId, + image: { + src: productVariant.imageSrc + }, + price: { + amount: productVariant.priceAmount + }, + product: { + id: productVariant.id, + title: productVariant.title, + untranslatedTitle: productVariant.untranslatedTitle, + vendor: productVariant.vendor, + type: productVariant.type, + url: productVariant.url + }, + sku: productVariant.sku, + title: productVariant.title, + untranslatedTitle: productVariant.untranslatedTitle + })) + } + } +} diff --git a/packages/destination-actions/src/destinations/app-fit/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/app-fit/__tests__/__snapshots__/snapshot.test.ts.snap index 91c320392b..9451a47a03 100644 --- a/packages/destination-actions/src/destinations/app-fit/__tests__/__snapshots__/snapshot.test.ts.snap +++ b/packages/destination-actions/src/destinations/app-fit/__tests__/__snapshots__/snapshot.test.ts.snap @@ -6,15 +6,27 @@ Object { "occurredAt": "2021-02-01T00:00:00.000Z", "payload": Object { "anonymousId": "m]^ldlwPRQruDQ&OXR1", - "deviceId": "m]^ldlwPRQruDQ&OXR1", - "deviceType": "m]^ldlwPRQruDQ&OXR1", - "eventId": "m]^ldlwPRQruDQ&OXR1", - "name": "m]^ldlwPRQruDQ&OXR1", - "osName": "m]^ldlwPRQruDQ&OXR1", + "eventName": "m]^ldlwPRQruDQ&OXR1", "properties": Object { "testType": "m]^ldlwPRQruDQ&OXR1", }, + "sourceEventId": "m]^ldlwPRQruDQ&OXR1", + "systemProperties": Object { + "appVersion": "m]^ldlwPRQruDQ&OXR1", + "device": Object { + "advertisingId": "m]^ldlwPRQruDQ&OXR1", + "id": "m]^ldlwPRQruDQ&OXR1", + "manufacturer": "m]^ldlwPRQruDQ&OXR1", + "model": "m]^ldlwPRQruDQ&OXR1", + }, + "ipAddress": "m]^ldlwPRQruDQ&OXR1", + "os": Object { + "name": "m]^ldlwPRQruDQ&OXR1", + "version": "m]^ldlwPRQruDQ&OXR1", + }, + }, "userId": "m]^ldlwPRQruDQ&OXR1", + "version": "2", }, } `; @@ -24,8 +36,13 @@ Object { "eventSource": "segment", "occurredAt": "2021-02-01T00:00:00.000Z", "payload": Object { - "eventId": "m]^ldlwPRQruDQ&OXR1", - "name": "m]^ldlwPRQruDQ&OXR1", + "eventName": "m]^ldlwPRQruDQ&OXR1", + "sourceEventId": "m]^ldlwPRQruDQ&OXR1", + "systemProperties": Object { + "device": Object {}, + "os": Object {}, + }, + "version": "2", }, } `; diff --git a/packages/destination-actions/src/destinations/app-fit/track/__tests__/__snapshots__/snapshot.test.ts.snap b/packages/destination-actions/src/destinations/app-fit/track/__tests__/__snapshots__/snapshot.test.ts.snap index 6d5134ace4..2d202e7e9d 100644 --- a/packages/destination-actions/src/destinations/app-fit/track/__tests__/__snapshots__/snapshot.test.ts.snap +++ b/packages/destination-actions/src/destinations/app-fit/track/__tests__/__snapshots__/snapshot.test.ts.snap @@ -6,15 +6,27 @@ Object { "occurredAt": "2021-02-01T00:00:00.000Z", "payload": Object { "anonymousId": "M$xwt#p", - "deviceId": "M$xwt#p", - "deviceType": "M$xwt#p", - "eventId": "M$xwt#p", - "name": "M$xwt#p", - "osName": "M$xwt#p", + "eventName": "M$xwt#p", "properties": Object { "testType": "M$xwt#p", }, + "sourceEventId": "M$xwt#p", + "systemProperties": Object { + "appVersion": "M$xwt#p", + "device": Object { + "advertisingId": "M$xwt#p", + "id": "M$xwt#p", + "manufacturer": "M$xwt#p", + "model": "M$xwt#p", + }, + "ipAddress": "M$xwt#p", + "os": Object { + "name": "M$xwt#p", + "version": "M$xwt#p", + }, + }, "userId": "M$xwt#p", + "version": "2", }, } `; @@ -24,8 +36,13 @@ Object { "eventSource": "segment", "occurredAt": "2021-02-01T00:00:00.000Z", "payload": Object { - "eventId": "M$xwt#p", - "name": "M$xwt#p", + "eventName": "M$xwt#p", + "sourceEventId": "M$xwt#p", + "systemProperties": Object { + "device": Object {}, + "os": Object {}, + }, + "version": "2", }, } `; diff --git a/packages/destination-actions/src/destinations/app-fit/track/__tests__/index.test.ts b/packages/destination-actions/src/destinations/app-fit/track/__tests__/index.test.ts index 1ce6845338..aab9508159 100644 --- a/packages/destination-actions/src/destinations/app-fit/track/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/app-fit/track/__tests__/index.test.ts @@ -9,11 +9,16 @@ describe('AppFit.track', () => { it('should create an event', async () => { const timestamp = new Date().toISOString() const event = createTestEvent({ - name: 'Segment Test Event Name', + event: 'Segment Test Event Name', messageId: '12345', userId: 'userId1', timestamp, - context: { device: { id: 'device1234', type: 'ios' }, os: { name: 'iPhone OS' } }, + context: { + ip: '8.8.8.8', + app: { version: '1.0.0' }, + device: { id: 'device1234', advertisingId: 'adId1234', type: 'ios', model: 'iPhone7,2', manufacturer: 'Apple' }, + os: { name: 'iPhone OS', version: '10.1' } + }, properties: { foo: 'bar' } }) @@ -28,7 +33,7 @@ describe('AppFit.track', () => { expect(responses[0].status).toBe(200) expect(responses[0].data).toMatchObject({}) expect(responses[0].options.body).toBe( - `{"eventSource":"segment","occurredAt":"${timestamp}","payload":{"eventId":"12345","userId":"userId1","anonymousId":"anonId1234","name":"Test Event","properties":{"foo":"bar"},"deviceId":"device1234","deviceType":"ios","osName":"iPhone OS"}}` + `{"eventSource":"segment","occurredAt":"${timestamp}","payload":{"version":"2","sourceEventId":"12345","eventName":"Segment Test Event Name","userId":"userId1","anonymousId":"anonId1234","properties":{"foo":"bar"},"systemProperties":{"appVersion":"1.0.0","ipAddress":"8.8.8.8","os":{"name":"iPhone OS","version":"10.1"},"device":{"id":"device1234","advertisingId":"adId1234","manufacturer":"Apple","model":"iPhone7,2"}}}}` ) }) }) diff --git a/packages/destination-actions/src/destinations/app-fit/track/generated-types.ts b/packages/destination-actions/src/destinations/app-fit/track/generated-types.ts index cc2087b012..3f407245a3 100644 --- a/packages/destination-actions/src/destinations/app-fit/track/generated-types.ts +++ b/packages/destination-actions/src/destinations/app-fit/track/generated-types.ts @@ -23,6 +23,10 @@ export interface Payload { properties?: { [k: string]: unknown } + /** + * The app version + */ + appVersion?: string /** * The device ID of the user */ @@ -31,10 +35,30 @@ export interface Payload { * The device type */ deviceType?: string + /** + * The device manufacturer + */ + deviceManufacturer?: string + /** + * The device model + */ + deviceModel?: string + /** + * The device advertising ID + */ + deviceAdvertisingId?: string + /** + * The IP address of the client + */ + ipAddress?: string /** * The name of the operating system */ osName?: string + /** + * The version of the operating system + */ + osVersion?: string /** * The event ID */ diff --git a/packages/destination-actions/src/destinations/app-fit/track/index.ts b/packages/destination-actions/src/destinations/app-fit/track/index.ts index dab147b26c..86b3ed6bd4 100644 --- a/packages/destination-actions/src/destinations/app-fit/track/index.ts +++ b/packages/destination-actions/src/destinations/app-fit/track/index.ts @@ -49,6 +49,14 @@ const action: ActionDefinition = { '@path': '$.properties' } }, + appVersion: { + label: 'App Version', + description: 'The app version', + type: 'string', + default: { + '@path': '$.context.app.version' + } + }, deviceId: { label: 'Device ID', description: 'The device ID of the user', @@ -65,6 +73,38 @@ const action: ActionDefinition = { '@path': '$.context.device.type' } }, + deviceManufacturer: { + label: 'Device Manufacturer', + description: 'The device manufacturer', + type: 'string', + default: { + '@path': '$.context.device.manufacturer' + } + }, + deviceModel: { + label: 'Device Model', + description: 'The device model', + type: 'string', + default: { + '@path': '$.context.device.model' + } + }, + deviceAdvertisingId: { + label: 'Device Advertising ID', + description: 'The device advertising ID', + type: 'string', + default: { + '@path': '$.context.device.advertisingId' + } + }, + ipAddress: { + label: 'IP Address', + description: 'The IP address of the client', + type: 'string', + default: { + '@path': '$.context.ip' + } + }, osName: { label: 'OS Name', description: 'The name of the operating system', @@ -73,6 +113,14 @@ const action: ActionDefinition = { '@path': '$.context.os.name' } }, + osVersion: { + label: 'OS Version', + description: 'The version of the operating system', + type: 'string', + default: { + '@path': '$.context.os.version' + } + }, eventId: { label: 'Event ID', description: 'The event ID', @@ -92,14 +140,26 @@ const action: ActionDefinition = { eventSource: 'segment', occurredAt: payload.occurredAt, payload: { - eventId: payload.eventId, + version: '2', + sourceEventId: payload.eventId, + eventName: payload.name, userId: payload.userId, anonymousId: payload.anonymousId, - name: payload.name, properties: payload.properties, - deviceId: payload.deviceId, - deviceType: payload.deviceType, - osName: payload.osName + systemProperties: { + appVersion: payload.appVersion, + ipAddress: payload.ipAddress, + os: { + name: payload.osName, + version: payload.osVersion + }, + device: { + id: payload.deviceId, + advertisingId: payload.deviceAdvertisingId, + manufacturer: payload.deviceManufacturer, + model: payload.deviceModel + } + } } } }) diff --git a/packages/destination-actions/src/destinations/customerio/__tests__/createUpdatePerson.test.ts b/packages/destination-actions/src/destinations/customerio/__tests__/createUpdatePerson.test.ts index 3bc259f5af..78eede8415 100644 --- a/packages/destination-actions/src/destinations/customerio/__tests__/createUpdatePerson.test.ts +++ b/packages/destination-actions/src/destinations/customerio/__tests__/createUpdatePerson.test.ts @@ -403,21 +403,18 @@ describe('CustomerIO', () => { full_name: 'Test User', email: 'test@example.com', created_at: timestamp, + objectId: groupId, person: { over18: true, identification: 'valid', birthdate } } - const context = { - groupId: groupId - } const event = createTestEvent({ userId, anonymousId, timestamp, - traits, - context + traits }) const response = await action('createUpdatePerson', { event, @@ -455,25 +452,23 @@ describe('CustomerIO', () => { const timestamp = dayjs.utc().toISOString() const groupId = 'g12345' const traits: { + objectId: string full_name: string email: string created_at: string object_type_id?: string } = { + objectId: groupId, full_name: 'Test User', email: 'test@example.com', created_at: timestamp, object_type_id: '2' } - const context = { - groupId: groupId - } const event = createTestEvent({ userId, anonymousId, timestamp, - traits, - context + traits }) const response = await action('createUpdatePerson', { event, @@ -590,6 +585,7 @@ describe('CustomerIO', () => { full_name: 'Test User', email: 'test@example.com', createdAt: timestamp, + objectId: groupId, person: { over18: true, identification: 'valid', @@ -598,16 +594,11 @@ describe('CustomerIO', () => { relationshipAttributes } - const context = { - groupId: groupId - } - const event = createTestEvent({ userId, anonymousId, timestamp, - traits, - context + traits }) const response = await action('createUpdatePerson', { event, @@ -621,6 +612,7 @@ describe('CustomerIO', () => { anonymous_id: anonymousId, created_at: dayjs.utc(timestamp).unix(), email: traits.email, + objectId: groupId, full_name: traits.full_name, person: { ...traits.person, @@ -650,6 +642,7 @@ describe('CustomerIO', () => { full_name: 'Test User', email: 'test@example.com', createdAt: timestamp, + objectId: groupId, person: { over18: true, identification: 'valid', @@ -660,17 +653,11 @@ describe('CustomerIO', () => { prefix: 'Mr.' } } - - const context = { - groupId: groupId - } - const event = createTestEvent({ userId, anonymousId, timestamp, - traits, - context + traits }) const mapping = getDefaultMappings('createUpdatePerson') @@ -687,6 +674,7 @@ describe('CustomerIO', () => { created_at: dayjs.utc(timestamp).unix(), email: traits.email, full_name: traits.full_name, + objectId: groupId, person: { ...traits.person, birthdate: dayjs.utc(birthdate).unix() diff --git a/packages/destination-actions/src/destinations/customerio/__tests__/deleteObject.test.ts b/packages/destination-actions/src/destinations/customerio/__tests__/deleteObject.test.ts index 73a2762dab..2305993eee 100644 --- a/packages/destination-actions/src/destinations/customerio/__tests__/deleteObject.test.ts +++ b/packages/destination-actions/src/destinations/customerio/__tests__/deleteObject.test.ts @@ -9,11 +9,9 @@ describe('CustomerIO', () => { const groupId = 'group_123' const objectTypeId = 'type_123' const event = createTestEvent({ - context: { - groupId - }, properties: { - objectTypeId + objectTypeId, + objectId: groupId } }) const response = await action('deleteObject', { diff --git a/packages/destination-actions/src/destinations/customerio/__tests__/deleteRelationship.test.ts b/packages/destination-actions/src/destinations/customerio/__tests__/deleteRelationship.test.ts index 8e9562d610..347d5756e8 100644 --- a/packages/destination-actions/src/destinations/customerio/__tests__/deleteRelationship.test.ts +++ b/packages/destination-actions/src/destinations/customerio/__tests__/deleteRelationship.test.ts @@ -11,10 +11,8 @@ describe('CustomerIO', () => { const objectId = 'object_id123' const objectTypeId = 'object_type_id123' const event = createTestEvent({ - context: { - groupId: objectId - }, properties: { + objectId: objectId, objectTypeId: objectTypeId } }) @@ -58,11 +56,9 @@ describe('CustomerIO', () => { const objectId = 'object_id123' const objectTypeId = 'object_type_id123' const event = createTestEvent({ - context: { - groupId: objectId - }, properties: { - objectTypeId + objectTypeId, + objectId } }) @@ -107,10 +103,8 @@ describe('CustomerIO', () => { it('should work if `userId` is an id', async () => { const event = createTestEvent({ - context: { - groupId: 'object_id123' - }, properties: { + objectId: 'object_id123', objectTypeId: 'object_type_id123' }, userId: '123' @@ -135,7 +129,7 @@ describe('CustomerIO', () => { } ], identifiers: { - object_id: event.context?.groupId, + object_id: event.properties?.objectId, object_type_id: event.properties?.objectTypeId }, type: 'object' @@ -144,11 +138,9 @@ describe('CustomerIO', () => { it('should work if `userId` is an email', async () => { const event = createTestEvent({ - context: { - groupId: 'object_id123' - }, properties: { - objectTypeId: 'object_type_id123' + objectTypeId: 'object_type_id123', + objectId: 'object_id123' }, userId: 'foo@bar.com' }) @@ -172,7 +164,7 @@ describe('CustomerIO', () => { } ], identifiers: { - object_id: event.context?.groupId, + object_id: event.properties?.objectId, object_type_id: event.properties?.objectTypeId }, type: 'object' @@ -181,10 +173,8 @@ describe('CustomerIO', () => { it('should work if `userId` is a `cio_` identifier', async () => { const event = createTestEvent({ - context: { - groupId: 'object_id123' - }, properties: { + objectId: 'object_id123', objectTypeId: 'object_type_id123' }, userId: 'cio_456' @@ -209,7 +199,7 @@ describe('CustomerIO', () => { } ], identifiers: { - object_id: event.context?.groupId, + object_id: event.properties?.objectId, object_type_id: event.properties?.objectTypeId }, type: 'object' diff --git a/packages/destination-actions/src/destinations/customerio/createUpdateObject/index.ts b/packages/destination-actions/src/destinations/customerio/createUpdateObject/index.ts index 4346ead5c0..0686a84b67 100644 --- a/packages/destination-actions/src/destinations/customerio/createUpdateObject/index.ts +++ b/packages/destination-actions/src/destinations/customerio/createUpdateObject/index.ts @@ -144,6 +144,10 @@ function mapPayload(payload: Payload) { object_type_id: object_type_id ?? '1', object_id: id } + // Removes `object_type_id` and `relationshipAttributes` from the `custom_attributes` object because our API does not use these values. + delete custom_attributes?.object_type_id + delete custom_attributes?.objectTypeId + delete custom_attributes?.relationshipAttributes let rel_attrs = relationship_attributes as Record diff --git a/packages/destination-actions/src/destinations/customerio/createUpdatePerson/index.ts b/packages/destination-actions/src/destinations/customerio/createUpdatePerson/index.ts index 1545adf3fb..307c5c1eb5 100644 --- a/packages/destination-actions/src/destinations/customerio/createUpdatePerson/index.ts +++ b/packages/destination-actions/src/destinations/customerio/createUpdatePerson/index.ts @@ -56,7 +56,7 @@ const action: ActionDefinition = { 'The ID used to uniquely identify an object in Customer.io. [Learn more](https://customer.io/docs/object-relationships).', type: 'string', default: { - '@path': '$.context.groupId' + '@path': '$.traits.objectId' } }, custom_attributes: { @@ -118,6 +118,7 @@ function mapPayload(payload: Payload) { delete custom_attributes.created_at delete custom_attributes?.object_type_id delete custom_attributes?.relationshipAttributes + delete custom_attributes?.objectTypeId if (created_at) { custom_attributes.created_at = created_at diff --git a/packages/destination-actions/src/destinations/customerio/deleteDevice/index.ts b/packages/destination-actions/src/destinations/customerio/deleteDevice/index.ts index 84609007f7..65f9951c0a 100644 --- a/packages/destination-actions/src/destinations/customerio/deleteDevice/index.ts +++ b/packages/destination-actions/src/destinations/customerio/deleteDevice/index.ts @@ -6,7 +6,7 @@ import { sendBatch, sendSingle } from '../utils' const action: ActionDefinition = { title: 'Delete Device', description: `Delete a person's device.`, - defaultSubscription: 'event = "Application Uninstalled"', + defaultSubscription: 'event = "Application Uninstalled" or event = "Device Deleted"', fields: { person_id: { label: 'Person ID', diff --git a/packages/destination-actions/src/destinations/customerio/deleteObject/index.ts b/packages/destination-actions/src/destinations/customerio/deleteObject/index.ts index aa0ef250a5..db0507bae2 100644 --- a/packages/destination-actions/src/destinations/customerio/deleteObject/index.ts +++ b/packages/destination-actions/src/destinations/customerio/deleteObject/index.ts @@ -13,7 +13,7 @@ const action: ActionDefinition = { description: 'An object ID used to identify an object.', type: 'string', default: { - '@path': '$.context.groupId' + '@path': '$.properties.objectId' } }, object_type_id: { diff --git a/packages/destination-actions/src/destinations/customerio/deleteRelationship/index.ts b/packages/destination-actions/src/destinations/customerio/deleteRelationship/index.ts index cac481d252..bb46a2ec6b 100644 --- a/packages/destination-actions/src/destinations/customerio/deleteRelationship/index.ts +++ b/packages/destination-actions/src/destinations/customerio/deleteRelationship/index.ts @@ -31,7 +31,7 @@ const action: ActionDefinition = { description: 'An object ID used to identify an object.', type: 'string', default: { - '@path': '$.context.groupId' + '@path': '$.properties.objectId' }, required: true }, diff --git a/packages/destination-actions/src/destinations/google-enhanced-conversions/postConversion/index.ts b/packages/destination-actions/src/destinations/google-enhanced-conversions/postConversion/index.ts index 90ccf38c06..cfa4bf0305 100644 --- a/packages/destination-actions/src/destinations/google-enhanced-conversions/postConversion/index.ts +++ b/packages/destination-actions/src/destinations/google-enhanced-conversions/postConversion/index.ts @@ -26,6 +26,7 @@ interface GoogleError { const action: ActionDefinition = { title: 'Upload Enhanced Conversion (Legacy)', description: 'Upload a conversion enhancement to the legacy Google Enhanced Conversions API.', + hidden: true, fields: { // Required Fields - These fields are required by Google's EC API to successfully match conversions. conversion_label: { diff --git a/packages/destination-actions/src/destinations/index.ts b/packages/destination-actions/src/destinations/index.ts index 0260ad52d9..3145d94c57 100644 --- a/packages/destination-actions/src/destinations/index.ts +++ b/packages/destination-actions/src/destinations/index.ts @@ -168,6 +168,7 @@ register('664ce7bdc820c71f7e3ff031', './contentstack') register('664ce847b3e6f19ea96b3611', './trubrics') register('66684ba89c0523461d8bb7f3', './taboola-actions') register('6683e1d5e37fd84efcf3bbef', './first-party-dv360') +register('668d1cb2a1dcc5ad33228d92', './angler-ai') function register(id: MetadataId, destinationPath: string) { // eslint-disable-next-line @typescript-eslint/no-var-requires diff --git a/packages/destination-actions/src/destinations/moloco-rmp/__tests__/convert.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/__tests__/convert.test.ts index 63e9e81e6c..1d79593a40 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/__tests__/convert.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/__tests__/convert.test.ts @@ -31,26 +31,26 @@ describe('Moloco MCM', () => { currency: 'USD', price: 12.34, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', currency: 'USD', price: 56.78, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - price: 69.12, + price: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - price: 5.00 + price: 5.0 } } @@ -79,7 +79,7 @@ describe('Moloco MCM', () => { amount: 12.34 }, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', @@ -88,23 +88,32 @@ describe('Moloco MCM', () => { amount: 56.78 }, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - amount: 69.12, + amount: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - amount: 5.00 + amount: 5.0 } } - - const output: MolocoEventPayload = convertEvent({ eventType: TEST_EVENT_TYPE, payload: input, settings: { channel_type: 'APP', platformId: 'any_plat_id', apiKey: 'any_api_key'}}) + + const output: MolocoEventPayload = convertEvent({ + eventType: TEST_EVENT_TYPE, + payload: input, + settings: { + channel_type: 'APP', + platformId: 'any_plat_id', + platformName: 'any_plat_name', + apiKey: 'any_api_key' + } + }) expect(output).toEqual(expectedOutput) }) @@ -130,26 +139,26 @@ describe('Moloco MCM', () => { currency: 'USD', price: 12.34, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', currency: 'USD', price: 56.78, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - price: 69.12, + price: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - price: 5.00 + price: 5.0 } } @@ -178,7 +187,7 @@ describe('Moloco MCM', () => { amount: 12.34 }, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', @@ -187,23 +196,32 @@ describe('Moloco MCM', () => { amount: 56.78 }, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - amount: 69.12, + amount: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - amount: 5.00 + amount: 5.0 } } - - const output: MolocoEventPayload = convertEvent({ eventType: TEST_EVENT_TYPE, payload: input, settings: { channel_type: 'APP', platformId: 'any_plat_id', apiKey: 'any_api_key'}}) + + const output: MolocoEventPayload = convertEvent({ + eventType: TEST_EVENT_TYPE, + payload: input, + settings: { + channel_type: 'APP', + platformId: 'any_plat_id', + platformName: 'any_plat_name', + apiKey: 'any_api_key' + } + }) expect(output).toEqual(expectedOutput) }) @@ -229,26 +247,26 @@ describe('Moloco MCM', () => { currency: 'USD', price: 12.34, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', currency: 'USD', price: 56.78, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - price: 69.12, + price: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - price: 5.00 + price: 5.0 } } @@ -277,7 +295,7 @@ describe('Moloco MCM', () => { amount: 12.34 }, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', @@ -286,27 +304,35 @@ describe('Moloco MCM', () => { amount: 56.78 }, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - amount: 69.12, + amount: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - amount: 5.00 + amount: 5.0 } } - - const output: MolocoEventPayload = convertEvent({ eventType: TEST_EVENT_TYPE, payload: input, settings: { channel_type: 'APP', platformId: 'any_plat_id', apiKey: 'any_api_key'}}) + + const output: MolocoEventPayload = convertEvent({ + eventType: TEST_EVENT_TYPE, + payload: input, + settings: { + channel_type: 'APP', + platformId: 'any_plat_id', + platformName: 'any_plat_name', + apiKey: 'any_api_key' + } + }) expect(output).toEqual(expectedOutput) }) - it('tests an event payload with a missing field (session_id)', async () => { const input: SegmentEventPayload = { event_id: '12e64c12-f386-42c9-871b-8dg3e539ad19', @@ -328,26 +354,26 @@ describe('Moloco MCM', () => { currency: 'USD', price: 12.34, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', currency: 'USD', price: 56.78, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - price: 69.12, + price: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - price: 5.00 + price: 5.0 } } @@ -375,7 +401,7 @@ describe('Moloco MCM', () => { amount: 12.34 }, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', @@ -384,23 +410,32 @@ describe('Moloco MCM', () => { amount: 56.78 }, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ], revenue: { currency: 'USD', - amount: 69.12, + amount: 69.12 }, search_query: 'iphone', page_id: '/home', referrer_page_id: 'google.com', shipping_charge: { currency: 'USD', - amount: 5.00 + amount: 5.0 } } - - const output: MolocoEventPayload = convertEvent({ eventType: TEST_EVENT_TYPE, payload: input, settings: { channel_type: 'APP', platformId: 'any_plat_id', apiKey: 'any_api_key'}}) + + const output: MolocoEventPayload = convertEvent({ + eventType: TEST_EVENT_TYPE, + payload: input, + settings: { + channel_type: 'APP', + platformId: 'any_plat_id', + platformName: 'any_plat_name', + apiKey: 'any_api_key' + } + }) expect(output).toEqual(expectedOutput) }) @@ -425,19 +460,30 @@ describe('Moloco MCM', () => { id: '123', price: 12.34, quantity: 1, - seller_id: 'cs032b-11ee-9a73-0n5e570313ef', + seller_id: 'cs032b-11ee-9a73-0n5e570313ef' }, { id: '456', currency: 'USD', price: 56.78, quantity: 2, - seller_id: 'cs032b-11ee-9a73-w5e570313ef', + seller_id: 'cs032b-11ee-9a73-w5e570313ef' } ] } - expect(() => convertEvent({ eventType: TEST_EVENT_TYPE, payload: input, settings: { channel_type: 'APP', platformId: 'any_plat_id', apiKey: 'any_api_key'} })).toThrowError(PayloadValidationError) + expect(() => + convertEvent({ + eventType: TEST_EVENT_TYPE, + payload: input, + settings: { + channel_type: 'APP', + platformId: 'any_plat_id', + platformName: 'any_plat_name', + apiKey: 'any_api_key' + } + }) + ).toThrowError(PayloadValidationError) }) }) }) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/__tests__/index.test.ts index b2fd50e923..08a63edab9 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/__tests__/index.test.ts @@ -14,11 +14,11 @@ const TEST_EVENT_TYPE = EventType.Home const AUTH = { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', channel_type: 'SITE' } - describe('Moloco MCM', () => { // TEST 1: Test the default mappings. The input event data are automatically collected fields // Custom mapping options are not provided so the default mappings are used @@ -56,9 +56,9 @@ describe('Moloco MCM', () => { url: 'https://segment.com/academy/' }, userAgent: - 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36', + 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -68,19 +68,19 @@ describe('Moloco MCM', () => { user_id: webEvent.userId, device: { ua: webEvent.context.userAgent, - ip: webEvent.context.ip, + ip: webEvent.context.ip }, session_id: webEvent.anonymousId, - page_id: webEvent.context.page.path, + page_id: webEvent.context.page.path } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: webEvent, settings: AUTH, useDefaultMappings: true, mapping: { - channel_type: 'SITE', - }, + channel_type: 'SITE' + } }) expect(responses.length).toBe(1) @@ -109,7 +109,7 @@ describe('Moloco MCM', () => { app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'ios', @@ -118,7 +118,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Apple', model: 'iPhone', - name: 'iPhone', + name: 'iPhone' }, library: { name: 'analytics.iOS', @@ -140,9 +140,9 @@ describe('Moloco MCM', () => { width: 750 }, traits: {}, - timezone: 'America/Los_Angeles', + timezone: 'America/Los_Angeles' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -156,18 +156,18 @@ describe('Moloco MCM', () => { model: iosEvent.context.device.model, os: iosEvent.context.os.name.toUpperCase(), os_version: iosEvent.context.os.version, - unique_device_id: iosEvent.context.device.id, + unique_device_id: iosEvent.context.device.id }, - session_id: iosEvent.anonymousId, + session_id: iosEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: iosEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { - channel_type: 'APP', - }, + channel_type: 'APP' + } }) expect(responses.length).toBe(1) @@ -196,7 +196,7 @@ describe('Moloco MCM', () => { app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -205,7 +205,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -217,7 +217,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -229,10 +229,11 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', - timezone: 'America/Los_Angeles', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + timezone: 'America/Los_Angeles' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -247,18 +248,18 @@ describe('Moloco MCM', () => { os: androidEvent.context.os.name.toUpperCase(), os_version: androidEvent.context.os.version, ua: androidEvent.context.userAgent, - unique_device_id: androidEvent.context.device.id, + unique_device_id: androidEvent.context.device.id }, - session_id: androidEvent.anonymousId, + session_id: androidEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: androidEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { - channel_type: 'APP', - }, + channel_type: 'APP' + } }) expect(responses.length).toBe(1) @@ -295,9 +296,9 @@ describe('Moloco MCM', () => { url: 'https://segment.com/academy/' }, userAgent: - 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36', + 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -306,30 +307,28 @@ describe('Moloco MCM', () => { channel_type: 'SITE', user_id: event.userId, device: { - ua: event.context.userAgent, + ua: event.context.userAgent // ip: event.context.ip, -- absent even though there is a default mapping for it }, session_id: event.anonymousId, - page_id: event.context.page.path, + page_id: event.context.page.path } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: event, settings: AUTH, useDefaultMappings: true, mapping: { - channel_type: 'SITE', - }, + channel_type: 'SITE' + } }) expect(responses.length).toBe(1) expect(responses[0].status).toBe(200) expect(responses[0].options.json).toEqual(expectedPayload) }) - }) - // TEST 2: Test the custom mappings. The input event data are automatically collected fields // Custom mapping options are provided so the default mappings are not used // This tests @@ -366,9 +365,9 @@ describe('Moloco MCM', () => { url: 'https://segment.com/academy/' }, userAgent: - 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36', + 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -378,12 +377,12 @@ describe('Moloco MCM', () => { user_id: event.userId, device: { ua: event.context.userAgent, - ip: event.context.ip, + ip: event.context.ip }, session_id: event.anonymousId, - page_id: event.context.page.path, + page_id: event.context.page.path } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: event, settings: AUTH, @@ -391,7 +390,7 @@ describe('Moloco MCM', () => { mapping: { channel_type: 'SITE', event_id: { '@path': '$.eventId' } - }, + } }) expect(responses.length).toBe(1) @@ -429,9 +428,9 @@ describe('Moloco MCM', () => { url: 'https://segment.com/academy/' }, userAgent: - 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36', + 'Mozilla/5.0 (Chrome; intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -441,12 +440,12 @@ describe('Moloco MCM', () => { user_id: event.userId, device: { ua: event.context.userAgent, - ip: event.context.ip, + ip: event.context.ip }, session_id: event.anonymousId, - page_id: event.context.page.path, + page_id: event.context.page.path } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: event, settings: AUTH, @@ -455,7 +454,7 @@ describe('Moloco MCM', () => { timestamp: { '@path': '$.timestamp' }, channel_type: 'SITE', event_id: { '@path': '$.eventId' } - }, + } }) expect(responses.length).toBe(1) @@ -463,7 +462,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate custom mappings for an object array mapping(items). The input IS NOT an array.' , async () => { + it('should validate custom mappings for an object array mapping(items). The input IS NOT an array.', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -486,12 +485,12 @@ describe('Moloco MCM', () => { name: 'Monopoly: 3rd Edition', price: 19.99, brand: 'Hasbro', - currency: 'USD', + currency: 'USD' }, app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -500,7 +499,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -512,7 +511,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -524,10 +523,11 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', - timezone: 'America/Los_Angeles', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + timezone: 'America/Los_Angeles' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -542,23 +542,23 @@ describe('Moloco MCM', () => { os: androidEvent.context.os.name.toUpperCase(), os_version: androidEvent.context.os.version, ua: androidEvent.context.userAgent, - unique_device_id: androidEvent.context.device.id, + unique_device_id: androidEvent.context.device.id }, items: [ { id: androidEvent.context.product.id, price: { amount: androidEvent.context.product.price, - currency: androidEvent.context.product.currency, + currency: androidEvent.context.product.currency } } ], - session_id: androidEvent.anonymousId, + session_id: androidEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: androidEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { channel_type: 'APP', @@ -567,9 +567,9 @@ describe('Moloco MCM', () => { id: { '@path': '$.context.product.id' }, price: { '@path': '$.context.product.price' }, currency: { '@path': '$.context.product.currency' } - }, + } ] - }, + } }) expect(responses.length).toBe(1) @@ -577,7 +577,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate custom mappings for an object array mapping(items). The input IS an array.' , async () => { + it('should validate custom mappings for an object array mapping(items). The input IS an array.', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -601,20 +601,20 @@ describe('Moloco MCM', () => { name: 'Monopoly: 3rd Edition', price: 19.99, brand: 'Hasbro', - currency: 'USD', + currency: 'USD' }, { id: 'nae2d1', name: 'Hogwarts: 3rd Edition', price: 29.99, brand: 'Hasbro', - currency: 'USD', + currency: 'USD' } ], app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -623,7 +623,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -635,7 +635,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -647,10 +647,11 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', - timezone: 'America/Los_Angeles', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + timezone: 'America/Los_Angeles' } - } as const; + } as const const expectedPayload: EventPayload = { event_type: TEST_EVENT_TYPE, @@ -665,30 +666,30 @@ describe('Moloco MCM', () => { os: androidEvent.context.os.name.toUpperCase(), os_version: androidEvent.context.os.version, ua: androidEvent.context.userAgent, - unique_device_id: androidEvent.context.device.id, + unique_device_id: androidEvent.context.device.id }, items: [ { id: androidEvent.context.product[0].id, price: { amount: androidEvent.context.product[0].price, - currency: androidEvent.context.product[0].currency, + currency: androidEvent.context.product[0].currency } }, { id: androidEvent.context.product[1].id, price: { amount: androidEvent.context.product[1].price, - currency: androidEvent.context.product[0].currency, + currency: androidEvent.context.product[0].currency } } ], - session_id: androidEvent.anonymousId, + session_id: androidEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: androidEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { channel_type: 'APP', @@ -702,7 +703,7 @@ describe('Moloco MCM', () => { } ] } - }, + } }) expect(responses.length).toBe(1) @@ -710,7 +711,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate items mapping with currency / when both default currency and currency for each item are given, it should use the latter.' , async () => { + it('should validate items mapping with currency / when both default currency and currency for each item are given, it should use the latter.', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -735,20 +736,20 @@ describe('Moloco MCM', () => { name: 'Monopoly: 3rd Edition', price: 19.99, brand: 'Hasbro', - currency: 'USD', + currency: 'USD' }, { id: 'nae2d1', name: 'Hogwarts: 3rd Edition', price: 29.99, brand: 'Hasbro', - currency: 'USD', + currency: 'USD' } ], app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -757,7 +758,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -769,7 +770,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -781,8 +782,9 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', - timezone: 'America/Los_Angeles', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + timezone: 'America/Los_Angeles' } } @@ -799,30 +801,30 @@ describe('Moloco MCM', () => { os: androidEvent.context.os.name.toUpperCase(), os_version: androidEvent.context.os.version, ua: androidEvent.context.userAgent, - unique_device_id: androidEvent.context.device.id, + unique_device_id: androidEvent.context.device.id }, items: [ { id: androidEvent.context.product[0].id, price: { amount: androidEvent.context.product[0].price, - currency: androidEvent.context.product[0].currency, + currency: androidEvent.context.product[0].currency } }, { id: androidEvent.context.product[1].id, price: { amount: androidEvent.context.product[1].price, - currency: androidEvent.context.product[0].currency, + currency: androidEvent.context.product[0].currency } } ], - session_id: androidEvent.anonymousId, + session_id: androidEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: androidEvent as SegmentEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -838,7 +840,7 @@ describe('Moloco MCM', () => { } ] } - }, + } }) expect(responses.length).toBe(1) @@ -846,7 +848,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate items mapping with currency / only default currency is given and it is used for each item.' , async () => { + it('should validate items mapping with currency / only default currency is given and it is used for each item.', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -882,7 +884,7 @@ describe('Moloco MCM', () => { app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -891,7 +893,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -903,7 +905,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -915,8 +917,9 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', - timezone: 'America/Los_Angeles', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + timezone: 'America/Los_Angeles' } } @@ -933,30 +936,30 @@ describe('Moloco MCM', () => { os: androidEvent.context.os.name.toUpperCase(), os_version: androidEvent.context.os.version, ua: androidEvent.context.userAgent, - unique_device_id: androidEvent.context.device.id, + unique_device_id: androidEvent.context.device.id }, items: [ { id: androidEvent.context.product[0].id, price: { amount: androidEvent.context.product[0].price, - currency: androidEvent.context.defaultCurrency, + currency: androidEvent.context.defaultCurrency } }, { id: androidEvent.context.product[1].id, price: { amount: androidEvent.context.product[1].price, - currency: androidEvent.context.defaultCurrency, + currency: androidEvent.context.defaultCurrency } } ], - session_id: androidEvent.anonymousId, + session_id: androidEvent.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: androidEvent as SegmentEvent, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -972,7 +975,7 @@ describe('Moloco MCM', () => { } ] } - }, + } }) expect(responses.length).toBe(1) @@ -980,7 +983,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate the page_id conversion when both "page_id" and "page_identifier_tokens" are given ("page_id" should be used).' , async () => { + it('should validate the page_id conversion when both "page_id" and "page_identifier_tokens" are given ("page_id" should be used).', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -1002,7 +1005,7 @@ describe('Moloco MCM', () => { app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -1011,7 +1014,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -1023,7 +1026,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -1035,7 +1038,8 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', timezone: 'America/Los_Angeles', event: 'Product List Viewed', vertical: 'fruit' @@ -1055,15 +1059,15 @@ describe('Moloco MCM', () => { os: event.context.os.name.toUpperCase(), os_version: event.context.os.version, ua: event.context.userAgent, - unique_device_id: event.context.device.id, + unique_device_id: event.context.device.id }, page_id: event.pageId, // -- still uses the pageId - session_id: event.anonymousId, + session_id: event.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: event, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -1073,7 +1077,7 @@ describe('Moloco MCM', () => { event: { '@path': '$.context.event' }, vertical: { '@path': '$.context.vertical' } } - }, + } }) expect(responses.length).toBe(1) @@ -1081,7 +1085,7 @@ describe('Moloco MCM', () => { expect(responses[0].options.json).toEqual(expectedPayload) }) - it('should validate the page_id conversion when only "page_identifier_tokens" is given.' , async () => { + it('should validate the page_id conversion when only "page_identifier_tokens" is given.', async () => { nock(/.*/).persist().post(/.*/).reply(200) // A test event case with automatically collected fields @@ -1103,7 +1107,7 @@ describe('Moloco MCM', () => { app: { name: 'AppName', version: '1.0.0', - build: '1', + build: '1' }, device: { type: 'android', @@ -1112,7 +1116,7 @@ describe('Moloco MCM', () => { adTrackingEnabled: true, manufacturer: 'Samsung', model: 'Galaxy S10', - name: 'galaxy', + name: 'galaxy' }, library: { name: 'analytics.ANDROID', @@ -1124,7 +1128,7 @@ describe('Moloco MCM', () => { carrier: 'T-Mobile US', cellular: true, wifi: false, - bluetooth: false, + bluetooth: false }, os: { name: 'Google Android', @@ -1136,7 +1140,8 @@ describe('Moloco MCM', () => { density: 2.0 }, traits: {}, - userAgent: 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', + userAgent: + 'Mozilla/5.0 (Linux; Android 10; SM-G960U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Mobile Safari/537.36', timezone: 'America/Los_Angeles', event: 'Product List Viewed', vertical: 'fruit' @@ -1156,15 +1161,15 @@ describe('Moloco MCM', () => { os: event.context.os.name.toUpperCase(), os_version: event.context.os.version, ua: event.context.userAgent, - unique_device_id: event.context.device.id, + unique_device_id: event.context.device.id }, - page_id: "event:Product List Viewed;vertical:fruit", // stringified from pageIdentifierTokens - session_id: event.anonymousId, + page_id: 'event:Product List Viewed;vertical:fruit', // stringified from pageIdentifierTokens + session_id: event.anonymousId } - + const responses = await testDestination.testAction(TEST_ACTION_SLUG, { event: event, - settings: { ...AUTH, channel_type: 'APP'}, + settings: { ...AUTH, channel_type: 'APP' }, useDefaultMappings: true, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -1174,7 +1179,7 @@ describe('Moloco MCM', () => { event: { '@path': '$.context.event' }, vertical: { '@path': '$.context.vertical' } } - }, + } }) expect(responses.length).toBe(1) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/addToCart/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/addToCart/__tests__/index.test.ts index bb4fc1e34b..584cd1fdd1 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/addToCart/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/addToCart/__tests__/index.test.ts @@ -16,7 +16,7 @@ describe('MolocoMCM.addToCart', () => { price: 100, currency: 'USD', quantity: 1, - sellerId: 'seller123', + sellerId: 'seller123' } } }) @@ -25,7 +25,8 @@ describe('MolocoMCM.addToCart', () => { event, settings: { platformId: 'foo', - apiKey: 'bar', + platformName: 'foo', + apiKey: 'bar', channel_type: 'SITE' }, mapping: { @@ -46,11 +47,11 @@ describe('MolocoMCM.addToCart', () => { }, sellerId: { '@path': '$.properties.item.sellerId' - }, + } } ] }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -67,40 +68,43 @@ describe('MolocoMCM.addToCart', () => { price: 100, currency: 'USD', quantity: 1, - sellerId: 'seller123', + sellerId: 'seller123' } } }) - await expect(testDestination.testAction('addToCart', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE' - }, - mapping: { - // items: [ - // { - // id: { - // '@path': '$.properties.item.id' - // }, - // price: { - // '@path': '$.properties.item.price' - // }, - // currency: { - // '@path': '$.properties.item.currency' - // }, - // quantity: { - // '@path': '$.properties.item.quantity' - // }, - // sellerId: { - // '@path': '$.properties.item.sellerId' - // }, - // } - // ] -- missing required field - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + await expect( + testDestination.testAction('addToCart', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: { + // items: [ + // { + // id: { + // '@path': '$.properties.item.id' + // }, + // price: { + // '@path': '$.properties.item.price' + // }, + // currency: { + // '@path': '$.properties.item.currency' + // }, + // quantity: { + // '@path': '$.properties.item.quantity' + // }, + // sellerId: { + // '@path': '$.properties.item.sellerId' + // }, + // } + // ] -- missing required field + }, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) }) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/addToWishlist/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/addToWishlist/__tests__/index.test.ts index 9d6a142385..762f0a3dde 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/addToWishlist/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/addToWishlist/__tests__/index.test.ts @@ -11,7 +11,6 @@ describe('MolocoMCM.addToWishlist', () => { const event = createTestEvent({ properties: { - id: '123', price: 100, currency: 'USD', @@ -25,7 +24,8 @@ describe('MolocoMCM.addToWishlist', () => { event, settings: { platformId: 'foo', - apiKey: 'bar', + platformName: 'foo', + apiKey: 'bar', channel_type: 'SITE' }, mapping: { @@ -46,11 +46,11 @@ describe('MolocoMCM.addToWishlist', () => { }, sellerId: { '@path': '$.properties.sellerId' - }, + } } ] }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -67,41 +67,43 @@ describe('MolocoMCM.addToWishlist', () => { price: 100, currency: 'USD', quantity: 1, - sellerId: 'seller123', + sellerId: 'seller123' } } }) - await expect(testDestination.testAction('addToWishlist', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE' - }, - mapping: { - - // items: [ - // { - // id: { - // '@path': '$.properties.item.id' - // }, - // price: { - // '@path': '$.properties.item.price' - // }, - // currency: { - // '@path': '$.properties.item.currency' - // }, - // quantity: { - // '@path': '$.properties.item.quantity' - // }, - // sellerId: { - // '@path': '$.properties.item.sellerId' - // }, - // } - // ] -- missing required field - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + await expect( + testDestination.testAction('addToWishlist', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: { + // items: [ + // { + // id: { + // '@path': '$.properties.item.id' + // }, + // price: { + // '@path': '$.properties.item.price' + // }, + // currency: { + // '@path': '$.properties.item.currency' + // }, + // quantity: { + // '@path': '$.properties.item.quantity' + // }, + // sellerId: { + // '@path': '$.properties.item.sellerId' + // }, + // } + // ] -- missing required field + }, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) }) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/common/request-client.ts b/packages/destination-actions/src/destinations/moloco-rmp/common/request-client.ts index 2657dd5218..6bd3348761 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/common/request-client.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/common/request-client.ts @@ -1,39 +1,39 @@ -import { - RequestClient, - ModifiedResponse -} from '@segment/actions-core' +import { RequestClient, ModifiedResponse } from '@segment/actions-core' import type { Settings } from '../generated-types' export class MolocoAPIClient { - url: string - platform: string - apiKey: string + url: string + platformId: string + platformName: string + apiKey: string - request: RequestClient + request: RequestClient - constructor(request: RequestClient, settings: Settings) { - this.platform = settings.platformId - this.apiKey = settings.apiKey - this.request = request + constructor(request: RequestClient, settings: Settings) { + this.platformId = settings.platformId + this.platformName = settings.platformName ?? '' + this.apiKey = settings.apiKey + this.request = request - this.url = this.getEndpoint() - } - - private getEndpoint() { - return `https://${this.platform.replace(/_/g, '-')}-evt.rmp-api.moloco.com/cdp/SEGMENT` - } + this.url = this.getEndpoint() + } - async sendEvent(body: Record): Promise { - const headers = { - 'x-api-key': this.apiKey, - 'x-platform-id': this.platform, - 'Content-Type': 'application/json' - } + private getEndpoint() { + const nameOrId = this.platformName ? this.platformName : this.platformId + return `https://${nameOrId.replace(/_/g, '-')}-evt.rmp-api.moloco.com/cdp/SEGMENT` + } - return await this.request(this.url, { - method: 'POST', - headers, - json: body - }) + async sendEvent(body: Record): Promise { + const headers = { + 'x-api-key': this.apiKey, + 'x-platform-id': this.platformId, + 'Content-Type': 'application/json' } -} \ No newline at end of file + + return await this.request(this.url, { + method: 'POST', + headers, + json: body + }) + } +} diff --git a/packages/destination-actions/src/destinations/moloco-rmp/common/settings.ts b/packages/destination-actions/src/destinations/moloco-rmp/common/settings.ts index bbd1c5946f..2af8d6b92e 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/common/settings.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/common/settings.ts @@ -1,8 +1,9 @@ // Generalized interface for auth.authentication.fields // All destination actions, will use the auth.authentication to define the fields for the authentication scheme, // and the corresponding interface will be automatically generated. -// This interface is the generalized version of that auto-generated interface. +// This interface is the generalized version of that auto-generated interface. export interface Settings { - platformId: string - apiKey: string + platformId: string + platformName: string + apiKey: string } diff --git a/packages/destination-actions/src/destinations/moloco-rmp/generated-types.ts b/packages/destination-actions/src/destinations/moloco-rmp/generated-types.ts index ef736085c0..1d962dd57d 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/generated-types.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/generated-types.ts @@ -5,6 +5,10 @@ export interface Settings { * ID of the platform */ platformId: string + /** + * Name of the platform (default to the `Platform ID`) + */ + platformName?: string /** * The API key for the platform */ diff --git a/packages/destination-actions/src/destinations/moloco-rmp/home/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/home/__tests__/index.test.ts index 8eeeee60cc..7bb923e7c7 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/home/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/home/__tests__/index.test.ts @@ -4,7 +4,7 @@ import Destination from '../../index' const testDestination = createTestIntegration(Destination) -describe('MolocoMCM.home', () => { +describe('MolocoMCM.home', () => { it('should successfully build an event and send', async () => { nock(/.*/).persist().post(/.*/).reply(200) @@ -13,13 +13,14 @@ describe('MolocoMCM.home', () => { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', channel_type: 'SITE' }, mapping: { timestamp: { '@path': '$.timestamp' } }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/index.ts b/packages/destination-actions/src/destinations/moloco-rmp/index.ts index 89f08d5686..1d1d4bf7d8 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/index.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/index.ts @@ -32,6 +32,13 @@ const destination: DestinationDefinition = { type: 'string', required: true }, + platformName: { + label: 'Platform Name', + description: 'Name of the platform (default to the `Platform ID`)', + type: 'string', + required: false, + default: '' + }, apiKey: { label: 'API Key', description: 'The API key for the platform', diff --git a/packages/destination-actions/src/destinations/moloco-rmp/itemPageView/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/itemPageView/__tests__/index.test.ts index 3b592da115..c42f5551af 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/itemPageView/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/itemPageView/__tests__/index.test.ts @@ -16,7 +16,7 @@ describe('MolocoMCM.itemPageView', () => { price: 100, currency: 'USD', quantity: 1, - sellerId: 'seller123', + sellerId: 'seller123' } } }) @@ -25,8 +25,9 @@ describe('MolocoMCM.itemPageView', () => { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', - channel_type: 'SITE', + channel_type: 'SITE' }, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -51,7 +52,7 @@ describe('MolocoMCM.itemPageView', () => { } ] }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -73,36 +74,38 @@ describe('MolocoMCM.itemPageView', () => { } }) - await expect(testDestination.testAction('itemPageView', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE', - }, - mapping: { - // items: [ - // { - // id: { - // '@path': '$.properties.item.id' - // }, - // price: { - // '@path': '$.properties.item.price' - // }, - // currency: { - // '@path': '$.properties.item.currency' - // }, - // quantity: { - // '@path': '$.properties.item.quantity' - // }, - // sellerId: { - // '@path': '$.properties.item.sellerId' - // } - // } - // ] -- missing required field - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + await expect( + testDestination.testAction('itemPageView', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: { + // items: [ + // { + // id: { + // '@path': '$.properties.item.id' + // }, + // price: { + // '@path': '$.properties.item.price' + // }, + // currency: { + // '@path': '$.properties.item.currency' + // }, + // quantity: { + // '@path': '$.properties.item.quantity' + // }, + // sellerId: { + // '@path': '$.properties.item.sellerId' + // } + // } + // ] -- missing required field + }, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) - }) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/land/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/land/__tests__/index.test.ts index ddadbdea97..aef4717bf2 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/land/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/land/__tests__/index.test.ts @@ -41,15 +41,16 @@ describe('MolocoMCM.land', () => { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', channel_type: 'SITE' }, mapping: { - timestamp: { '@path': '$.timestamp' }, + timestamp: { '@path': '$.timestamp' } // referrer_page_id is default to context.page.referrer }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -87,17 +88,18 @@ describe('MolocoMCM.land', () => { } }) - await expect(testDestination.testAction('land', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE' - }, - mapping: { - - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + await expect( + testDestination.testAction('land', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: {}, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) -}) \ No newline at end of file +}) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/pageView/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/pageView/__tests__/index.test.ts index 586af9c1f0..d335e6fa7e 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/pageView/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/pageView/__tests__/index.test.ts @@ -40,17 +40,17 @@ describe('MolocoMCM.pageView', () => { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', channel_type: 'SITE' }, mapping: { - // page_id is default to context.page.path }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) expect(responses[0].status).toBe(200) }) -}) \ No newline at end of file +}) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/purchase/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/purchase/__tests__/index.test.ts index e83e861091..5c6eb7cb14 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/purchase/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/purchase/__tests__/index.test.ts @@ -26,8 +26,9 @@ describe('MolocoMCM.purchase', () => { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', - channel_type: 'SITE', + channel_type: 'SITE' }, mapping: { timestamp: { '@path': '$.timestamp' }, @@ -59,7 +60,7 @@ describe('MolocoMCM.purchase', () => { } } }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -82,26 +83,28 @@ describe('MolocoMCM.purchase', () => { } }) - await expect(testDestination.testAction('purchase', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE' - }, - mapping: { - // items: -- missing mapping for a required field - revenue: { - price: { - '@path': '$.properties.revenue' - }, - currency: { - '@path': '$.properties.currency' + await expect( + testDestination.testAction('purchase', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: { + // items: -- missing mapping for a required field + revenue: { + price: { + '@path': '$.properties.revenue' + }, + currency: { + '@path': '$.properties.currency' + } } - } - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + }, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) - }) diff --git a/packages/destination-actions/src/destinations/moloco-rmp/search/__tests__/index.test.ts b/packages/destination-actions/src/destinations/moloco-rmp/search/__tests__/index.test.ts index 964254106e..db8e91d062 100644 --- a/packages/destination-actions/src/destinations/moloco-rmp/search/__tests__/index.test.ts +++ b/packages/destination-actions/src/destinations/moloco-rmp/search/__tests__/index.test.ts @@ -1,6 +1,6 @@ import nock from 'nock' import { AggregateAjvError } from '@segment/ajv-human-errors' -import { createTestEvent, createTestIntegration, } from '@segment/actions-core' +import { createTestEvent, createTestIntegration } from '@segment/actions-core' import Destination from '../../index' const testDestination = createTestIntegration(Destination) @@ -13,24 +13,25 @@ describe('MolocoMCM.search', () => { properties: { context: { page: { - query: "Test Query" + query: 'Test Query' } } } }) - + const responses = await testDestination.testAction('search', { event, settings: { platformId: 'foo', + platformName: 'foo', apiKey: 'bar', channel_type: 'SITE' }, mapping: { timestamp: { '@path': '$.timestamp' }, - search_query: { '@path': '$.properties.context.page.query'} + search_query: { '@path': '$.properties.context.page.query' } }, - useDefaultMappings: true, + useDefaultMappings: true }) expect(responses.length).toBe(1) @@ -44,25 +45,28 @@ describe('MolocoMCM.search', () => { properties: { context: { page: { - query: "Test Query" + query: 'Test Query' } } } }) - await expect(testDestination.testAction('search', { - event, - settings: { - platformId: 'foo', - apiKey: 'bar', - channel_type: 'SITE' - }, - mapping: { - // searchQuery: { - // '@path': '$.properties.context.page.query' - // } -- missing required field - }, - useDefaultMappings: true, - })).rejects.toThrowError(AggregateAjvError) + await expect( + testDestination.testAction('search', { + event, + settings: { + platformId: 'foo', + platformName: 'foo', + apiKey: 'bar', + channel_type: 'SITE' + }, + mapping: { + // searchQuery: { + // '@path': '$.properties.context.page.query' + // } -- missing required field + }, + useDefaultMappings: true + }) + ).rejects.toThrowError(AggregateAjvError) }) }) diff --git a/packages/destination-actions/src/destinations/salesforce/account/index.ts b/packages/destination-actions/src/destinations/salesforce/account/index.ts index bbb84e11b9..b15579ffb0 100644 --- a/packages/destination-actions/src/destinations/salesforce/account/index.ts +++ b/packages/destination-actions/src/destinations/salesforce/account/index.ts @@ -10,7 +10,8 @@ import { validateLookup, enable_batching, recordMatcherOperator, - batch_size + batch_size, + hideIfDeleteOperation } from '../sf-properties' import type { Payload } from './generated-types' @@ -34,7 +35,8 @@ const action: ActionDefinition = { type: 'string', default: { '@path': '$.traits.name' - } + }, + depends_on: hideIfDeleteOperation }, account_number: { label: 'Account Number', @@ -43,7 +45,8 @@ const action: ActionDefinition = { type: 'string', default: { '@path': '$.groupId' - } + }, + depends_on: hideIfDeleteOperation }, number_of_employees: { label: 'Number of employees', @@ -55,7 +58,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.employees' }, else: { '@path': '$.properties.employees' } } - } + }, + depends_on: hideIfDeleteOperation }, billing_city: { label: 'Billing City', @@ -67,7 +71,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.city' }, else: { '@path': '$.properties.address.city' } } - } + }, + depends_on: hideIfDeleteOperation }, billing_postal_code: { label: 'Billing Postal Code', @@ -79,7 +84,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.postal_code' }, else: { '@path': '$.properties.address.postal_code' } } - } + }, + depends_on: hideIfDeleteOperation }, billing_country: { label: 'Billing Country', @@ -91,7 +97,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.country' }, else: { '@path': '$.properties.address.country' } } - } + }, + depends_on: hideIfDeleteOperation }, billing_street: { label: 'Billing Street', @@ -103,7 +110,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.street' }, else: { '@path': '$.properties.address.street' } } - } + }, + depends_on: hideIfDeleteOperation }, billing_state: { label: 'Billing State', @@ -115,32 +123,38 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.state' }, else: { '@path': '$.properties.address.state' } } - } + }, + depends_on: hideIfDeleteOperation }, shipping_city: { label: 'Shipping City', description: 'City for the shipping address of the account.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, shipping_postal_code: { label: 'Shipping Postal Code', description: 'Postal code for the shipping address of the account.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, shipping_country: { label: 'Shipping Country', description: 'Country for the shipping address of the account.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, shipping_street: { label: 'Shipping Street', description: 'Street address for the shipping address of the account.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, shipping_state: { label: 'Shipping State', description: 'State for the shipping address of the account.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, phone: { label: 'Phone', @@ -152,7 +166,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.phone' }, else: { '@path': '$.properties.phone' } } - } + }, + depends_on: hideIfDeleteOperation }, description: { label: 'Description', @@ -164,7 +179,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.description' }, else: { '@path': '$.properties.description' } } - } + }, + depends_on: hideIfDeleteOperation }, website: { label: 'Website', @@ -176,7 +192,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.website' }, else: { '@path': '$.properties.website' } } - } + }, + depends_on: hideIfDeleteOperation }, customFields: customFields }, diff --git a/packages/destination-actions/src/destinations/salesforce/cases/index.ts b/packages/destination-actions/src/destinations/salesforce/cases/index.ts index 599688a95d..f3ab985619 100644 --- a/packages/destination-actions/src/destinations/salesforce/cases/index.ts +++ b/packages/destination-actions/src/destinations/salesforce/cases/index.ts @@ -10,7 +10,8 @@ import { validateLookup, enable_batching, recordMatcherOperator, - batch_size + batch_size, + hideIfDeleteOperation } from '../sf-properties' import Salesforce, { generateSalesforceRequest } from '../sf-operations' @@ -30,7 +31,8 @@ const action: ActionDefinition = { description: { label: 'Description', description: 'A text description of the case.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, customFields: customFields }, diff --git a/packages/destination-actions/src/destinations/salesforce/contact/index.ts b/packages/destination-actions/src/destinations/salesforce/contact/index.ts index 95df669ca0..f3c1863c78 100644 --- a/packages/destination-actions/src/destinations/salesforce/contact/index.ts +++ b/packages/destination-actions/src/destinations/salesforce/contact/index.ts @@ -10,7 +10,8 @@ import { validateLookup, enable_batching, recordMatcherOperator, - batch_size + batch_size, + hideIfDeleteOperation } from '../sf-properties' import Salesforce, { generateSalesforceRequest } from '../sf-operations' @@ -37,7 +38,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.last_name' }, else: { '@path': '$.properties.last_name' } } - } + }, + depends_on: hideIfDeleteOperation }, first_name: { label: 'First Name', @@ -49,13 +51,15 @@ const action: ActionDefinition = { then: { '@path': '$.traits.first_name' }, else: { '@path': '$.properties.first_name' } } - } + }, + depends_on: hideIfDeleteOperation }, account_id: { label: 'Account ID', description: 'The ID of the account that this contact is associated with. This is the Salesforce-generated ID assigned to the account during creation (i.e. 0018c00002CDThnAAH).', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, email: { label: 'Email', @@ -67,7 +71,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.email' }, else: { '@path': '$.properties.email' } } - } + }, + depends_on: hideIfDeleteOperation }, mailing_city: { label: 'Mailing City', @@ -79,7 +84,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.city' }, else: { '@path': '$.properties.address.city' } } - } + }, + depends_on: hideIfDeleteOperation }, mailing_postal_code: { label: 'Mailing Postal Code', @@ -91,7 +97,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.postal_code' }, else: { '@path': '$.properties.address.postal_code' } } - } + }, + depends_on: hideIfDeleteOperation }, mailing_country: { label: 'Mailing Country', @@ -103,7 +110,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.country' }, else: { '@path': '$.properties.address.country' } } - } + }, + depends_on: hideIfDeleteOperation }, mailing_street: { label: 'Mailing Street', @@ -115,7 +123,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.street' }, else: { '@path': '$.properties.address.street' } } - } + }, + depends_on: hideIfDeleteOperation }, mailing_state: { label: 'Mailing State', @@ -127,7 +136,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.state' }, else: { '@path': '$.properties.address.state' } } - } + }, + depends_on: hideIfDeleteOperation }, customFields: customFields }, diff --git a/packages/destination-actions/src/destinations/salesforce/lead/index.ts b/packages/destination-actions/src/destinations/salesforce/lead/index.ts index be5aff7008..d7dede2ad6 100644 --- a/packages/destination-actions/src/destinations/salesforce/lead/index.ts +++ b/packages/destination-actions/src/destinations/salesforce/lead/index.ts @@ -10,7 +10,8 @@ import { validateLookup, enable_batching, recordMatcherOperator, - batch_size + batch_size, + hideIfDeleteOperation } from '../sf-properties' import Salesforce, { generateSalesforceRequest } from '../sf-operations' @@ -38,7 +39,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.company' }, else: { '@path': '$.properties.company' } } - } + }, + depends_on: hideIfDeleteOperation }, last_name: { label: 'Last Name', @@ -50,7 +52,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.last_name' }, else: { '@path': '$.properties.last_name' } } - } + }, + depends_on: hideIfDeleteOperation }, first_name: { label: 'First Name', @@ -62,7 +65,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.first_name' }, else: { '@path': '$.properties.first_name' } } - } + }, + depends_on: hideIfDeleteOperation }, email: { label: 'Email', @@ -74,7 +78,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.email' }, else: { '@path': '$.properties.email' } } - } + }, + depends_on: hideIfDeleteOperation }, city: { label: 'City', @@ -86,7 +91,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.city' }, else: { '@path': '$.properties.address.city' } } - } + }, + depends_on: hideIfDeleteOperation }, postal_code: { label: 'Postal Code', @@ -98,7 +104,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.postal_code' }, else: { '@path': '$.properties.address.postal_code' } } - } + }, + depends_on: hideIfDeleteOperation }, country: { label: 'Country', @@ -110,7 +117,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.country' }, else: { '@path': '$.properties.address.country' } } - } + }, + depends_on: hideIfDeleteOperation }, street: { label: 'Street', @@ -122,7 +130,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.street' }, else: { '@path': '$.properties.address.street' } } - } + }, + depends_on: hideIfDeleteOperation }, state: { label: 'State', @@ -134,7 +143,8 @@ const action: ActionDefinition = { then: { '@path': '$.traits.address.state' }, else: { '@path': '$.properties.address.state' } } - } + }, + depends_on: hideIfDeleteOperation }, customFields: customFields }, diff --git a/packages/destination-actions/src/destinations/salesforce/opportunity/index.ts b/packages/destination-actions/src/destinations/salesforce/opportunity/index.ts index 9ec852e839..f59855cd1a 100644 --- a/packages/destination-actions/src/destinations/salesforce/opportunity/index.ts +++ b/packages/destination-actions/src/destinations/salesforce/opportunity/index.ts @@ -10,7 +10,8 @@ import { validateLookup, enable_batching, recordMatcherOperator, - batch_size + batch_size, + hideIfDeleteOperation } from '../sf-properties' import type { Payload } from './generated-types' @@ -31,27 +32,32 @@ const action: ActionDefinition = { label: 'Close Date', description: 'Date when the opportunity is expected to close. Use yyyy-MM-dd format. **This is required to create an opportunity.**', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, name: { label: 'Name', description: 'A name for the opportunity. **This is required to create an opportunity.**', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, stage_name: { label: 'Stage Name', description: 'Current stage of the opportunity. **This is required to create an opportunity.**', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, amount: { label: 'Amount', description: 'Estimated total sale amount.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, description: { label: 'Description', description: 'A text description of the opportunity.', - type: 'string' + type: 'string', + depends_on: hideIfDeleteOperation }, customFields: customFields }, diff --git a/packages/destination-actions/src/destinations/salesforce/sf-properties.ts b/packages/destination-actions/src/destinations/salesforce/sf-properties.ts index 442615b3cb..76094be1a0 100644 --- a/packages/destination-actions/src/destinations/salesforce/sf-properties.ts +++ b/packages/destination-actions/src/destinations/salesforce/sf-properties.ts @@ -1,4 +1,15 @@ import { IntegrationError, InputField } from '@segment/actions-core' +import { DependsOnConditions } from '@segment/actions-core/destination-kit/types' + +export const hideIfDeleteOperation: DependsOnConditions = { + conditions: [ + { + fieldKey: 'operation', + operator: 'is_not', + value: 'delete' + } + ] +} export const operation: InputField = { label: 'Operation', @@ -19,7 +30,8 @@ export const enable_batching: InputField = { description: 'If true, events are sent to [Salesforce’s Bulk API 2.0](https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/asynch_api_intro.htm) rather than their streaming REST API. Once enabled, Segment will collect events into batches of 5000 before sending to Salesforce. *Enabling Bulk API is not compatible with the `create` operation*.', type: 'boolean', - default: false + default: false, + depends_on: hideIfDeleteOperation } export const batch_size: InputField = { @@ -28,7 +40,8 @@ export const batch_size: InputField = { type: 'number', required: false, unsafe_hidden: true, - default: 5000 + default: 5000, + depends_on: hideIfDeleteOperation } export const bulkUpsertExternalId: InputField = { @@ -145,7 +158,8 @@ export const customFields: InputField = { `, type: 'object', - defaultObjectUI: 'keyvalue' + defaultObjectUI: 'keyvalue', + depends_on: hideIfDeleteOperation } interface Payload { diff --git a/packages/destination-actions/src/destinations/taboola-actions/syncAudience/index.ts b/packages/destination-actions/src/destinations/taboola-actions/syncAudience/index.ts index 243a80d4ef..4568d36f67 100644 --- a/packages/destination-actions/src/destinations/taboola-actions/syncAudience/index.ts +++ b/packages/destination-actions/src/destinations/taboola-actions/syncAudience/index.ts @@ -7,6 +7,7 @@ import { TaboolaClient } from './client' const action: ActionDefinition = { title: 'Sync Audience', description: 'Sync a Segment Engage Audience to Taboola.', + defaultSubscription: 'type = "track"', fields: { external_audience_id: { label: 'External Audience ID', diff --git a/packages/destination-actions/src/destinations/webhook-audiences/index.ts b/packages/destination-actions/src/destinations/webhook-audiences/index.ts index db73442ba6..17c5d16be0 100644 --- a/packages/destination-actions/src/destinations/webhook-audiences/index.ts +++ b/packages/destination-actions/src/destinations/webhook-audiences/index.ts @@ -1,9 +1,10 @@ -import type { AudienceDestinationDefinition } from '@segment/actions-core' +import type { ActionDefinition, AudienceDestinationDefinition } from '@segment/actions-core' import type { Settings, AudienceSettings } from './generated-types' import send from '../webhook/send' import { IntegrationError } from '@segment/actions-core' import { createHmac } from 'crypto' +import { Payload } from './send.types' const externalIdKey = 'externalId' const audienceNameKey = 'audienceName' @@ -157,7 +158,7 @@ const destination: AudienceDestinationDefinition = { settings }) } - } + } as ActionDefinition } } diff --git a/packages/destinations-manifest/package.json b/packages/destinations-manifest/package.json index dfadaa7d0e..de94c661c4 100644 --- a/packages/destinations-manifest/package.json +++ b/packages/destinations-manifest/package.json @@ -1,6 +1,6 @@ { "name": "@segment/destinations-manifest", - "version": "1.71.0", + "version": "1.72.0", "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org" @@ -12,44 +12,44 @@ "main": "./dist/index.js", "typings": "./dist/index.d.ts", "dependencies": { - "@segment/analytics-browser-actions-1flow": "^1.33.0", - "@segment/analytics-browser-actions-adobe-target": "^1.51.0", - "@segment/analytics-browser-actions-algolia-plugins": "^1.28.0", - "@segment/analytics-browser-actions-amplitude-plugins": "^1.51.0", - "@segment/analytics-browser-actions-braze": "^1.54.0", - "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.54.0", - "@segment/analytics-browser-actions-bucket": "^1.31.0", - "@segment/analytics-browser-actions-cdpresolution": "^1.38.0", - "@segment/analytics-browser-actions-commandbar": "^1.51.0", - "@segment/analytics-browser-actions-devrev": "^1.38.0", - "@segment/analytics-browser-actions-friendbuy": "^1.52.0", - "@segment/analytics-browser-actions-fullstory": "^1.53.0", - "@segment/analytics-browser-actions-google-analytics-4": "^1.58.0", - "@segment/analytics-browser-actions-google-campaign-manager": "^1.42.0", - "@segment/analytics-browser-actions-heap": "^1.51.0", - "@segment/analytics-browser-actions-hubspot": "^1.51.0", - "@segment/analytics-browser-actions-intercom": "^1.54.0", - "@segment/analytics-browser-actions-iterate": "^1.51.0", - "@segment/analytics-browser-actions-jimo": "^1.39.0", - "@segment/analytics-browser-actions-koala": "^1.52.0", - "@segment/analytics-browser-actions-logrocket": "^1.51.0", - "@segment/analytics-browser-actions-pendo-web-actions": "^1.40.0", - "@segment/analytics-browser-actions-playerzero": "^1.51.0", - "@segment/analytics-browser-actions-replaybird": "^1.32.0", - "@segment/analytics-browser-actions-ripe": "^1.51.0", + "@segment/analytics-browser-actions-1flow": "^1.34.0", + "@segment/analytics-browser-actions-adobe-target": "^1.52.0", + "@segment/analytics-browser-actions-algolia-plugins": "^1.29.0", + "@segment/analytics-browser-actions-amplitude-plugins": "^1.52.0", + "@segment/analytics-browser-actions-braze": "^1.55.0", + "@segment/analytics-browser-actions-braze-cloud-plugins": "^1.55.0", + "@segment/analytics-browser-actions-bucket": "^1.32.0", + "@segment/analytics-browser-actions-cdpresolution": "^1.39.0", + "@segment/analytics-browser-actions-commandbar": "^1.52.0", + "@segment/analytics-browser-actions-devrev": "^1.39.0", + "@segment/analytics-browser-actions-friendbuy": "^1.53.0", + "@segment/analytics-browser-actions-fullstory": "^1.54.0", + "@segment/analytics-browser-actions-google-analytics-4": "^1.59.0", + "@segment/analytics-browser-actions-google-campaign-manager": "^1.43.0", + "@segment/analytics-browser-actions-heap": "^1.52.0", + "@segment/analytics-browser-actions-hubspot": "^1.52.0", + "@segment/analytics-browser-actions-intercom": "^1.55.0", + "@segment/analytics-browser-actions-iterate": "^1.52.0", + "@segment/analytics-browser-actions-jimo": "^1.40.0", + "@segment/analytics-browser-actions-koala": "^1.53.0", + "@segment/analytics-browser-actions-logrocket": "^1.52.0", + "@segment/analytics-browser-actions-pendo-web-actions": "^1.41.0", + "@segment/analytics-browser-actions-playerzero": "^1.52.0", + "@segment/analytics-browser-actions-replaybird": "^1.33.0", + "@segment/analytics-browser-actions-ripe": "^1.52.0", "@segment/analytics-browser-actions-sabil": "^1.6.0", - "@segment/analytics-browser-actions-screeb": "^1.52.0", - "@segment/analytics-browser-actions-snap-plugins": "^1.32.0", - "@segment/analytics-browser-actions-sprig": "^1.51.0", - "@segment/analytics-browser-actions-stackadapt": "^1.53.0", - "@segment/analytics-browser-actions-survicate": "^1.27.0", - "@segment/analytics-browser-actions-tiktok-pixel": "^1.51.0", - "@segment/analytics-browser-actions-upollo": "^1.51.0", - "@segment/analytics-browser-actions-userpilot": "^1.51.0", - "@segment/analytics-browser-actions-utils": "^1.51.0", - "@segment/analytics-browser-actions-vwo": "^1.52.0", - "@segment/analytics-browser-actions-wiseops": "^1.52.0", - "@segment/analytics-browser-hubble-web": "^1.37.0", - "@segment/browser-destination-runtime": "^1.50.0" + "@segment/analytics-browser-actions-screeb": "^1.53.0", + "@segment/analytics-browser-actions-snap-plugins": "^1.33.0", + "@segment/analytics-browser-actions-sprig": "^1.52.0", + "@segment/analytics-browser-actions-stackadapt": "^1.54.0", + "@segment/analytics-browser-actions-survicate": "^1.28.0", + "@segment/analytics-browser-actions-tiktok-pixel": "^1.52.0", + "@segment/analytics-browser-actions-upollo": "^1.52.0", + "@segment/analytics-browser-actions-userpilot": "^1.52.0", + "@segment/analytics-browser-actions-utils": "^1.52.0", + "@segment/analytics-browser-actions-vwo": "^1.53.0", + "@segment/analytics-browser-actions-wiseops": "^1.53.0", + "@segment/analytics-browser-hubble-web": "^1.38.0", + "@segment/browser-destination-runtime": "^1.51.0" } } diff --git a/scripts/generate-release-tags.sh b/scripts/generate-release-tags.sh index d1d5a2b941..5da5e11e9c 100755 --- a/scripts/generate-release-tags.sh +++ b/scripts/generate-release-tags.sh @@ -38,7 +38,8 @@ else tag=$(printf release-$(date '+%Y-%m-%d%%s') $suffix) echo "Tagging $sha with $tag" - git tag -a $tag -m "Release $tag" + git tag -a $tag -m "Release $tag" --force + git push origin $tag fi # this script assumes the last commit was publish commit and gets all package.json files changed in the last commit @@ -47,5 +48,6 @@ files=$(git show --pretty="" --name-only HEAD | grep -Ei '^packages/.*package\.j for file in $files; do tag=$(cat $file | jq -r '.name + "@" + .version') echo "Tagging $sha with $tag" - git tag -a $tag -m "Release $tag" + git tag -a $tag -m "Release $tag" --force + git push origin $tag done